gvalkov / python-evdev

Python bindings for the Linux input subsystem
https://python-evdev.rtfd.org/
BSD 3-Clause "New" or "Revised" License
320 stars 108 forks source link

SystemError: Objects/longobject.c:404: bad argument to internal #84

Open OliverGavin opened 6 years ago

OliverGavin commented 6 years ago

I'm following the tutorial here but an exception is being thrown...

>>> from evdev import UInput, AbsInfo, ecodes as e

>>> cap = {
...     e.EV_KEY : [e.KEY_A, e.KEY_B],
...     e.EV_ABS : [
...         (e.ABS_X, AbsInfo(value=0, min=0, max=255,
...                           fuzz=0, flat=0, resolution=0)),
...         (e.ABS_Y, AbsInfo(0, 0, 255, 0, 0, 0)),
...         (e.ABS_MT_POSITION_X, (0, 255, 128, 0)) ]
... }

>>> ui = UInput(cap, name='example-device', version=0x3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 147, in __init__
    _uinput.create(self.fd, name, vendor, product, version, bustype, absinfo)
SystemError: /builddir/build/BUILD/Python-3.6.2/Objects/longobject.c:404: bad argument to internal function

I tried to fix it like this:

>>> from evdev import UInput, AbsInfo, ecodes as e

>>> cap = {
...     e.EV_KEY : [e.KEY_A, e.KEY_B],
...     e.EV_ABS : [
...         (e.ABS_X, AbsInfo(value=0, min=0, max=255,
...                           fuzz=0, flat=0, resolution=0)),
...         (e.ABS_Y, AbsInfo(0, 0, 255, 0, 0, 0)) ]
... }

>>> ui = UInput(cap, name='example-device', version=0x3)
>>> print(ui)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 171, in __str__
    evtypes = [i[0] for i in self.capabilities(True).keys()]
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 200, in capabilities
    raise UInputError('input device not opened - cannot read capabilites')
evdev.uinput.UInputError: input device not opened - cannot read capabilites

I tried copying the capabilities of my trackpad with the same error:

>>> cap = {
...     e.EV_KEY: [
...         e.BTN_LEFT,
...         e.BTN_MOUSE,
...         e.BTN_RIGHT,
...         e.BTN_TOOL_FINGER,
...         e.BTN_TOUCH,
...         e.BTN_TOOL_DOUBLETAP,
...         e.BTN_TOOL_TRIPLETAP
...     ],
...     e.EV_ABS: [
...         (e.ABS_X, AbsInfo(value=2869, min=0, max=2940, fuzz=0, flat=0, resolution=31)),
...         (e.ABS_Y, AbsInfo(value=540, min=0, max=1400, fuzz=0, flat=0, resolution=31)),
...         (e.ABS_PRESSURE, AbsInfo(value=0, min=0, max=255, fuzz=0, flat=0, resolution=0)),
...         (e.ABS_TOOL_WIDTH, AbsInfo(value=0, min=0, max=15, fuzz=0, flat=0, resolution=0)),
...         (e.ABS_MT_SLOT, AbsInfo(value=0, min=0, max=1, fuzz=0, flat=0, resolution=0)),
...         (e.ABS_MT_POSITION_X, AbsInfo(value=0, min=0, max=2940, fuzz=0, flat=0, resolution=31)),
...         (e.ABS_MT_POSITION_Y, AbsInfo(value=0, min=0, max=1400, fuzz=0, flat=0, resolution=31)),
...         (e.ABS_MT_TRACKING_ID, AbsInfo(value=0, min=0, max=65535, fuzz=0, flat=0, resolution=0))
...     ]
... }
>>> 
>>> ui = UInput(cap, name='example-device', version=0x1)
>>> print(ui)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 171, in __str__
    evtypes = [i[0] for i in self.capabilities(True).keys()]
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 200, in capabilities
    raise UInputError('input device not opened - cannot read capabilites')
evdev.uinput.UInputError: input device not opened - cannot read capabilites

How do I fix this? What does it mean if the 'input device not opened'? can I open it?

My goal is write touch events on a device with no touch screen (input using a camera).

ssieb commented 6 years ago

Are you running this as root or have you given your user some permissions? I get an error at the line trying to create the UInput device when running as a user, but no problems at all when running as root. I added myself to the input group and then I have no errors when running as my user either.

OliverGavin commented 6 years ago

Ok I'll try that.

I had given myself permission with chmod +0666 /dev/input but maybe that was insufficient

OliverGavin commented 6 years ago

I rebooted so my permissions reverted to default.

Adding myself to the input group, the error is:

Traceback (most recent call last):
  File "mouse.py", line 239, in <module>
    ui = UInput(cap, name='example-device', version=0x3)
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 125, in __init__
    self._verify()
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 221, in _verify
    raise UInputError(msg.format(self.devnode))
evdev.uinput.UInputError: "/dev/uinput" cannot be opened for writing

After running chmod +0666 /dev/uinput the error changes to:

Traceback (most recent call last):
  File "mouse.py", line 239, in <module>
    ui = UInput(cap, name='example-device', version=0x3)
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 147, in __init__
    _uinput.create(self.fd, name, vendor, product, version, bustype, absinfo)
SystemError: /builddir/build/BUILD/Python-3.6.2/Objects/longobject.c:404: bad argument to internal function

Removing (e.ABS_MT_POSITION_X, (0, 255, 128, 0)):

Traceback (most recent call last):
  File "mouse.py", line 150, in <module>
    print(ui)
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 171, in __str__
    evtypes = [i[0] for i in self.capabilities(True).keys()]
  File "/home/user/.virtualenvs/venv/lib/python3.6/site-packages/evdev/uinput.py", line 200, in capabilities
    raise UInputError('input device not opened - cannot read capabilites')
evdev.uinput.UInputError: input device not opened - cannot read capabilites
gvalkov commented 6 years ago

Hi @OliverGavin,

evdev.uinput.UInputError: input device not opened - cannot read capabilities

UInput() creates a new input device in /dev/input/ that you most likely don't have access to. Adding yourself to the input group should fix that. Another option is to add an udev group that changes the attributes of the device. For example:

# /etc/udev/rules.d/10-local.rules
KERNEL=="event*", NAME="input/%k", MODE="660", GROUP="input", OWNER="oliver"

Reload udev with:

udevadm control --reload-rules 
udevadm trigger

You could do the same thing with uinput, though I'm not sure what the exact rule syntax to match /dev/uinput would be.

I can reproduce the ABS_MT_POSITION_X issue - I'll look into it.

gvalkov commented 6 years ago

It should work if you set ABS_MT_POSITION_X to an AbsInfo or just pass a tuple of 6 elements. There is no validation in uinput.c.

OliverGavin commented 6 years ago

@gvalkov

I tried the AbsInfo and now I get this:

Traceback (most recent call last):
  File "mouse.py", line 240, in <module>
    ui = UInput(cap, name='ETPS/2 Elantech Touchpad', version=0x3)
  File "/home/oligavin/.virtualenvs/venv_python36_fyp_pytrack/lib/python3.6/site-packages/evdev/uinput.py", line 147, in __init__
    _uinput.create(self.fd, name, vendor, product, version, bustype, absinfo)
OSError: [Errno 22] Invalid argument
cap = {
    e.EV_KEY: [e.KEY_A, e.KEY_B],
    e.EV_ABS: [
        (e.ABS_X, AbsInfo(value=0, min=0, max=255,
                          fuzz=0, flat=0, resolution=0)),
        (e.ABS_Y, AbsInfo(0, 0, 255, 0, 0, 0)),
        (e.ABS_MT_POSITION_X, AbsInfo(0, 255, 128, 0, 0, 0))
    ]
}

ui = UInput(cap, name='example-device', version=0x3)
print(ui)

EDIT: e.ABS_MT_POSITION_X, AbsInfo(value=0, min=0, max=2940, fuzz=0, flat=0, resolution=31) fixed the error. The min was greater than the max in the tutorial... Maybe some validation could make these issues easier ;)

OliverGavin commented 6 years ago

Ok so I've got this working:

from evdev import UInput, AbsInfo, ecodes as e

cap = {
    e.EV_KEY: [e.KEY_A, e.KEY_B],
    e.EV_ABS: [
        (e.ABS_X, AbsInfo(value=0, min=0, max=255,
                          fuzz=0, flat=0, resolution=0)),
        (e.ABS_Y, AbsInfo(0, 0, 255, 0, 0, 0)),
        # (e.ABS_MT_POSITION_X, AbsInfo(0, 255, 128, 0, 0, 0))
    ]
}

ui = UInput(cap, name='ETPS/2 Elantech Touchpad', version=0x3)
print(ui)

The problem was that name must be an existing input device like name='ETPS/2 Elantech Touchpad'.

Does it have to be an existing device? I want to do this on a raspberry pi which doesn't already have a trackpad listed like this (naturally). Can evdev create the virtual device or do I have to do that manually some how?

I still can't get anything to actually happen however, relative or absolute... no errors, no response

OliverGavin commented 6 years ago

Apologies, everything works if I add time.sleep(0.02) after ui.syn() with enough events (I converted from the test tool to code).

I misunderstood what absolute in ABS meant, I was expecting the pointer to go to a particular position on the screen... but rather it is a particular point on the trackpad.

Is there any way that I can register a 'fake' device to simulate a touch screen? or at least is it possible to set the pointers initial position?

My best guess right now is that in order for ABS events to function like a touch screen event, I need to simulate a touchscreen rather than a trackpad and let linux handle it correctly, is that correct?

gvalkov commented 6 years ago

I don't think you can do that with evdev alone. If you're running X11, perhaps try any of the Python bindings to xlib/xcb. It's also fairly straightforward with xdotool mousemove.