repeating macros while holding keys

xkb
sezanzeb 4 years ago committed by sezanzeb
parent 8cc63244f5
commit cb7cc67e7f

@ -117,11 +117,11 @@ cd key-mapper && sudo python3 setup.py install
- [x] support timed macros, maybe using some sort of syntax
- [x] add to the AUR, provide .deb file
- [x] basic support for gamepads as keyboard and mouse combi
- [x] executing a macro forever while holding down the key
- [ ] map D-Pad and Joystick directions as buttons, joystick purpose via config
- [ ] automatically load presets when devices get plugged in after login
- [ ] option to write hwdb configs for lower level mappings ([Remapping keys using hwdb files](https://www.reddit.com/r/linux_gaming/comments/k3h9qv/remapping_keys_using_hwdb_files/))
- [ ] mapping a combined button press to a key
- [ ] executing a macro while holding down the key
## Tests

@ -65,20 +65,34 @@ def handle_keycode(code_to_code, macros, event, uinput):
mapping of linux-keycode to linux-keycode
macros : dict
mapping of linux-keycode to _Macro objects
event : evdev.InputEvent
"""
if event.value == 2:
# button-hold event
# button-hold event. Linux seems to create them on its own, no need
# to inject them.
return
input_keycode = event.code
input_type = event.type
if input_keycode in macros:
if event.value == 0:
# key-release event. Tell the macro for that keycode
# that the key is released and let it decide what to with that
# information.
macro = active_macros.get(input_keycode)
# TODO test
if macro is not None:
macro.release_key()
if event.value != 1:
# only key-down events trigger macros
return
macro = macros[input_keycode]
active_macros[input_keycode] = macro
# TODO test that holding is true
macro.holding = True
logger.spam(
'got code:%s value:%s, maps to macro %s',
input_keycode,

@ -80,6 +80,8 @@ class _Macro:
# all required capabilities, without those of child macros
self.capabilities = set()
# TODO test that child_macros is properly populated
self.child_macros = []
def get_capabilities(self):
@ -100,9 +102,8 @@ class _Macro:
macro will write to this function once executed with `.run()`.
"""
self.handler = handler
for task_type, task in self.tasks:
if task_type == CHILD_MACRO:
task.set_handler(handler)
for macro in self.child_macros:
macro.set_handler(handler)
async def run(self):
"""Run the macro."""
@ -113,9 +114,6 @@ class _Macro:
logger.debug('Macro execution stopped')
break
if task_type == CHILD_MACRO:
task = task.run
coroutine = task()
if asyncio.iscoroutine(coroutine):
await coroutine
@ -125,7 +123,13 @@ class _Macro:
# TODO test
self.running = False
async def hold(self, macro):
def release_key(self):
"""Tell all child macros that the key was released."""
self.holding = False
for macro in self.child_macros:
macro.release_key()
def hold(self, macro):
"""Loops the execution until key release."""
if not isinstance(macro, _Macro):
raise ValueError(
@ -134,12 +138,15 @@ class _Macro:
)
# TODO test
def task():
async def task():
while self.holding and self.running:
await self.run()
await macro.run()
self.tasks.append((REPEAT, task))
self.child_macros.append(macro)
return self
def modify(self, modifier, macro):
@ -164,9 +171,11 @@ class _Macro:
self.capabilities.add(code)
self.child_macros.append(macro)
self.tasks.append((MODIFIER, lambda: self.handler(code, 1)))
self.add_keycode_pause()
self.tasks.append((CHILD_MACRO, macro))
self.tasks.append((CHILD_MACRO, macro.run))
self.add_keycode_pause()
self.tasks.append((MODIFIER, lambda: self.handler(code, 0)))
self.add_keycode_pause()
@ -195,7 +204,10 @@ class _Macro:
)
for _ in range(repeats):
self.tasks.append((CHILD_MACRO, macro))
self.tasks.append((CHILD_MACRO, macro.run))
self.child_macros.append(macro)
return self
def add_keycode_pause(self):

@ -154,7 +154,10 @@ def push_event(device, event):
class Event:
"""Event to put into the injector for tests."""
"""Event to put into the injector for tests.
fakes evdev.InputEvent
"""
def __init__(self, type, code, value):
"""
Paramaters

@ -33,6 +33,7 @@ class TestKeycodeMapper(unittest.TestCase):
self.assertFalse(should_map_event_as_btn(EV_ABS, ABS_X))
self.assertFalse(should_map_event_as_btn(EV_REL, REL_X))
# TODO test for macro holding
if __name__ == "__main__":
unittest.main()

Loading…
Cancel
Save