simplified keycode injection

pull/14/head
sezanzeb 4 years ago
parent afa8365599
commit cdbb3c8b39

@ -302,6 +302,8 @@ class KeycodeInjector:
async def _keycode_loop(self, device, uinput, map_ev_abs): async def _keycode_loop(self, device, uinput, map_ev_abs):
"""Inject keycodes for one of the virtual devices. """Inject keycodes for one of the virtual devices.
Can be stopped by stopping the asyncio loop.
Parameters Parameters
---------- ----------
device : evdev.InputDevice device : evdev.InputDevice
@ -311,6 +313,10 @@ class KeycodeInjector:
map_ev_abs : bool map_ev_abs : bool
if joystick events should be mapped to mouse movements 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 # Parse all macros beforehand
logger.debug('Parsing macros') logger.debug('Parsing macros')
macros = {} macros = {}
@ -321,6 +327,12 @@ class KeycodeInjector:
output, output,
lambda *args: self._macro_write(*args, uinput) 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( logger.debug(
'Started injecting into %s, fd %s', 'Started injecting into %s, fd %s',
@ -346,7 +358,7 @@ class KeycodeInjector:
# linux does them itself, no need to trigger them # linux does them itself, no need to trigger them
continue 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 # this should only ever happen in tests to avoid blocking them
# forever, as soon as all events are consumed. In normal operation # forever, as soon as all events are consumed. In normal operation

@ -25,49 +25,34 @@
import asyncio import asyncio
from keymapper.logger import logger 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.""" """Write the mapped keycode."""
input_keycode = event.code + KEYCODE_OFFSET input_keycode = event.code
character = mapping.get_character(input_keycode)
if character is None: if input_keycode in macros:
# unknown keycode, forward it macro = macros[input_keycode]
target_keycode = input_keycode
elif macros.get(input_keycode) is not None:
if event.value == 0:
return
logger.spam( logger.spam(
'got code:%s value:%s, maps to macro %s', 'got code:%s value:%s, maps to macro %s',
event.code + KEYCODE_OFFSET, event.code + KEYCODE_OFFSET,
event.value, event.value,
character macro.code
) )
macro = macros.get(input_keycode) asyncio.ensure_future(macro.run())
if macro is not None:
asyncio.ensure_future(macro.run())
return 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( 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.code + KEYCODE_OFFSET,
event.value, event.value,
target_keycode, target_keycode
character
) )
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() uinput.syn()

@ -53,7 +53,7 @@ DEBUG = 6
class _Macro: class _Macro:
"""Supports chaining and preparing actions.""" """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. """Create a macro instance that can be populated with tasks.
Parameters Parameters
@ -65,10 +65,13 @@ class _Macro:
depth : int depth : int
0 for the outermost parent macro, 1 or greater for child macros, 0 for the outermost parent macro, 1 or greater for child macros,
like the second argument of repeat. like the second argument of repeat.
code : string
The original parsed code, for logging purposes.
""" """
self.tasks = [] self.tasks = []
self.handler = handler self.handler = handler
self.depth = depth self.depth = depth
self.code = code
async def run(self): async def run(self):
"""Run the macro.""" """Run the macro."""
@ -216,7 +219,7 @@ def _parse_recurse(macro, handler, macro_instance=None, depth=0):
assert isinstance(depth, int) assert isinstance(depth, int)
if macro_instance is None: if macro_instance is None:
macro_instance = _Macro(handler, depth) macro_instance = _Macro(handler, depth, macro)
else: else:
assert isinstance(macro_instance, _Macro) assert isinstance(macro_instance, _Macro)

@ -305,8 +305,9 @@ def main():
# in all of the available tests like unittest.main() does..., # in all of the available tests like unittest.main() does...,
# so provide both options. # so provide both options.
if len(modules) > 0: if len(modules) > 0:
# for example `tests/test.py integration.Integration.test_can_start` # for example
# or `tests/test.py integration daemon` # `tests/test.py test_integration.TestIntegration.test_can_start`
# or `tests/test.py test_integration test_daemon`
testsuite = unittest.defaultTestLoader.loadTestsFromNames( testsuite = unittest.defaultTestLoader.loadTestsFromNames(
[f'testcases.{module}' for module in modules] [f'testcases.{module}' for module in modules]
) )

Loading…
Cancel
Save