From 8ac2092e74faeb28a64ca4f4e61f7e0ee11a949f Mon Sep 17 00:00:00 2001 From: sezanzeb Date: Wed, 2 Dec 2020 21:36:54 +0100 Subject: [PATCH] got rid of the confusing xkb keycode offset --- keymapper/dev/injector.py | 12 +++----- keymapper/dev/keycode_mapper.py | 16 +++------- keymapper/dev/reader.py | 5 ++- keymapper/mapping.py | 10 +++--- keymapper/state.py | 8 ++--- tests/test.py | 3 +- tests/testcases/test_daemon.py | 14 ++++----- tests/testcases/test_injector.py | 48 ++++++++++++++--------------- tests/testcases/test_integration.py | 12 ++++---- tests/testcases/test_mapping.py | 6 ++-- tests/testcases/test_reader.py | 5 ++- 11 files changed, 62 insertions(+), 77 deletions(-) diff --git a/keymapper/dev/injector.py b/keymapper/dev/injector.py index fe665078..fd147cc7 100644 --- a/keymapper/dev/injector.py +++ b/keymapper/dev/injector.py @@ -33,7 +33,7 @@ from evdev.ecodes import EV_KEY, EV_ABS from keymapper.logger import logger from keymapper.getdevices import get_devices -from keymapper.state import system_mapping, KEYCODE_OFFSET +from keymapper.state import system_mapping from keymapper.dev.keycode_mapper import handle_keycode, \ should_map_event_as_btn from keymapper.dev.ev_abs_mapper import ev_abs_mapper, JOYSTICK @@ -144,7 +144,7 @@ class KeycodeInjector: needed = False for (ev_type, keycode), _ in self.mapping: # TODO test ev_type - if keycode - KEYCODE_OFFSET in capabilities.get(ev_type, []): + if keycode in capabilities.get(ev_type, []): needed = True break @@ -208,7 +208,7 @@ class KeycodeInjector: keycode = system_mapping.get(character) if keycode is not None: - capabilities[EV_KEY].append(keycode - KEYCODE_OFFSET) + capabilities[EV_KEY].append(keycode) if abs_to_rel: del capabilities[ecodes.EV_ABS] @@ -315,7 +315,7 @@ class KeycodeInjector: 'macro writes code:%s value:%d char:%s', keycode, value, character ) - uinput.write(EV_KEY, keycode - KEYCODE_OFFSET, value) + uinput.write(EV_KEY, keycode, value) uinput.syn() async def _keycode_loop(self, device, uinput, abs_to_rel): @@ -340,8 +340,6 @@ class KeycodeInjector: logger.debug('Parsing macros') macros = {} for (ev_type, keycode), output in self.mapping: - keycode -= KEYCODE_OFFSET - if '(' in output and ')' in output and len(output) >= 4: # probably a macro macros[keycode] = parse( @@ -355,7 +353,7 @@ class KeycodeInjector: logger.error('Don\'t know what %s is', output) continue - code_code_mapping[keycode] = target_keycode - KEYCODE_OFFSET + code_code_mapping[keycode] = target_keycode logger.debug( 'Started injecting into %s, fd %s', diff --git a/keymapper/dev/keycode_mapper.py b/keymapper/dev/keycode_mapper.py index 9feda761..89364f41 100644 --- a/keymapper/dev/keycode_mapper.py +++ b/keymapper/dev/keycode_mapper.py @@ -27,7 +27,6 @@ import asyncio import evdev from keymapper.logger import logger -from keymapper.state import KEYCODE_OFFSET from keymapper.dev.ev_abs_mapper import JOYSTICK @@ -60,8 +59,7 @@ def handle_keycode(code_code_mapping, macros, event, uinput): Parameters ---------- code_code_mapping : dict - mapping of linux-keycode to linux-keycode. No need to substract - anything before writing to the device. + mapping of linux-keycode to linux-keycode. macros : dict mapping of linux-keycode to _Macro objects """ @@ -72,10 +70,6 @@ def handle_keycode(code_code_mapping, macros, event, uinput): input_keycode = event.code input_type = event.type - # for logging purposes. It should log the same keycode as xev and gtk, - # which is also displayed in the UI. - xkb_keycode = input_keycode + KEYCODE_OFFSET - if input_keycode in macros: if event.value != 1: # only key-down events trigger macros @@ -84,7 +78,7 @@ def handle_keycode(code_code_mapping, macros, event, uinput): macro = macros[input_keycode] logger.spam( 'got code:%s value:%s, maps to macro %s', - xkb_keycode, + input_keycode, event.value, macro.code ) @@ -96,15 +90,15 @@ def handle_keycode(code_code_mapping, macros, event, uinput): target_type = evdev.events.EV_KEY logger.spam( 'got code:%s value:%s event:%s, maps to EV_KEY:%s', - xkb_keycode, + input_keycode, event.value, evdev.ecodes.EV[event.type], - target_keycode + KEYCODE_OFFSET + target_keycode ) else: logger.spam( 'got unmapped code:%s value:%s', - xkb_keycode, + input_keycode, event.value, ) target_keycode = input_keycode diff --git a/keymapper/dev/reader.py b/keymapper/dev/reader.py index b4e96e4a..dd7611cf 100644 --- a/keymapper/dev/reader.py +++ b/keymapper/dev/reader.py @@ -30,7 +30,6 @@ import evdev from keymapper.logger import logger from keymapper.getdevices import get_devices, refresh_devices -from keymapper.state import KEYCODE_OFFSET from keymapper.dev.keycode_mapper import should_map_event_as_btn @@ -114,11 +113,11 @@ class _KeycodeReader: if should_map_event_as_btn(event.type, event.code): logger.spam( 'got code:%s value:%s type:%s', - event.code + KEYCODE_OFFSET, + event.code, event.value, evdev.ecodes.EV[event.type] ) - self._pipe[1].send((event.type, event.code + KEYCODE_OFFSET)) + self._pipe[1].send((event.type, event.code)) def _read_worker(self): """Process that reads keycodes and buffers them into a pipe.""" diff --git a/keymapper/mapping.py b/keymapper/mapping.py index 05d60e2d..b0ae81ae 100644 --- a/keymapper/mapping.py +++ b/keymapper/mapping.py @@ -63,15 +63,14 @@ class Mapping: Everything will be mapped to EV_KEY. new_keycode : int The source keycode, what the mouse would report without any - modification. xkb keycode. + modification. character : string or string[] - A single character known to xkb, Examples: KP_1, Shift_L, a, B. - Can also be an array, which is used for reading the xkbmap output - completely. + A single character known to xkb or linux. + Examples: KP_1, Shift_L, a, B, BTN_LEFT. previous_keycode : int or None If None, will not remove any previous mapping. If you recently used 10 for new_keycode and want to overwrite that with 11, - provide 5 here. xkb keycode. + provide 5 here. """ try: new_keycode = int(new_keycode) @@ -98,7 +97,6 @@ class Mapping: Parameters ---------- keycode : int - the xkb keycode ev_type : int one of evdev.events """ diff --git a/keymapper/state.py b/keymapper/state.py index 3e7c4154..2d1714d6 100644 --- a/keymapper/state.py +++ b/keymapper/state.py @@ -30,8 +30,8 @@ import evdev from keymapper.mapping import Mapping -# offset between xkb and linux keycodes. linux keycodes are lower -KEYCODE_OFFSET = 8 +# xkb uses keycodes that are 8 higher than those from evdev +XKB_KEYCODE_OFFSET = 8 def populate_system_mapping(): @@ -42,10 +42,10 @@ def populate_system_mapping(): mappings = re.findall(r'(\d+) = (.+)\n', xmodmap) for keycode, names in mappings: for name in names.split(): - mapping[name] = int(keycode) + mapping[name] = int(keycode) - XKB_KEYCODE_OFFSET for name, ecode in evdev.ecodes.ecodes.items(): - mapping[name] = ecode + KEYCODE_OFFSET + mapping[name] = ecode return mapping diff --git a/tests/test.py b/tests/test.py index 7ff52805..714c1354 100644 --- a/tests/test.py +++ b/tests/test.py @@ -149,8 +149,7 @@ class Event: type : int one of evdev.ecodes.EV_* code : int - keyboard event code as known to linux. E.g. 2 for the '1' button, - which would be 10 in xkb + keyboard event code as known to linux. E.g. 2 for the '1' button value : int 1 for down, 0 for up, 2 for hold """ diff --git a/tests/testcases/test_daemon.py b/tests/testcases/test_daemon.py index 953d05d9..c5a74909 100644 --- a/tests/testcases/test_daemon.py +++ b/tests/testcases/test_daemon.py @@ -31,7 +31,7 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk from keymapper.state import custom_mapping, system_mapping, \ - clear_system_mapping, KEYCODE_OFFSET + clear_system_mapping from keymapper.config import config from keymapper.daemon import Daemon, get_dbus_interface, BUS_NAME @@ -97,7 +97,7 @@ class TestDaemon(unittest.TestCase): config.set_autoload_preset('device 2', preset) pending_events['device 2'] = [ - Event(evdev.events.EV_KEY, keycode_from_1 - KEYCODE_OFFSET, 0), + Event(evdev.events.EV_KEY, keycode_from_1, 0), ] self.daemon = Daemon() @@ -108,15 +108,15 @@ class TestDaemon(unittest.TestCase): event = uinput_write_history_pipe[0].recv() self.assertEqual(event.type, evdev.events.EV_KEY) - self.assertEqual(event.code, keycode_to_1 - KEYCODE_OFFSET) + self.assertEqual(event.code, keycode_to_1) self.assertEqual(event.value, 0) self.daemon.stop_injecting('device 2') self.assertFalse(self.daemon.is_injecting('device 2')) pending_events['device 2'] = [ - Event(evdev.events.EV_KEY, keycode_from_2 - KEYCODE_OFFSET, 1), - Event(evdev.events.EV_KEY, keycode_from_2 - KEYCODE_OFFSET, 0), + Event(evdev.events.EV_KEY, keycode_from_2, 1), + Event(evdev.events.EV_KEY, keycode_from_2, 0), ] time.sleep(0.2) @@ -126,12 +126,12 @@ class TestDaemon(unittest.TestCase): event = uinput_write_history_pipe[0].recv() self.assertEqual(event.type, evdev.events.EV_KEY) - self.assertEqual(event.code, keycode_to_2 - KEYCODE_OFFSET) + self.assertEqual(event.code, keycode_to_2) self.assertEqual(event.value, 1) event = uinput_write_history_pipe[0].recv() self.assertEqual(event.type, evdev.events.EV_KEY) - self.assertEqual(event.code, keycode_to_2 - KEYCODE_OFFSET) + self.assertEqual(event.code, keycode_to_2) self.assertEqual(event.value, 0) diff --git a/tests/testcases/test_injector.py b/tests/testcases/test_injector.py index 133d2152..66950ce9 100644 --- a/tests/testcases/test_injector.py +++ b/tests/testcases/test_injector.py @@ -30,12 +30,12 @@ from keymapper.dev.injector import is_numlock_on, toggle_numlock,\ ensure_numlock, KeycodeInjector from keymapper.dev.keycode_mapper import handle_keycode from keymapper.state import custom_mapping, system_mapping, \ - clear_system_mapping, KEYCODE_OFFSET + clear_system_mapping from keymapper.mapping import Mapping from keymapper.config import config from keymapper.dev.macros import parse -from tests.test import uinput_write_history, Event, pending_events, fixtures, \ +from tests.test import Event, pending_events, fixtures, \ clear_write_history, EVENT_READ_TIMEOUT, uinput_write_history_pipe, \ MAX_ABS @@ -81,7 +81,7 @@ class TestInjector(unittest.TestCase): character='a' ) - maps_to = system_mapping['a'] - KEYCODE_OFFSET + maps_to = system_mapping['a'] self.injector = KeycodeInjector('foo', mapping) fake_device = FakeDevice() @@ -302,14 +302,14 @@ class TestInjector(unittest.TestCase): # keycode used in X and in the mappings pending_events['device 2'] = [ # should execute a macro - Event(EV_KEY, 0, 1), - Event(EV_KEY, 0, 0), + Event(EV_KEY, 8, 1), + Event(EV_KEY, 8, 0), # normal keystroke - Event(EV_KEY, 1, 1), - Event(EV_KEY, 1, 0), + Event(EV_KEY, 9, 1), + Event(EV_KEY, 9, 0), # just pass those over without modifying - Event(EV_KEY, 2, 1), - Event(EV_KEY, 2, 0), + Event(EV_KEY, 10, 1), + Event(EV_KEY, 10, 0), Event(3124, 3564, 6542), ] @@ -334,30 +334,30 @@ class TestInjector(unittest.TestCase): # keystrokes are all over the place. # just check if they are there and if so, remove them from the list. ev_key = EV_KEY - self.assertIn((ev_key, code_q - KEYCODE_OFFSET, 1), history) - self.assertIn((ev_key, code_q - KEYCODE_OFFSET, 0), history) - self.assertIn((ev_key, code_w - KEYCODE_OFFSET, 1), history) - self.assertIn((ev_key, code_w - KEYCODE_OFFSET, 0), history) - index_q_1 = history.index((ev_key, code_q - KEYCODE_OFFSET, 1)) - index_q_0 = history.index((ev_key, code_q - KEYCODE_OFFSET, 0)) - index_w_1 = history.index((ev_key, code_w - KEYCODE_OFFSET, 1)) - index_w_0 = history.index((ev_key, code_w - KEYCODE_OFFSET, 0)) + self.assertIn((ev_key, code_q, 1), history) + self.assertIn((ev_key, code_q, 0), history) + self.assertIn((ev_key, code_w, 1), history) + self.assertIn((ev_key, code_w, 0), history) + index_q_1 = history.index((ev_key, code_q, 1)) + index_q_0 = history.index((ev_key, code_q, 0)) + index_w_1 = history.index((ev_key, code_w, 1)) + index_w_0 = history.index((ev_key, code_w, 0)) self.assertGreater(index_q_0, index_q_1) self.assertGreater(index_w_1, index_q_0) self.assertGreater(index_w_0, index_w_1) del history[index_q_1] - index_q_0 = history.index((ev_key, code_q - KEYCODE_OFFSET, 0)) + index_q_0 = history.index((ev_key, code_q, 0)) del history[index_q_0] - index_w_1 = history.index((ev_key, code_w - KEYCODE_OFFSET, 1)) + index_w_1 = history.index((ev_key, code_w, 1)) del history[index_w_1] - index_w_0 = history.index((ev_key, code_w - KEYCODE_OFFSET, 0)) + index_w_0 = history.index((ev_key, code_w, 0)) del history[index_w_0] # the rest should be in order. - self.assertEqual(history[0], (ev_key, code_a - KEYCODE_OFFSET, 1)) - self.assertEqual(history[1], (ev_key, code_a - KEYCODE_OFFSET, 0)) - self.assertEqual(history[2], (ev_key, input_b - KEYCODE_OFFSET, 1)) - self.assertEqual(history[3], (ev_key, input_b - KEYCODE_OFFSET, 0)) + self.assertEqual(history[0], (ev_key, code_a, 1)) + self.assertEqual(history[1], (ev_key, code_a, 0)) + self.assertEqual(history[2], (ev_key, input_b, 1)) + self.assertEqual(history[3], (ev_key, input_b, 0)) self.assertEqual(history[4], (3124, 3564, 6542)) diff --git a/tests/testcases/test_integration.py b/tests/testcases/test_integration.py index 318da8a6..baedc5b8 100644 --- a/tests/testcases/test_integration.py +++ b/tests/testcases/test_integration.py @@ -36,7 +36,7 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk from keymapper.state import custom_mapping, system_mapping, \ - clear_system_mapping, KEYCODE_OFFSET + clear_system_mapping from keymapper.paths import CONFIG, get_config_path from keymapper.config import config from keymapper.dev.reader import keycode_reader @@ -408,8 +408,8 @@ class TestIntegration(unittest.TestCase): system_mapping['a'] = keycode_to pending_events['device 2'] = [ - Event(evdev.events.EV_KEY, keycode_from - KEYCODE_OFFSET, 1), - Event(evdev.events.EV_KEY, keycode_from - KEYCODE_OFFSET, 0) + Event(evdev.events.EV_KEY, keycode_from, 1), + Event(evdev.events.EV_KEY, keycode_from, 0) ] custom_mapping.save('device 2', 'foo preset') @@ -428,12 +428,12 @@ class TestIntegration(unittest.TestCase): event = uinput_write_history_pipe[0].recv() self.assertEqual(event.type, evdev.events.EV_KEY) - self.assertEqual(event.code, keycode_to - KEYCODE_OFFSET) + self.assertEqual(event.code, keycode_to) self.assertEqual(event.value, 1) event = uinput_write_history_pipe[0].recv() self.assertEqual(event.type, evdev.events.EV_KEY) - self.assertEqual(event.code, keycode_to - KEYCODE_OFFSET) + self.assertEqual(event.code, keycode_to) self.assertEqual(event.value, 0) def test_stop_injecting(self): @@ -446,7 +446,7 @@ class TestIntegration(unittest.TestCase): # not all of those events should be processed, since that takes some # time due to time.sleep in the fakes and the injection is stopped. - pending_events['device 2'] = [Event(1, keycode_from - KEYCODE_OFFSET, 1)] * 100 + pending_events['device 2'] = [Event(1, keycode_from, 1)] * 100 custom_mapping.save('device 2', 'foo preset') diff --git a/tests/testcases/test_mapping.py b/tests/testcases/test_mapping.py index 39fdf03f..4c5a55a5 100644 --- a/tests/testcases/test_mapping.py +++ b/tests/testcases/test_mapping.py @@ -35,10 +35,8 @@ class TestMapping(unittest.TestCase): # not actually a mapping object, just a dict mapping = populate_system_mapping() self.assertGreater(len(mapping), 100) - # xkb keycode 10 is typically mapped to '1' - self.assertEqual(mapping['1'], 10) - # linux keycodes are properly increased to the xkb keycodes - self.assertEqual(mapping['KEY_1'], 10) + self.assertEqual(mapping['1'], 2) + self.assertEqual(mapping['KEY_1'], 2) self.assertEqual(mapping['KEY_LEFTSHIFT'], mapping['Shift_L']) def test_clone(self): diff --git a/tests/testcases/test_reader.py b/tests/testcases/test_reader.py index ef958cd1..6a14e942 100644 --- a/tests/testcases/test_reader.py +++ b/tests/testcases/test_reader.py @@ -25,7 +25,6 @@ from evdev.events import EV_KEY import time from keymapper.dev.reader import keycode_reader -from keymapper.state import KEYCODE_OFFSET from tests.test import Event, pending_events, EVENT_READ_TIMEOUT @@ -58,7 +57,7 @@ class TestReader(unittest.TestCase): keycode_reader._pipe[0].send((EV_KEY, 1234)) time.sleep(EVENT_READ_TIMEOUT * 5) - self.assertEqual(keycode_reader.read(), (EV_KEY, CODE_3 + KEYCODE_OFFSET)) + self.assertEqual(keycode_reader.read(), (EV_KEY, CODE_3)) self.assertEqual(keycode_reader.read(), (None, None)) def test_wrong_device(self): @@ -106,7 +105,7 @@ class TestReader(unittest.TestCase): keycode_reader.start_reading('device 1') time.sleep(EVENT_READ_TIMEOUT * 5) - self.assertEqual(keycode_reader.read(), (EV_KEY, CODE_3 + KEYCODE_OFFSET)) + self.assertEqual(keycode_reader.read(), (EV_KEY, CODE_3)) self.assertEqual(keycode_reader.read(), (None, None))