Hello community, here is the log from the commit of package python-evdev for openSUSE:Factory checked in at 2018-08-29 12:26:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-evdev (Old) and /work/SRC/openSUSE:Factory/.python-evdev.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-evdev" Wed Aug 29 12:26:24 2018 rev:3 rq:631923 version:1.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-evdev/python-evdev.changes 2018-06-29 22:34:44.886087855 +0200 +++ /work/SRC/openSUSE:Factory/.python-evdev.new/python-evdev.changes 2018-08-29 12:26:25.275556810 +0200 @@ -1,0 +2,9 @@ +Tue Aug 28 08:00:44 UTC 2018 - [email protected] + +- Update to version 1.1.0 + * Add support for handling force-feedback effect uploads. + * Fix typo preventing force-feedback effects that need left + coefficients from working. +- Add _service file to fetch source from Git. + +------------------------------------------------------------------- Old: ---- v1.0.0.tar.gz New: ---- _service v1.1.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-evdev.spec ++++++ --- /var/tmp/diff_new_pack.yIr3H0/_old 2018-08-29 12:26:25.879558134 +0200 +++ /var/tmp/diff_new_pack.yIr3H0/_new 2018-08-29 12:26:25.883558143 +0200 @@ -19,7 +19,7 @@ %define modname evdev %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-evdev -Version: 1.0.0 +Version: 1.1.0 Release: 0 Summary: Python bindings to the Linux input handling subsystem License: BSD-3-Clause ++++++ _service ++++++ <services> <service name="obs_scm" mode="disabled"> <param name="url">https://github.com/gvalkov/python-evdev.git</param> <param name="scm">git</param> <param name="revision">v1.1.0</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> </service> <service name="set_version" mode="disabled" /> </services> ++++++ v1.0.0.tar.gz -> v1.1.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/docs/changelog.rst new/python-evdev-1.1.0/docs/changelog.rst --- old/python-evdev-1.0.0/docs/changelog.rst 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/docs/changelog.rst 2018-08-27 21:11:25.000000000 +0200 @@ -1,6 +1,14 @@ Changelog --------- +1.1.0 (Aug 27, 2018) +==================== + +- Add support for handling force-feedback effect uploads (many thanks to `@ndreys`). + +- Fix typo preventing ff effects that need left coefficients from working. + + 1.0.0 (Jun 02, 2018) ==================== @@ -335,6 +343,7 @@ .. _`@isia`: https://github.com/isia .. _`@forsenonlhaimaisentito`: https://github.com/forsenonlhaimaisentito .. _`@paulo-raca`: https://github.com/paulo-raca +.. _`@ndreys`: https://github.com/ndreys .. _issue21121: http://bugs.python.org/issue21121 .. _`#63`: https://github.com/gvalkov/python-evdev/issues/63 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/docs/conf.py new/python-evdev-1.1.0/docs/conf.py --- old/python-evdev-1.0.0/docs/conf.py 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/docs/conf.py 2018-08-27 21:11:25.000000000 +0200 @@ -60,7 +60,7 @@ # built documents. # # The full version, including alpha/beta/rc tags. -release = '1.0.0' +release = '1.1.0' # The short X.Y version. version = release diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/docs/install.rst new/python-evdev-1.1.0/docs/install.rst --- old/python-evdev-1.0.0/docs/install.rst 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/docs/install.rst 2018-08-27 21:11:25.000000000 +0200 @@ -10,7 +10,10 @@ <a href="https://www.archlinux.org/packages/extra/x86_64/python-evdev/"> <img height="30px" src="_static/pacifica-icon-set/distributor-logo-archlinux.png"> </a> - <a href="https://packages.ubuntu.com/artful/python-evdev"> + <a href="https://packages.debian.org/search?searchon=names&keywords=python-evdev"> + <img height="30px" src="_static/pacifica-icon-set/distributor-logo-debian.png"> + </a> + <a href="https://packages.ubuntu.com/search?suite=default§ion=all&arch=any&keywords=python-evdev&searchon=names"> <img height="30px" src="_static/pacifica-icon-set/distributor-logo-ubuntu.png"> </a> <a href="https://apps.fedoraproject.org/packages/python3-evdev"> @@ -24,7 +27,7 @@ --!> </div> -Consult the relevant documentation of your OS package manager for installation instructions. +Consult the documentation of your OS package manager for installation instructions. From source diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/docs/tutorial.rst new/python-evdev-1.1.0/docs/tutorial.rst --- old/python-evdev-1.0.0/docs/tutorial.rst 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/docs/tutorial.rst 2018-08-27 21:11:25.000000000 +0200 @@ -362,3 +362,75 @@ .. _`async/await`: https://docs.python.org/3/library/asyncio-task.html + +Create ``uinput`` device capable of recieving FF-effects +======================================================== + +:: + + import asyncio + from evdev import UInput, categorize, ecodes + + cap = { + ecodes.EV_FF: [ecodes.FF_RUMBLE ], + ecodes.EV_KEY: [ecodes.KEY_A, ecodes.KEY_B] + } + + ui = UInput(cap, name='test-controller', version=0x3) + + async def print_events(device): + async for event in device.async_read_loop(): + print(categorize(event)) + + # Wait for an EV_UINPUT event that will signal us that an + # effect upload/erase operation is in progress. + if event.type != ecodes.EV_UINPUT: + pass + + if event.code == ecodes.UI_FF_UPLOAD: + upload = device.begin_upload(event.value) + upload.retval = 0 + + print(f'[upload] effect_id: {upload.effect_id}, type: {upload.effect.type}') + device.end_upload(upload) + + elif event.code == ecodes.UI_FF_ERASE: + erase = device.begin_erase(event.value) + print(f'[erase] effect_id {erase.effect_id}') + + erase.retval = 0 + device.end_erase(erase) + + asyncio.ensure_future(print_events(ui)) + loop = asyncio.get_event_loop() + loop.run_forever() + + +Injecting an FF-event into first FF-capable device found +======================================================== + +:: + + from evdev import ecodes, InputDevice, ff + + # Find first EV_FF capable event device (that we have permissions to use). + for name in evdev.list_devices(): + dev = InputDevice(name) + if ecodes.EV_FF in dev.capabilities(): + break + + rumble = ff.Rumble(strong_magnitude=0x0000, weak_magnitude=0xffff) + effect_type = ff.EffectType(ff_rumble_effect=rumble) + duration_ms = 1000 + + effect = ff.Effect( + ecodes.FF_RUMBLE, -1, 0, + ff.Trigger(0, 0), + ff.Replay(duration_ms, 0), + ff.EffectType(ff_rumble_effect=rumble) + ) + + repeat_count = 1 + effect_id = dev.upload_effect(effect) + dev.write(e.EV_FF, effect_id, repeat_count) + dev.erase_effect(effect_id) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/evdev/ff.py new/python-evdev-1.1.0/evdev/ff.py --- old/python-evdev-1.0.0/evdev/ff.py 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/evdev/ff.py 2018-08-27 21:11:25.000000000 +0200 @@ -8,6 +8,7 @@ _u16 = ctypes.c_uint16 _u32 = ctypes.c_uint32 _s16 = ctypes.c_int16 +_s32 = ctypes.c_int32 class Replay(ctypes.Structure): ''' @@ -100,7 +101,7 @@ ('right_saturation', _u16), ('left_saturation', _u16), ('right_coeff', _s16), - ('left_foeff', _s16), + ('left_coeff', _s16), ('deadband', _u16), ('center', _s16), ] @@ -167,6 +168,21 @@ ('u', EffectType) ] +class UInputUpload(ctypes.Structure): + _fields_ = [ + ('request_id', _u32), + ('retval', _s32), + ('effect', Effect), + ('old', Effect), + ] + +class UInputErase(ctypes.Structure): + _fields_ = [ + ('request_id', _u32), + ('retval', _s32), + ('effect_id', _u32), + ] + # ff_types = { # ecodes.FF_CONSTANT, # ecodes.FF_PERIODIC, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/evdev/genecodes.py new/python-evdev-1.1.0/evdev/genecodes.py --- old/python-evdev-1.0.0/evdev/genecodes.py 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/evdev/genecodes.py 2018-08-27 21:11:25.000000000 +0200 @@ -20,7 +20,7 @@ #----------------------------------------------------------------------------- -macro_regex = r'#define +((?:KEY|ABS|REL|SW|MSC|LED|BTN|REP|SND|ID|EV|BUS|SYN|FF)_\w+)' +macro_regex = r'#define +((?:KEY|ABS|REL|SW|MSC|LED|BTN|REP|SND|ID|EV|BUS|SYN|FF|UI_FF)_\w+)' macro_regex = re.compile(macro_regex) uname = list(os.uname()); del uname[1] @@ -34,6 +34,7 @@ #include <dev/evdev/input.h> #else #include <linux/input.h> +#include <linux/uinput.h> #endif /* Automatically generated by evdev.genecodes */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/evdev/input.c new/python-evdev-1.1.0/evdev/input.c --- old/python-evdev-1.0.0/evdev/input.c 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/evdev/input.c 2018-08-27 21:11:25.000000000 +0200 @@ -381,6 +381,11 @@ effect->u.constant.envelope.attack_level, effect->u.constant.envelope.fade_length, effect->u.constant.envelope.fade_level); + + case FF_RUMBLE: + fprintf(stderr, " rumble: (%d, %d)\n", + effect->u.rumble.strong_magnitude, + effect->u.rumble.weak_magnitude); break; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/evdev/uinput.c new/python-evdev-1.1.0/evdev/uinput.c --- old/python-evdev-1.0.0/evdev/uinput.c 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/evdev/uinput.c 2018-08-27 21:11:25.000000000 +0200 @@ -69,7 +69,7 @@ static PyObject * -uinput_create(PyObject *self, PyObject *args) { +uinput_setup(PyObject *self, PyObject *args) { int fd, len, i, abscode; uint16_t vendor, product, version, bustype; @@ -89,6 +89,8 @@ uidev.id.version = version; uidev.id.bustype = bustype; + uidev.ff_effects_max = FF_MAX_EFFECTS; + len = PyList_Size(absinfo); for (i=0; i<len; i++) { // item -> (ABS_X, 0, 255, 0, 0, 0, 0) @@ -113,6 +115,22 @@ /* goto on_err; */ /* } */ + Py_RETURN_NONE; + + on_err: + _uinput_close(fd); + PyErr_SetFromErrno(PyExc_IOError); + return NULL; +} + +static PyObject * +uinput_create(PyObject *self, PyObject *args) +{ + int fd; + + int ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + if (ioctl(fd, UI_DEV_CREATE) < 0) goto on_err; @@ -206,6 +224,25 @@ return NULL; } +int _uinput_begin_upload(int fd, struct uinput_ff_upload *upload) +{ + return ioctl(fd, UI_BEGIN_FF_UPLOAD, upload); +} + +int _uinput_end_upload(int fd, struct uinput_ff_upload *upload) +{ + return ioctl(fd, UI_END_FF_UPLOAD, upload); +} + +int _uinput_begin_erase(int fd, struct uinput_ff_erase *upload) +{ + return ioctl(fd, UI_BEGIN_FF_ERASE, upload); +} + +int _uinput_end_erase(int fd, struct uinput_ff_erase *upload) +{ + return ioctl(fd, UI_END_FF_ERASE, upload); +} #define MODULE_NAME "_uinput" #define MODULE_HELP "Python bindings for parts of linux/uinput.c" @@ -214,6 +251,9 @@ { "open", uinput_open, METH_VARARGS, "Open uinput device node."}, + { "setup", uinput_setup, METH_VARARGS, + "Set an uinput device up."}, + { "create", uinput_create, METH_VARARGS, "Create an uinput device."}, @@ -228,7 +268,7 @@ { "set_phys", uinput_set_phys, METH_VARARGS, "Set physical path"}, - + { NULL, NULL, 0, NULL} }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/evdev/uinput.py new/python-evdev-1.1.0/evdev/uinput.py --- old/python-evdev-1.0.0/evdev/uinput.py 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/evdev/uinput.py 2018-08-27 21:11:25.000000000 +0200 @@ -8,6 +8,8 @@ from evdev import _uinput from evdev import ecodes, util, device from evdev.events import InputEvent +import evdev.ff as ff +import ctypes try: from evdev.eventio_async import EventIO @@ -131,6 +133,8 @@ # Set phys name _uinput.set_phys(self.fd, phys) + _uinput.setup(self.fd, name, vendor, product, version, bustype, absinfo) + # Set device capabilities. for etype, codes in events.items(): for code in codes: @@ -149,7 +153,11 @@ _uinput.enable(self.fd, etype, code) # Create the uinput device. - _uinput.create(self.fd, name, vendor, product, version, bustype, absinfo) + _uinput.create(self.fd) + + self.dll = ctypes.CDLL(_uinput.__file__) + self.dll._uinput_begin_upload.restype = ctypes.c_int + self.dll._uinput_end_upload.restype = ctypes.c_int #: An :class:`InputDevice <evdev.device.InputDevice>` instance #: for the fake input device. ``None`` if the device cannot be @@ -206,6 +214,35 @@ return self.device.capabilities(verbose, absinfo) + def begin_upload(self, effect_id): + upload = ff.UInputUpload() + upload.effect_id = effect_id + + if self.dll._uinput_begin_upload(self.fd, ctypes.byref(upload)): + raise UInputError('Failed to begin uinput upload: ' + + os.strerror()) + + return upload + + def end_upload(self, upload): + if self.dll._uinput_end_upload(self.fd, ctypes.byref(upload)): + raise UInputError('Failed to end uinput upload: ' + + os.strerror()) + + def begin_erase(self, effect_id): + erase = ff.UInputErase() + erase.effect_id = effect_id + + if self.dll._uinput_begin_erase(self.fd, ctypes.byref(erase)): + raise UInputError('Failed to begin uinput erase: ' + + os.strerror()) + return erase + + def end_erase(self, erase): + if self.dll._uinput_end_erase(self.fd, ctypes.byref(erase)): + raise UInputError('Failed to end uinput erase: ' + + os.strerror()) + def _verify(self): ''' Verify that an uinput device exists and is readable and writable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/setup.cfg new/python-evdev-1.1.0/setup.cfg --- old/python-evdev-1.0.0/setup.cfg 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/setup.cfg 2018-08-27 21:11:25.000000000 +0200 @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.0.0 +current_version = 1.1.0 message = Bump version: {current_version} -> {new_version} commit = True tag = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evdev-1.0.0/setup.py new/python-evdev-1.1.0/setup.py --- old/python-evdev-1.0.0/setup.py 2018-06-02 00:42:45.000000000 +0200 +++ new/python-evdev-1.1.0/setup.py 2018-08-27 21:11:25.000000000 +0200 @@ -44,7 +44,7 @@ #----------------------------------------------------------------------------- kw = { 'name': 'evdev', - 'version': '1.0.0', + 'version': '1.1.0', 'description': 'Bindings to the Linux input handling subsystem', 'long_description': open(pjoin(here, 'README.rst')).read(), @@ -70,6 +70,7 @@ headers = [ '/usr/include/linux/input.h', '/usr/include/linux/input-event-codes.h', + '/usr/include/linux/uinput.h', ] headers = [header for header in headers if os.path.isfile(header)]
