gvalkov/python-evdev

Event injection does not work

mqnc opened this issue · 3 comments

mqnc commented

I am running in python3.8 on KUbuntu 20.04. I have the same issue when using your nemesis, the python-uinput library.

Here is my code:

from evdev import UInput, ecodes as e
import time

ui = UInput.from_device(
	"/dev/input/by-path/pci-0000:02:00.0-usb-0:1:1.0-event-joystick", name='fake')
ui.capabilities(verbose=True).keys()

ui.write(e.EV_KEY, e.BTN_0, 1)
ui.syn()

while True:
	ui.write(e.EV_ABS, e.ABS_X, 20)
	ui.syn()
	ui.write(e.EV_ABS, e.ABS_X, 40)
	ui.syn()
	time.sleep(0.1)

The device I am copying is a real x-box 360 gamepad. I run the code as root.

I am testing with this page: https://gamepad-tester.com/

The fake gamepad appears and does one single update (which I can see in the timestamp).

If I do this:
cat /dev/input/js0 I can see garbage being printed out whenever I touch my real gamepad. If I do the same for the fake gamepad, it also shows a bit of garbage which looks fairly plausible, given the events I send:

me@pc:~$ cat /dev/input/js1
 K�� K�� K�� K�� K�� K�� K�� K�� K� K��	 K��
 K�� K�$� K��� K� K�K�� K��� K�� K��^C
me@pc:~$ cat /dev/input/js1
\a��\a��\a��\a��\a��\a��\a��\a��\a�\a��	\a��
\a��\a�$�\a���\a�\a�K��\a���\a��\a��^C
me@pc:~$ cat /dev/input/js1
8o��8o��8o��8o��8o��8o��8o��8o��8o�8o��	8o��
8o��8o�$�8o���8o�8o�K��8o���8o��8o��^C
me@pc:~$ cat /dev/input/js1
d|��d|��d|��d|��d|��d|��d|��d|��d|�d|��	d|��
d|��d|�$�d|���d|�d|�K��d|���d|��d|��^C

The curious thing however is, that it does not continue printing. It prints around 2 lines when I run cat but that's it. But the lines are always different for every run (my python script runs continuously in another terminal).

However,

me@pc:~$ cat /dev/input/event21

this keeps printing stuff.

The fake gamepad also doesn't show up in /dev/input/by-id/ or in /dev/input/by-path/

But I can see it here:


cat /proc/bus/input/devices

I: Bus=0003 Vendor=045e Product=028e Version=0114
N: Name="Microsoft X-Box 360 pad"
P: Phys=usb-0000:02:00.0-1/input0
S: Sysfs=/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/usb3/3-1/3-1:1.0/input/input85
U: Uniq=
H: Handlers=event20 js0 
B: PROP=0
B: EV=20000b
B: KEY=7cdb000000000000 0 0 0 0
B: ABS=3003f
B: FF=107030000 0

I: Bus=0003 Vendor=0001 Product=0001 Version=0001
N: Name="fake"
P: Phys=py-evdev-uinput
S: Sysfs=/devices/virtual/input/input94
U: Uniq=
H: Handlers=event21 js1 
B: PROP=0
B: EV=20000b
B: KEY=7cdb000000000000 0 0 0 0
B: ABS=3003f
B: FF=0

I was thinking maybe it's just a problem with browsers but the KDE Gamepad Controller program shows the same behavior.

This thing works however:

https://github.com/GrantEdwards/uinput-joystick-demo

but I'd prefer to work in python.

Any help appreciated!

ssieb commented

Try using the evtest utility instead of looking at the garbage. :-)

mqnc commented
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x1 product 0x1 version 0x1
Input device name: "fake"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 304 (BTN_SOUTH)
    Event code 305 (BTN_EAST)
    Event code 307 (BTN_NORTH)
    Event code 308 (BTN_WEST)
    Event code 310 (BTN_TL)
    Event code 311 (BTN_TR)
    Event code 314 (BTN_SELECT)
    Event code 315 (BTN_START)
    Event code 316 (BTN_MODE)
    Event code 317 (BTN_THUMBL)
    Event code 318 (BTN_THUMBR)
  Event type 3 (EV_ABS)
    Event code 0 (ABS_X)
      Value     30
      Min   -32768
      Max    32767
      Fuzz      16
      Flat     128
    Event code 1 (ABS_Y)
      Value    495
      Min   -32768
      Max    32767
      Fuzz      16
      Flat     128
    Event code 2 (ABS_Z)
      Value      0
      Min        0
      Max      255
    Event code 3 (ABS_RX)
      Value  -5130
      Min   -32768
      Max    32767
      Fuzz      16
      Flat     128
    Event code 4 (ABS_RY)
      Value   -164
      Min   -32768
      Max    32767
      Fuzz      16
      Flat     128
    Event code 5 (ABS_RZ)
      Value      0
      Min        0
      Max      255
    Event code 16 (ABS_HAT0X)
      Value      0
      Min       -1
      Max        1
    Event code 17 (ABS_HAT0Y)
      Value      0
      Min       -1
      Max        1
  Event type 21 (EV_FF)
Properties:
Testing ... (interrupt to exit)
Event: time 1640600002.895447, type 3 (EV_ABS), code 0 (ABS_X), value 27
Event: time 1640600002.895447, -------------- SYN_REPORT ------------
Event: time 1640600002.895456, type 3 (EV_ABS), code 0 (ABS_X), value 30
Event: time 1640600002.895456, -------------- SYN_REPORT ------------
Event: time 1640600002.995596, type 3 (EV_ABS), code 0 (ABS_X), value 27
Event: time 1640600002.995596, -------------- SYN_REPORT ------------
Event: time 1640600002.995605, type 3 (EV_ABS), code 0 (ABS_X), value 30
Event: time 1640600002.995605, -------------- SYN_REPORT ------------
Event: time 1640600003.095732, type 3 (EV_ABS), code 0 (ABS_X), value 27
Event: time 1640600003.095732, -------------- SYN_REPORT ------------
Event: time 1640600003.095757, type 3 (EV_ABS), code 0 (ABS_X), value 30
Event: time 1640600003.095757, -------------- SYN_REPORT ------------
Event: time 1640600003.195824, type 3 (EV_ABS), code 0 (ABS_X), value 27
Event: time 1640600003.195824, -------------- SYN_REPORT ------------
Event: time 1640600003.195830, type 3 (EV_ABS), code 0 (ABS_X), value 30

This looks good! Although the value doesn't match but that is probably due to some scaling.
I was wondering what other tools I'm unaware of and typed "ev " and discovered
evdev-joystick, evemu-device, evemu-play, evtest, evemu-describe, evemu-event, evemu-record
Those might also be useful. But I'd still prefer to work with a python library :p
But thanks for the hint so far!

I also checked if I can somehow read the output of the older input streams /dev/input/js1 and found that jstest can do it (I thought I tried that yesterday but it just threw an error).

$ jstest /dev/input/js1
Driver version is 2.1.0.
Joystick (fake) has 8 axes (X, Y, Z, Rx, Ry, Rz, Hat0X, Hat0Y)
and 11 buttons (BtnA, BtnB, BtnX, BtnY, BtnTL, BtnTR, BtnSelect, BtnStart, BtnMode, BtnThumbL, BtnThumbR).
Testing ... (interrupt to exit)
Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:   369  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:   369  2:-32767  3:     0  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:   369  2:-32767  3: -5042  4:     0  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:   369  2:-32767  3: -5042  4:   -37  5:     0  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:   369  2:-32767  3: -5042  4:   -37  5:-32767  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:   369  2:-32767  3: -5042  4:   -37  5:-32767  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off Axes:  0:     0  1:   369  2:-32767  3: -5042  4:   -37  5:-32767  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off  9:off 10:off ^C

If I run this for my real gamepad, it prints stuff when I touch it. The fake one immediately prints what I pasted above and nothing more. So I guess that something is wrong with the old interface and browsers connect to that. The behavior in the browser pretty much matches with what I can see in the output here.

mqnc commented

Ok I think I got it.
BTN_0 does not work but BTN_A does. The capabilities() of the gamepad lists ['BTN_A', 'BTN_GAMEPAD', 'BTN_SOUTH']. Furthermore, the axis values that I sent were so miniscule (compared to 32767) that they probably got filtered out by the api as noise to the point that they don't even generate an event. Using BTN_A and higher test values for the axes works fine.

So I guess I got terribly unlucky with my tests :/