From e9c7336e7e2fd51a1ce08d821eaea320aac7bdad Mon Sep 17 00:00:00 2001 From: Spas Kalinov Date: Tue, 18 Aug 2026 21:31:12 +0300 Subject: [PATCH] uinput: support event types without codes --- docs/changelog.rst | 6 ++++++ src/evdev/uinput.c | 22 ++++++++++++++++++++++ src/evdev/uinput.py | 8 +++++++- tests/test_uinput.py | 10 ++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index bcf1636..631b6b2 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,12 @@ Changelog --------- +Unreleased +========== + +- Allow ``UInput`` event types without event codes, such as ``EV_REP``. + + 1.9.3 (Feb 05, 2025) ==================== diff --git a/src/evdev/uinput.c b/src/evdev/uinput.c index 9d0b87c..af8a929 100644 --- a/src/evdev/uinput.c +++ b/src/evdev/uinput.c @@ -298,6 +298,25 @@ uinput_write(PyObject *self, PyObject *args) } +static PyObject * +uinput_enable_event_type(PyObject *self, PyObject *args) +{ + int fd; + uint16_t type; + + int ret = PyArg_ParseTuple(args, "ih", &fd, &type); + if (!ret) return NULL; + + if (ioctl(fd, UI_SET_EVBIT, type) < 0) { + _uinput_close(fd); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_RETURN_NONE; +} + + static PyObject * uinput_enable_event(PyObject *self, PyObject *args) { @@ -376,6 +395,9 @@ static PyMethodDef MethodTable[] = { { "enable", uinput_enable_event, METH_VARARGS, "Enable a type of event."}, + { "enable_type", uinput_enable_event_type, METH_VARARGS, + "Enable an event type without enabling an event code."}, + { "set_phys", uinput_set_phys, METH_VARARGS, "Set physical path"}, diff --git a/src/evdev/uinput.py b/src/evdev/uinput.py index 2c69c2b..446311d 100644 --- a/src/evdev/uinput.py +++ b/src/evdev/uinput.py @@ -106,7 +106,9 @@ def __init__( events : dict Dictionary of event types mapping to lists of event codes. The event types and codes that the uinput device will be able to - inject - defaults to all key codes. + inject - defaults to all key codes. An event type mapped to an + empty sequence enables the event type without enabling any event + codes, which is useful for types such as ``EV_REP``. name The name of the input device. @@ -165,6 +167,10 @@ def __init__( for prop in input_props: _uinput.set_prop(self.fd, prop) + for etype, codes in events.items(): + if not codes: + _uinput.enable_type(self.fd, etype) + for etype, code in prepared_events: _uinput.enable(self.fd, etype, code) diff --git a/tests/test_uinput.py b/tests/test_uinput.py index 666361f..e38274f 100644 --- a/tests/test_uinput.py +++ b/tests/test_uinput.py @@ -67,6 +67,16 @@ def test_enable_events(c): assert sorted(cap[e.EV_KEY]) == sorted(c["events"][e.EV_KEY]) +def test_enable_event_type_without_codes(c): + e = ecodes + c["events"] = {e.EV_KEY: [e.KEY_A], e.EV_REP: []} + + with uinput.UInput(**c) as ui: + repeat = ui.device.repeat + assert repeat.delay > 0 + assert repeat.repeat > 0 + + def test_abs_values(c): e = ecodes c = {