From cb577cf2b35c1209ca86121f448acba730b15a74 Mon Sep 17 00:00:00 2001 From: sezanzeb Date: Sat, 13 Feb 2021 14:11:49 +0100 Subject: [PATCH] graphics tablet improvements --- keymapper/dev/injector.py | 2 +- keymapper/dev/utils.py | 28 ++++++++++++++++---- readme/development.md | 7 +++++ tests/test.py | 4 +++ tests/testcases/test_dev_utils.py | 11 ++++++++ tests/testcases/test_injector.py | 44 +++++++++++++++++++++---------- 6 files changed, 76 insertions(+), 20 deletions(-) diff --git a/keymapper/dev/injector.py b/keymapper/dev/injector.py index 861f7e91..5e262ec6 100644 --- a/keymapper/dev/injector.py +++ b/keymapper/dev/injector.py @@ -315,7 +315,7 @@ class Injector: # copy the capabilities because the uinput is going # to act like the device. - capabilities = input_device.capabilities(absinfo=False) + capabilities = input_device.capabilities(absinfo=True) if (self._key_to_code or macros) and capabilities.get(EV_KEY) is None: capabilities[EV_KEY] = [] diff --git a/keymapper/dev/utils.py b/keymapper/dev/utils.py index 65c715f1..7addfb4d 100644 --- a/keymapper/dev/utils.py +++ b/keymapper/dev/utils.py @@ -41,6 +41,15 @@ JOYSTICK = [ ] +# drawing table stylus movements +STYLUS = [ + (EV_ABS, evdev.ecodes.ABS_DISTANCE), + (EV_ABS, evdev.ecodes.ABS_TILT_X), + (EV_ABS, evdev.ecodes.ABS_TILT_Y), + (EV_KEY, evdev.ecodes.BTN_DIGI) +] + + # a third of a quarter circle, so that each quarter is divided in 3 areas: # up, left and up-left. That makes up/down/left/right larger than the # overlapping sections though, maybe it should be 8 equal areas though, idk @@ -97,17 +106,19 @@ def should_map_event_as_btn(event, mapping): Especially important for gamepad events, some of the buttons require special rules. """ - if event.type == EV_KEY: - return True + if (event.type, event.code) in STYLUS: + return False is_mousepad = event.type == EV_ABS and 47 <= event.code <= 61 if is_mousepad: return False - if is_wheel(event): - return True - if event.type == EV_ABS: + if event.code == evdev.ecodes.ABS_MISC: + # what is that even supposed to be. + # the intuos 5 spams those with every event + return False + if event.code in JOYSTICK: l_purpose = mapping.get('gamepad.joystick.left_purpose') r_purpose = mapping.get('gamepad.joystick.right_purpose') @@ -120,6 +131,13 @@ def should_map_event_as_btn(event, mapping): else: return True + if is_wheel(event): + return True + + if event.type == EV_KEY: + # usually all EV_KEY events are allright + return True + return False diff --git a/readme/development.md b/readme/development.md index e104e38d..75e31947 100644 --- a/readme/development.md +++ b/readme/development.md @@ -32,6 +32,7 @@ requests. - [x] automatically load presets when devices get plugged in after login (udev) - [x] map keys using a `modifier + modifier + ... + key` syntax - [ ] injecting keys that aren't available in the systems keyboard layout +- [ ] injecting keys while abs capabilities are present. e.g. stylus buttons ## Tests @@ -45,6 +46,12 @@ coverage combine && coverage report -m To read events, `evtest` is very helpful. Add `-d` to `key-mapper-gtk` to get debug output. +Single tests can be executed via + +```bash +python3 tests/test.py test_paths.TestPaths.test_mkdir +``` + ## Releasing ssh/login into a debian/ubuntu environment diff --git a/tests/test.py b/tests/test.py index 6a487844..3d7bc865 100644 --- a/tests/test.py +++ b/tests/test.py @@ -72,6 +72,10 @@ uinput_write_history_pipe = multiprocessing.Pipe() pending_events = {} +if os.path.exists(tmp): + shutil.rmtree(tmp) + + def read_write_history_pipe(): """convert the write history from the pipe to some easier to manage list""" history = [] diff --git a/tests/testcases/test_dev_utils.py b/tests/testcases/test_dev_utils.py index d3b0c2ec..c7c24ec4 100644 --- a/tests/testcases/test_dev_utils.py +++ b/tests/testcases/test_dev_utils.py @@ -80,12 +80,23 @@ class TestDevUtils(unittest.TestCase): self.assertFalse(do(new_event(EV_ABS, ecodes.ABS_MT_TOOL_Y, 1))) self.assertFalse(do(new_event(EV_ABS, ecodes.ABS_MT_POSITION_X, 1))) + """stylus movements""" + + self.assertFalse(do(new_event(EV_KEY, ecodes.BTN_DIGI, 1))) + self.assertFalse(do(new_event(EV_ABS, ecodes.ABS_TILT_X, 1))) + self.assertFalse(do(new_event(EV_ABS, ecodes.ABS_TILT_Y, 1))) + self.assertFalse(do(new_event(EV_ABS, ecodes.ABS_DISTANCE, 1))) + """joysticks""" self.assertFalse(do(new_event(EV_ABS, ecodes.ABS_RX, 1234))) self.assertFalse(do(new_event(EV_ABS, ecodes.ABS_Y, -1))) self.assertFalse(do(new_event(EV_ABS, ecodes.ABS_RY, -1))) + """weird events""" + + self.assertFalse(do(new_event(EV_ABS, ecodes.ABS_MISC, -1))) + mapping.set('gamepad.joystick.right_purpose', BUTTONS) config.set('gamepad.joystick.left_purpose', BUTTONS) diff --git a/tests/testcases/test_injector.py b/tests/testcases/test_injector.py index d605a7b0..74c14b4b 100644 --- a/tests/testcases/test_injector.py +++ b/tests/testcases/test_injector.py @@ -141,8 +141,8 @@ class TestInjector(unittest.TestCase): device, abs_to_rel ) - self.assertNotIn(evdev.ecodes.EV_ABS, capabilities) - self.assertIn(evdev.ecodes.EV_REL, capabilities) + self.assertNotIn(EV_ABS, capabilities) + self.assertIn(EV_REL, capabilities) self.assertIn(evdev.ecodes.REL_X, capabilities.get(EV_REL)) self.assertIn(evdev.ecodes.REL_Y, capabilities.get(EV_REL)) @@ -173,7 +173,7 @@ class TestInjector(unittest.TestCase): device, gamepad ) - self.assertIn(evdev.ecodes.EV_ABS, capabilities) + self.assertIn(EV_ABS, capabilities) def test_gamepad_purpose_none_2(self): # forward abs joystick events for the left joystick only @@ -194,8 +194,8 @@ class TestInjector(unittest.TestCase): device, gamepad ) - self.assertIn(evdev.ecodes.EV_ABS, capabilities) - self.assertIn(evdev.ecodes.EV_REL, capabilities) + self.assertIn(EV_ABS, capabilities) + self.assertIn(EV_REL, capabilities) custom_mapping.change(Key(EV_KEY, BTN_A, 1), 'a') device = self.injector._grab_device(path) @@ -207,9 +207,9 @@ class TestInjector(unittest.TestCase): device, gamepad ) - self.assertIn(evdev.ecodes.EV_ABS, capabilities) - self.assertIn(evdev.ecodes.EV_REL, capabilities) - self.assertIn(evdev.ecodes.EV_KEY, capabilities) + self.assertIn(EV_ABS, capabilities) + self.assertIn(EV_REL, capabilities) + self.assertIn(EV_KEY, capabilities) def test_adds_ev_key(self): # for some reason, having any EV_KEY capability is needed to @@ -787,11 +787,21 @@ class TestModifyCapabilities(unittest.TestCase): self._capabilities = { evdev.ecodes.EV_SYN: [1, 2, 3], evdev.ecodes.EV_FF: [1, 2, 3], - evdev.ecodes.EV_ABS: [1, 2, 3] + EV_ABS: [ + (1, evdev.AbsInfo( + value=None, min=None, max=1234, fuzz=None, + flat=None, resolution=None + )), + (2, evdev.AbsInfo( + value=None, min=50, max=2345, fuzz=None, + flat=None, resolution=None + )), + 3 + ] } - def capabilities(self, absinfo=True): - assert absinfo is False + def capabilities(self, absinfo=False): + assert absinfo is True return self._capabilities mapping = Mapping() @@ -846,12 +856,18 @@ class TestModifyCapabilities(unittest.TestCase): self.assertNotIn(evdev.ecodes.EV_SYN, capabilities) self.assertNotIn(evdev.ecodes.EV_FF, capabilities) - self.assertNotIn(evdev.ecodes.EV_REL, capabilities) + self.assertNotIn(EV_REL, capabilities) # keeps that stuff since modify_capabilities is told that it is not # a gamepad, so it probably serves some special purpose for that - # device type. - self.assertIn(evdev.ecodes.EV_ABS, capabilities) + # device type. For example drawing tablets need that information in + # order to move the cursor around. Since it keeps ABS, the AbsInfo + # should also be still intact + self.assertIn(EV_ABS, capabilities) + self.assertEqual(capabilities[EV_ABS][0][1].max, 1234) + self.assertEqual(capabilities[EV_ABS][1][1].max, 2345) + self.assertEqual(capabilities[EV_ABS][1][1].min, 50) + self.assertEqual(capabilities[EV_ABS][2], 3) def test_no_abs_volume(self): # I don't know what ABS_VOLUME is, for now I would like to just always