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):
"""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

@ -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()

@ -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)

@ -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]
)

Loading…
Cancel
Save