From cdbb3c8b393dec6dc4a69e4922989b6f6c5a3729 Mon Sep 17 00:00:00 2001 From: sezanzeb Date: Wed, 2 Dec 2020 16:17:52 +0100 Subject: [PATCH] simplified keycode injection --- keymapper/dev/injector.py | 14 ++++++++++- keymapper/dev/keycode_mapper.py | 43 +++++++++++---------------------- keymapper/dev/macros.py | 7 ++++-- tests/test.py | 5 ++-- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/keymapper/dev/injector.py b/keymapper/dev/injector.py index 8f5352ce..632c3eda 100644 --- a/keymapper/dev/injector.py +++ b/keymapper/dev/injector.py @@ -302,6 +302,8 @@ class KeycodeInjector: async def _keycode_loop(self, device, uinput, map_ev_abs): """Inject keycodes for one of the virtual devices. + Can be stopped by stopping the asyncio loop. + Parameters ---------- device : evdev.InputDevice @@ -311,6 +313,10 @@ class KeycodeInjector: map_ev_abs : bool if joystick events should be mapped to mouse movements """ + # efficiently figure out the target keycode without taking + # extra steps. + code_code_mapping = {} + # Parse all macros beforehand logger.debug('Parsing macros') macros = {} @@ -321,6 +327,12 @@ class KeycodeInjector: output, lambda *args: self._macro_write(*args, uinput) ) + continue + + target_keycode = system_mapping.get(output) + if target_keycode is None: + logger.error('Don\'t know what %s is', output) + return logger.debug( 'Started injecting into %s, fd %s', @@ -346,7 +358,7 @@ class KeycodeInjector: # linux does them itself, no need to trigger them continue - handle_keycode(self.mapping, macros, event, uinput) + handle_keycode(code_code_mapping, macros, event, uinput) # this should only ever happen in tests to avoid blocking them # forever, as soon as all events are consumed. In normal operation diff --git a/keymapper/dev/keycode_mapper.py b/keymapper/dev/keycode_mapper.py index 446bd076..fe5c5e5b 100644 --- a/keymapper/dev/keycode_mapper.py +++ b/keymapper/dev/keycode_mapper.py @@ -25,49 +25,34 @@ import asyncio from keymapper.logger import logger -from keymapper.state import system_mapping, KEYCODE_OFFSET +from keymapper.state import KEYCODE_OFFSET -def handle_keycode(mapping, macros, event, uinput): +def handle_keycode(code_code_mapping, macros, event, uinput): """Write the mapped keycode.""" - input_keycode = event.code + KEYCODE_OFFSET - character = mapping.get_character(input_keycode) + input_keycode = event.code - if character is None: - # unknown keycode, forward it - target_keycode = input_keycode - elif macros.get(input_keycode) is not None: - if event.value == 0: - return + if input_keycode in macros: + macro = macros[input_keycode] logger.spam( 'got code:%s value:%s, maps to macro %s', event.code + KEYCODE_OFFSET, event.value, - character + macro.code ) - macro = macros.get(input_keycode) - if macro is not None: - asyncio.ensure_future(macro.run()) + asyncio.ensure_future(macro.run()) return - else: - # TODO compile int-int mapping instead of going this route. - # I think that makes the reverse mapping obsolete. - # It already is actually. - target_keycode = system_mapping.get(character) - if target_keycode is None: - logger.error( - 'Don\'t know what %s maps to', - character - ) - return + if input_keycode in code_code_mapping: + target_keycode = code_code_mapping[input_keycode] logger.spam( - 'got code:%s value:%s, maps to code:%s char:%s', + 'got code:%s value:%s, maps to code:%s', event.code + KEYCODE_OFFSET, event.value, - target_keycode, - character + target_keycode ) + else: + target_keycode = input_keycode - uinput.write(event.type, target_keycode - KEYCODE_OFFSET, event.value) + uinput.write(event.type, target_keycode, event.value) uinput.syn() diff --git a/keymapper/dev/macros.py b/keymapper/dev/macros.py index 29c26926..9b41ce57 100644 --- a/keymapper/dev/macros.py +++ b/keymapper/dev/macros.py @@ -53,7 +53,7 @@ DEBUG = 6 class _Macro: """Supports chaining and preparing actions.""" - def __init__(self, handler, depth): + def __init__(self, handler, depth, code): """Create a macro instance that can be populated with tasks. Parameters @@ -65,10 +65,13 @@ class _Macro: depth : int 0 for the outermost parent macro, 1 or greater for child macros, like the second argument of repeat. + code : string + The original parsed code, for logging purposes. """ self.tasks = [] self.handler = handler self.depth = depth + self.code = code async def run(self): """Run the macro.""" @@ -216,7 +219,7 @@ def _parse_recurse(macro, handler, macro_instance=None, depth=0): assert isinstance(depth, int) if macro_instance is None: - macro_instance = _Macro(handler, depth) + macro_instance = _Macro(handler, depth, macro) else: assert isinstance(macro_instance, _Macro) diff --git a/tests/test.py b/tests/test.py index d74dd995..7ff52805 100644 --- a/tests/test.py +++ b/tests/test.py @@ -305,8 +305,9 @@ def main(): # in all of the available tests like unittest.main() does..., # so provide both options. if len(modules) > 0: - # for example `tests/test.py integration.Integration.test_can_start` - # or `tests/test.py integration daemon` + # for example + # `tests/test.py test_integration.TestIntegration.test_can_start` + # or `tests/test.py test_integration test_daemon` testsuite = unittest.defaultTestLoader.loadTestsFromNames( [f'testcases.{module}' for module in modules] )