I'm developing an application in python which sends keyboard events to another external application. I use the pywin32 package to set the external application and send the desired key:
import win32com.client as w32
shell = w32.Dispatch("WScript.Shell")
shell.AppActivate(desired_application)
shell.SendKeys("{ENTER}")
The external application I'm using has a virtual keyboard and a text area which receives the events of the keyboard. I want to send the key event (in this case, an 'ENTER') to the keyboard area (because the keyboard is making a scan through the letters and will select the desired letter with an Enter). However, my application is sending the key events to the text area instead of the keyboard.
I tried to get the handle of the window I want with FindWindow and EnumChildWindow from win32gui... So, is there a way to send the keys to the specific child window of the external application?
I manage to choose the specific handle with EnumChildWindow (to enumerate all the handles of the application) and send the message with PostMessage.
import win32api
win32api.PostMessage(handler, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
Related
This question already has an answer here:
SendMessage doesn't work for some applications
(1 answer)
Closed last month.
I want to send keyboard input to a game running in the background (game: Knight Online) but the win32api.SendMessage, PostMessage methods are not working. how can I do that
I tried the code in this link
code:
from time import sleep
import win32gui
import win32con
def callback(handle, param):
s = win32gui.GetClassName(handle)
try:
print(f'Sending key to {handle}, {s}')
win32gui.SendMessage(handle, 0x0102, 0x5A, 0)
sleep(.5)
except Exception:
print('Exception sending to {handle}, {s}')
window_id = win32gui.FindWindow(None, "Knight OnLine Client")
win32gui.EnumChildWindows(window_id, callback, 0)
output:
Sending key to 23004754, Edit
Sending key to 1639850, Edit
Sending key to 10421696, Edit
the input does not work in the game
Why it doesn't work
There are many stops along the pipeline from a keypress to an application. And applications can choose where along that pipeline to receive keyboard input.
You're sending 0x0102 which is WM_CHAR. That's about as far to the end of the pipeline as you can go. It's likely the game is tapping the pipe earlier.
When you press a physical key, the keyboard driver places an input event in an input queue.
When the OS pulls that event from the input queue, it places a WM_KEYDOWN message in the message queue for the thread that owns the window with the input focus.
When the application's GUI thread pulls the message from queue, it may choose to route it through an API called TranslateMessage, which watches for low level keyboard messages like WM_KEYDOWN and WM_KEYUP.
TranslateMessage synthesizes WM_CHAR (and/or WM_UNICHAR) and sends them to the window (just before allowing the keyboard message to be processed). These messages tell the program that the user has typed a character (for example, a capital E with an acute accent) which can be done only with a series of keyboard messages.
Meanwhile, part of the system is tracking the state of the entire keyboard at different points in time.
One of those is the asynchronous keyboard state, which watches that input queue so that it knows what's happening on the keyboard right now. Games can query this with GetAsyncKeyState (and maybe with the legacy DirectInput API). A fast video game might rely on this (after checking that they are the "active" window).
There's also a synchronous keyboard state, which is tracked per GUI thread as the threads pull keyboard messages from their queues. Imagine if a thread fell behind and a lot of keyboard messages were still queued up. The synchronous keyboard state (from GetKeyState or GetKeyboardState) would indicate the keyboard state at the time the most recently processed window message was posted, which may be different that the asynchronous state which would already reflect all of the messages still in the queue.
The character input messages, like WM_CHAR, are useful for text editors, word processors, etc. But even they must tap the pipeline earlier for keystrokes like Page Up and Page Down.
Many apps work primarily with the WM_KEYDOWN and WM_KEYUP messages.
Fast video games likely use the asynchronous keyboard state or perhaps the synchronous one. And they may purposely not process any keyboard input when they are in the background.
What you can try
The easiest thing to try is to send (or better, post) WM_KEYDOWN and WM_KEYUP messages instead of WM_CHAR. That won't guarantee success.
Windows has the SendInput API for putting events in the input queue (the way the keyboard driver does). I don't know if there's a Python library that covers that. Even if there is, it's not likely to help, since the system won't send your injected keyboard input events to a background window.
I would like to send DirectInput keys to an inactive window without interfering with my actual mouse. I tried using PostMessage, SendInput and SendMessage but pywin32 uses virtual keycodes while ctypes does work with DirectInput. I have no idea how I can make it send in an inactive window.
Try using this, it manages to work for me send the keystrokes to the inactive window,
Use (but add error checking) hwndMain = win32gui.FindWindow("notepad", "prueba.txt: log keys") hwndEdit = win32gui.FindWindowEx
I am writing an automation test for a hotkey application and one of the challenges is to find out if the correct key/s are pressed after remapping a key. For example, if I rebind the Q key to A, the letter A should type in when I press Q in the keyboard.
Now, I want to be able to perform this action through a script without having to manually press the rebinded key. I have tried the libraries pywinauto, keyboard, and pynput to no avail; they just type in the exact character/s and no conversion occurs.
How to reproduce:
rebind Q key to A using any hotkey software (using any remapping/hotkey tool e.g. autohotkey, razer synapse, logitech setpoint, microsoft mouse and keyboard center, etc.)
install python keyboard library https://pypi.org/project/keyboard/
run below in python console
>>> import keyboard
>>> keyboard.press_and_release('Q')
>>> Q
In the above, Q was rebinded to A in the hotkey application but the code still outputted Q.
Is it possible to send actual key press events as though the physical buttons are pressed (so that the hotkey is triggered) and Q will type A instead? And to capture the key press (A) and store it in a string so that I can use this to assert whether the hotkey is activated. The code should work regardless of what hotkey program I use to rebind a key.
I want to send key down events to game applications using pywinauto. I get the application like this:
from pywinauto.application import Application
app = Application()
app.connect(title='Adobe Flash Player 29')
win = app.window_(title_re = "Adobe Flash Player 29")
This allows me to send things like mouse clicks to the application:
win.Click(coords=(300,330))
This works fine, and I can also send "TypeKeys" events to the application:
while True:
win.TypeKeys("w")
However, instead of holding the key down, it repeatedly sends single letters to the game. I need a way to hold the key down instead (and this must be in context of an application, not just a raw keyboard input).
EDIT: I mean I want to send held key presses to applications other than the active window
from pywinauto.keyboard import SendKeys
<...code>
SendKeys('{DOWN}') # Keyboard input
# in case of element
element.type_keys('{DOWN}')
checkout this Link, Hope this will help you.
What I want
Write a script that reads what HID usage ids usb keyboards send without root user right.
The purpose is to map a scancode/HID id and the resulting literal input for writing a keyboard configuration tool; T key press may input a literal Y if the user is using dvorak layout or Z may input a literal ツ.
The code snippet below does a nice job in capturing scancode(usb keyboards send hid usage id, but it still captures scancode), but requires read permission for /dev/input/*, not ideal.
from evdev import *
dev = InputDevice('/dev/input/event5')
print(dev)
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
print(categorize(event))
Is there anyway to do this without special permissions?
Conclusion:
X input extension 2(XI2) provides access to RawEvents; though I could not find what I need in RawKeyPress event: Capture XI2 RawKeyPress event and interpreting it with python
It's half possible to convert X11 keycodes back to scancodes.
Not detailed but my note on them here: How to translate X11 keycode back to scancode or hid usage id reliably
As to capturing keyboard events upstream of /dev/input/event*, it's not possible without some permissions.
XI2 support in python is poor and playing with it seems to require using C library or writing X client library. The latest version of python3-xlib does support it but at least I cannot find documentations and understanding binary data is not easy.
The key event generation chain:
This blog post had some details about keyboard event generation process: https://seasonofcode.com/posts/internal-input-event-handling-in-the-linux-kernel-and-the-android-userspace.html
----os space-------------
A user press a keyboard key
The keyboard sends an hidbp(a packet of a sort) to the usb controller
USB controller receives the packet and make an irq(Interrupt request)
CPU responds to the irq and invokes irq handler which is set by the keyboard driver.
---somewhat uncertain
irq handler stores the packet or event and queues the processing function call for it in the kernel and exits.
The queued function process the event and reports it to various functions in include/linux/input.h and calls input_sync to write the event to a device file such as /dev/input/event1.
---user space----
Be it xwindow server or android InputDeviceReader reads form /dev/input/event*
If what I've read is right and have read it right, anything upstream of the /dev/input/event* happens in the kernel and the task is handled by the device driver.