Duplicate device input events on unix (/dev/input/event) - python

I'm using linux/ubuntu, and I would like to play a little bit with my touchpad. I'm trying to use python-evdev to read events from /dev/input/events, for now just printing them:
import evdev
dev = evdev.InputDevice('/dev/input/event6')
import time
while True:
try:
for event in dev.read():
print event
except:
print " ~ "
time.sleep(.5)
If I do run that script in with root privilege in a virtual console (outside X, pressing ctrl+alt+F1), the script does print events when I touch the touchpad. Yet, if X is on screen and I run this in a gnome-terminal console, nothing is printed; I somehow guess this is normal, the inputs are intercepted by X. Yet I would like to get them anyway. Is there a way to duplicate whatever comes from /dev/input/event6 so thqt both X and my script can read all events ?

sorry, a bit late on the answer here.
Up until version 1.8, the xorg synaptics driver used the EVIOCGRAB ioctl to prevent events to be delivered to other clients. That's disabled now by default, you can still use the GrabEventDevice option to disable it on your machine for older versions (see man synaptics).
In short, nothing wrong with your script, it's the synaptics driver that's the problem here. You'll find that your script will work on other devices just fine (though the xorg wacom driver did also grab the device until recently).
upstream commit in synaptics:
http://cgit.freedesktop.org/xorg/driver/xf86-input-synaptics/commit/?id=f1948e08ee9894864254a18098e4f4fceb6e322f

So, your idea is, X got the data from your touchpad, so that your python code is blocked from receiving touchpad signal, right? Or, may I repeat your words as: at least for some specific kind of device, an application can't get /dev/input/event*, when another is reading from that device?
Theoritically, since linux make all devices as a file, you are accessing a file as read-only, while X is also read-only accessing the file.
I just did another experiment as: I have a infrared reciver on my archlinux, and I connected to the system in two ssh consoles. I use two ways to access IR, that is, two applications to read the file of /dev/input/event0 (event0 is the SF on my arch):
1, a piece of python code, with evdev;
2, a shell command as: sudo cat /dev/input/event0 | hexdump
You can look on the 2nd as working as your X. If you were reasoning correctly, they both should not receive data from the IR (event0) on the same time, when I sending signal from a IR remote controller, right? But, I really got date on the two ssh consoles(I wish I could post image, but I am new with too low reputation to do so).
So, I think it should not be the reason. I guess it might be because of your touchpad itself. You know, some devices can only work on a single application. e.g., keyboard can only enter characters on the active application, and some input method just make itself as active over other applications, and redirect after it processed. Also, say, if you had a VM running on your system, and you use only one mouse, what would happen if you are moving pointer on the host desktop? Will the pointer in VM move? Or vice versa?
So I need more info about your touchpad. If your TP works only with a single active applicatio, I am afraid you need somethink like a hook to get touchpad signal ahead of X, and redirec it to X and your python code, which might be beyond evdev.

You could create a kernel input handler based on evdev so that the device input is distributed both to the normal /dev/input/eventN and, let's say, /dev/input/copied_eventN
X would read from /dev/input/eventN but you would still be able to read from /dev/input/copied_eventN
Actually you could very easily create a kernel module by copy-pasting the code in drivers/input/evdev.c

Related

Send keystrokes to non-active GUI application without occupying the keyboard

As the title explain, i'm trying to use the terminal to send commands as keystrokes to a GUI application that's minimized.
There is a lot of similar questions here on Stack with some great answers, but i'm having, mainly, three problems with the solutions i saw: Most of the solutions need the automated application to be the active one. Or, i can't normally use my keyboard while the script/process is running. Or worse, the solution works only on Windows OS.
I need what this person asked 2 months ago: Send keystrokes to a specific window (in background), but do something else in the meantime
But i want it on Linux.
I'm using Kubuntu 18.10, if that helps.
xdotool was close, but i couldn't quite get it to send the commands to a specific window or PID. It also uses "my keyboard", so i can't, for example, write an essay/code/browse online while xdotool is running. Pexpect also have this last problem.
AutoHotKey looks like it would work, but it's only for Windows and i'm trying to not use Wine. Same with pywin32.
keyboard (https://github.com/boppreh/keyboard) seems nice, but it can't send a command to a specific application. Same with PyAutoGUI.
I selected the Python tag because most of the solutions i saw use Python, but i'm open to any language.
Use a nested X server to input keystrokes without changing focus or keyboard grab.
Proof of concept:
Xephyr -resizeable :13
export DISPLAY=:13
xterm
xdotool type rhabarber
The Xephyr nested X server is started and will listen on local X socket 13 (whereas :0 typically identifies the currently running X server, but when multiple sessions are ran concurrently, it could be higher).
Then we set DISPLAY environment variable to :13, so any X application we start will connect to Xephyr; xterm is our target application here. Using xdotool or any other tool we can send keystrokes.
As the target X server is identified through $DISPLAY, applications can be started or input events triggered from elsewhere as well. If needed, you might also run a lightweight window manager within Xephyr, e.g. to 'maximize' the application so that it fills the whole Xephyr window.

Python - control application started by the different user in Windows

I am making application that controls a browser with SendKeys. But as SendKeys get the full control over the keyboard, I want to run this app under the different user. This way I will be working, the application will do what it have to do, and we will not make problems for each other).
The simplest code is
import time
import SendKeys
time.sleep(10)
SendKeys.SendKeys('hello')
I run it, focus on the field where I want to insert my text "hello", and wait. If I don't change the user, all is done as expected.
But when I run it, change the user and return after 10 seconds, I see that SendKeys sent nothing to the program.
How to send keystrokes to the program under the different user?
(I was trying to do the same with pywinauto, but the result was almost the same - all is good if I don't change the user, and error if I change it. So I thought that it is much simplier to resolve this problem with only SendKeys).
Just to summarize our discussion in comments and in the chat. Your wishes are very wide. I'm just trying to show you some directions to learn.
If you want to use SendKeys/TypeKeys/ClickInput methods (working as a real user), you need to run your automation script in the remote session, not locally. This is explained in details in my other answer: SetCursorPos fail with "the parameter is incorrect" after rdp session terminated.
If you want to run the automation on the same machine silently (in minimized state), there is an example for dealing with hidden windows: Python - Control window with pywinauto while the window is minimized or hidden. Just minimize the window and use silent methods (almost all except ClickInput and TypeKeys).
Feel free to ask more detailed questions about pywinauto and GUI automation.

How I can capture in Python the Ctrl key (only Ctrl, without another at the same time) when pressed?

I need to detect, in a python console (text mode) program, when the Ctrl key is pressed, without another key at the same time. I tried with getch from curses library and stdin, but it waits for any key but not Ctrl or Alt. I found information in stackoverflow but always referred to Windows/event environment, or pressed simultaneously with another key (Ctrl + C for example) but this is not my case. I have found in some forum that's no possible, but I can believe it.
This answer is Linux-centric, seeing your mention of Raspbian console mode implies a Debian GNU/Linux console system.
If you're really talking about the console, this is possible albeit very hacky. Curses has a raw mode to read most keys, but Control is a modifier key, so won't show up that way. The method I can think of is to read the input device, much like X would. Use lsinput to find which device is your keyboard. As input-events demonstrates, you can see events there while they are also processed elsewhere. Among the downsides are that you won't know if the input was actually going to you (unless you track virtual console switching, job status etc) and you need access to the device, as that property implies it might be sensitive data such as a password being entered to login on another virtual console.
It might be simpler to remap what the control key itself sends using loadkeys, thus changing it from a modifier to a detectable key. It will still retain its lower level protocol properties (in USB HID boot protocol keyboard, for instance, it will have a dedicated bit rather than use one of typically only 6 slots for pressed keys).
Either way, this is not easy or portable, and won't work at all over terminal environments such as an ssh session.

Can I keep the terminal as the active window, even if it's in the background? - Python 3.3

G'day,
I've just posted this question here. Following on from that, is there a means to lock keyboard user input to the terminal, when it's running behind another window? My system requires a user to scan their barcode (barcode scanner acts as a keyboard. ie. outputs a string of letters and presses enter) inside the terminal. However, the system also requires that a log CSV file be displayed on the attached monitor. As such, with the terminal in the background, the cursor automatically reverts to the log CSV file when opened, which disables the users' barcode scan from being entered into the terminal.
I'm still relatively new to Python, and haven't completely figured out the functionality of this system. I will eventually set it up such that when the system boots, the log file will automatically open on top, with the terminal (and cursor input) running in the background.
Again, I don't have any code to demonstrate my attempts, but I have done extensive research. The only thing I've found that may offer this functionality is xdotool. I could automatically rearrange the windows such that the terminal was always at the back, and somehow automatically allocate the terminal as the 'active' window?
Any help here would be great!
Thanks!

Media Play/Pause Simulation

My keyboard contains a row of buttons for various non-standard keyboard tasks. These keys contain such functions as modifying the volume, playing or pausing, and skipping tracks. How can I simulate a basic play/pause with Python? I am on Windows, by the way.
I would use pywin32. Bundled with the installation is a large number of API-docs (usually placed at something like C:\Python32\Lib\site-packages.) It essentially wraps a lot of stuff in the Win32-library which is used for many low-levels tasks in Windows.
After installing it you could use the wrapper for keybd_event.
You could also use SendInput instead of keybd_event but it doesn't seem to be wrapped by PyWin32. SendMessage is also an option but more cumbersome.
You'll need to look up the virtual scan code for those special buttons, since I doubt the char-to-code mapping functions will help you here. You can find the reference here.
Then it is a simple matter of calling the function. The snippet below pauses Chuck Berry on my computer.
>>> import win32api
>>> VK_MEDIA_PLAY_PAUSE = 0xB3
>>> hwcode = win32api.MapVirtualKey(VK_MEDIA_PLAY_PAUSE, 0)
>>> hwcode
34
>>> win32api.keybd_event(VK_MEDIA_PLAY_PAUSE, hwcode)
MapVirtualKey gives us the hardware scan code which keybd_event needs (or more likely, the keyboard driver.)
Note that all this is snapped up by the keyboard driver, so you don't really have any control where the keystrokes are sent. With SendMessage you can send them to a specific window. It usually doesn't matter with media keys since those are intercepted by music players and such.
This was not working for me on Windows 10 64, all recent updates installed. I needed this (the 3rd parameter 2) before it'd work.
win32api.keybd_event(0xB3,0,2,0)
didn't bother looking into why it works, but threw it out there since this and other similar posts had me frustrated as for some reason not working on my PC.
This successfully paused/played Amazon Music on my PC.
You can use pyautogui. This library contains a lot of keyboard and mouse simulations.
To install run pip install pyautogui in cmd.
In order to simulate a play/pause keypress, you should use pyautogui.press("playpause").
Check out their docs at https://pyautogui.readthedocs.io/en/latest/keyboard.html to see the list of the supported keys and some other keyboard functions.

Categories

Resources