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.
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 am controlling a test system using PyVisa/GPIB. The system is comprised of two separate testers (A and B) and a laptop. The the laptop passively listens for a GPIB message from tester A, when received the laptop triggers tester B.
I am using the following code to passively listen for events from tester A:
rm = visa.ResourceManager()
con = "GPIB0::3"
tester_A = rm.get_instrument(con, timeout=5000)
while True:
event = None
try:
event = tester_A.read_raw()
except VisaIOError:
logger.warning("Timeout expired.")
if event != None:
# Do something
Is there a better way to listen and respond to events from tester A? Is there a better way to control this system via GPIB?
The approach you describe will work, but as you are experiencing, is not ideal if you are not quite sure when the instrument is going to respond. The solution lies in using the GPIB's service request (SRQ) functionality.
In brief, the GPIB connection also provides various status registers that allow you to quickly check, for example, whether the instrument is on, whether an error has occurred, etc. (pretty picture). Some of the bits in this register can be set so that they turn on or off after particular events, for example when an operation is complete. This means you tell the instrument to execute a series of commands that you suspect will take a while, and to then flip a bit in the status register to indicate it is done.
From within your software you can do a number of things to make use of this:
Keep looping through a while loop until the status bit indicates that the operation is complete - this is very crude and I wouldn't recommend it.
VISA has a viWaitOnEvent function that allows you to wait until the status bit indicatesthat the operation is complete - a good solution if you need all execution to stop until the instrument has taken a measurement.
VISA also allows you to create an event that occurs when the status bit has flipped - This is a particularly nice solution as it allows you to write an event handler to handle the event.
I'm sending keyboard signals to the OS (Windows) via python. The problem is the specific application (Project 64, Nintendo 64 emulator) is not receiving the signals, I'm not sure why. The keys are registered in Word and my browser for example.
shell = win32com.client.Dispatch("WScript.Shell")
ser=serial.Serial('com10',115200)
while 1:
datain=ser.read(1)
if datain=='':
continue
datain_int=int(binascii.hexlify(datain), 16)
datain_bin=bin(datain_int)
if datain_int==0:
continue
print(datain_int)
if datain_int==128:
shell.SendKeys("a")
Since other applications are receiving your keystrokes it is entirely possible that the application, being an emulator, is scanning the keyboard directly rather than having keystrokes passed from the operating system.
If this is the case you would probably be better off downloading the source code and patching it to use input from the serial port directly. You an also have a look at the source code to see how it is receiving the keyboard events.
There is some way to get the device path of a mouse and keyboard using Xlib based in a looping with XNextEvent? I need to know what /dev/input/event* generates a event specific like mouse press and keyboard key F1 press.
I'm using evdev for input devices in Xorg, I searched documentation and cannot find a way.
I accept too suggestion of some app that I can use to identify input device based in events like mouse press and keyboard press.
Thanks.
Edit: If there is a way to make this using another lib, preferable one with bindings for python, please let me know.
I realize that Xlib do not have a method to get the file descriptor of the input devices, so I figured out another way to resolve this case, is not ready yet, but apparently is the best way to follow, just posting here for someone with the same problem.
I'm using the module python-evdev (installed with pip in ubuntu), with this module I can monitor the devices is /dev/input/event*, so I just need to start a thread for each device that I previous identified which is a mouse or keyboard (using the module evdev and checking if device have "capabilities(verbose=True)" with event codes like ecodes.KEY_F1 and ecodes.BTN_MOUSE), and when a event occur, write to a shared variable, that I should monitor.
For the graphic interface running in Xorg, without Windows Managers, I using python-glade2, works like a charm, I run a Xorg with python-glade2 app using xinit.
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)