mirror of
https://github.com/sezanzeb/input-remapper
synced 2024-11-04 12:00:16 +00:00
macro improvements
This commit is contained in:
parent
e159aff995
commit
845b7c2397
@ -40,7 +40,8 @@ Documentation:
|
|||||||
- `m` holds a modifier while executing the second parameter
|
- `m` holds a modifier while executing the second parameter
|
||||||
- `.` executes two actions behind each other
|
- `.` executes two actions behind each other
|
||||||
|
|
||||||
For a list of supported keystrokes and their names, check the output of `xmodmap -pke`
|
For a list of supported keystrokes and their names, check the output of
|
||||||
|
`xmodmap -pke`
|
||||||
|
|
||||||
Maybe you shouldn't use this feature in online PVP though. Might even get
|
Maybe you shouldn't use this feature in online PVP though. Might even get
|
||||||
detected by the game.
|
detected by the game.
|
||||||
|
@ -42,9 +42,18 @@ from keymapper.logger import logger
|
|||||||
from keymapper.config import config
|
from keymapper.config import config
|
||||||
|
|
||||||
|
|
||||||
|
# for debugging purposes
|
||||||
|
MODIFIER = 1
|
||||||
|
CHILD_MACRO = 2
|
||||||
|
SLEEP = 3
|
||||||
|
REPEAT = 4
|
||||||
|
KEYSTROKE = 5
|
||||||
|
DEBUG = 6
|
||||||
|
|
||||||
|
|
||||||
class _Macro:
|
class _Macro:
|
||||||
"""Supports chaining and preparing actions."""
|
"""Supports chaining and preparing actions."""
|
||||||
def __init__(self, handler):
|
def __init__(self, handler, depth):
|
||||||
"""Create a macro instance that can be populated with tasks.
|
"""Create a macro instance that can be populated with tasks.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -53,13 +62,17 @@ class _Macro:
|
|||||||
A function that accepts keycodes as the first parameter and the
|
A function that accepts keycodes as the first parameter and the
|
||||||
key-press state as the second. 1 for down and 0 for up. The
|
key-press state as the second. 1 for down and 0 for up. The
|
||||||
macro will write to this function once executed with `.run()`.
|
macro will write to this function once executed with `.run()`.
|
||||||
|
depth : int
|
||||||
|
0 for the outermost parent macro, 1 or greater for child macros,
|
||||||
|
like the second argument of repeat.
|
||||||
"""
|
"""
|
||||||
self.tasks = []
|
self.tasks = []
|
||||||
self.handler = handler
|
self.handler = handler
|
||||||
|
self.depth = depth
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
"""Run the macro."""
|
"""Run the macro."""
|
||||||
for task in self.tasks:
|
for i, (_, task) in enumerate(self.tasks):
|
||||||
coroutine = task()
|
coroutine = task()
|
||||||
if asyncio.iscoroutine(coroutine):
|
if asyncio.iscoroutine(coroutine):
|
||||||
await coroutine
|
await coroutine
|
||||||
@ -76,11 +89,11 @@ class _Macro:
|
|||||||
modifier : str
|
modifier : str
|
||||||
macro : _Macro
|
macro : _Macro
|
||||||
"""
|
"""
|
||||||
self.tasks.append(lambda: self.handler(modifier, 1))
|
self.tasks.append((MODIFIER, lambda: self.handler(modifier, 1)))
|
||||||
self.add_keycode_pause()
|
self.add_keycode_pause()
|
||||||
self.tasks.append(macro.run)
|
self.tasks.append((CHILD_MACRO, macro.run))
|
||||||
self.add_keycode_pause()
|
self.add_keycode_pause()
|
||||||
self.tasks.append(lambda: self.handler(modifier, 0))
|
self.tasks.append((MODIFIER, lambda: self.handler(modifier, 0)))
|
||||||
self.add_keycode_pause()
|
self.add_keycode_pause()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -93,7 +106,7 @@ class _Macro:
|
|||||||
macro : _Macro
|
macro : _Macro
|
||||||
"""
|
"""
|
||||||
for _ in range(repeats):
|
for _ in range(repeats):
|
||||||
self.tasks.append(macro.run)
|
self.tasks.append((CHILD_MACRO, macro.run))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_keycode_pause(self):
|
def add_keycode_pause(self):
|
||||||
@ -103,17 +116,17 @@ class _Macro:
|
|||||||
async def sleep():
|
async def sleep():
|
||||||
await asyncio.sleep(sleeptime)
|
await asyncio.sleep(sleeptime)
|
||||||
|
|
||||||
self.tasks.append(sleep)
|
self.tasks.append((SLEEP, sleep))
|
||||||
|
|
||||||
def keycode(self, character):
|
def keycode(self, character):
|
||||||
"""Write the character."""
|
"""Write the character."""
|
||||||
self.tasks.append(lambda: self.handler(character, 1))
|
self.tasks.append((KEYSTROKE, lambda: self.handler(character, 1)))
|
||||||
self.tasks.append(lambda: logger.spam(
|
self.tasks.append((DEBUG, lambda: logger.spam(
|
||||||
'macro writes character %s',
|
'macro writes character %s',
|
||||||
character
|
character
|
||||||
))
|
)))
|
||||||
self.add_keycode_pause()
|
self.add_keycode_pause()
|
||||||
self.tasks.append(lambda: self.handler(character, 0))
|
self.tasks.append((KEYSTROKE, lambda: self.handler(character, 0)))
|
||||||
self.add_keycode_pause()
|
self.add_keycode_pause()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -124,7 +137,7 @@ class _Macro:
|
|||||||
async def sleep():
|
async def sleep():
|
||||||
await asyncio.sleep(sleeptime)
|
await asyncio.sleep(sleeptime)
|
||||||
|
|
||||||
self.tasks.append(sleep)
|
self.tasks.append((SLEEP, sleep))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
@ -171,7 +184,6 @@ def _parse_recurse(macro, handler, macro_instance=None, depth=0):
|
|||||||
macro_instance : _Macro or None
|
macro_instance : _Macro or None
|
||||||
A macro instance to add tasks to
|
A macro instance to add tasks to
|
||||||
depth : int
|
depth : int
|
||||||
For logging and debugging purposes
|
|
||||||
"""
|
"""
|
||||||
# to anyone who knows better about compilers and thinks this is horrible:
|
# to anyone who knows better about compilers and thinks this is horrible:
|
||||||
# please make a pull request. Because it probably is.
|
# please make a pull request. Because it probably is.
|
||||||
@ -184,7 +196,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)
|
macro_instance = _Macro(handler, depth)
|
||||||
else:
|
else:
|
||||||
assert isinstance(macro_instance, _Macro)
|
assert isinstance(macro_instance, _Macro)
|
||||||
|
|
||||||
@ -192,7 +204,7 @@ def _parse_recurse(macro, handler, macro_instance=None, depth=0):
|
|||||||
space = ' ' * depth
|
space = ' ' * depth
|
||||||
|
|
||||||
# is it another macro?
|
# is it another macro?
|
||||||
call_match = re.match(r'^(\w+)\(.+?', macro)
|
call_match = re.match(r'^(\w+)\(', macro)
|
||||||
call = call_match[1] if call_match else None
|
call = call_match[1] if call_match else None
|
||||||
if call is not None:
|
if call is not None:
|
||||||
# available functions in the macro
|
# available functions in the macro
|
||||||
@ -255,6 +267,7 @@ def _parse_recurse(macro, handler, macro_instance=None, depth=0):
|
|||||||
macro = int(macro)
|
macro = int(macro)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
logger.spam('%s%s %s', space, type(macro), macro)
|
||||||
return macro
|
return macro
|
||||||
|
|
||||||
|
|
||||||
@ -272,8 +285,11 @@ def parse(macro, handler):
|
|||||||
key-press state as the second. 1 for down and 0 for up. The
|
key-press state as the second. 1 for down and 0 for up. The
|
||||||
macro will write to this function once executed with `.run()`.
|
macro will write to this function once executed with `.run()`.
|
||||||
"""
|
"""
|
||||||
|
# whitespaces, tabs, newlines and such don't serve a purpose. make
|
||||||
|
# the log output clearer.
|
||||||
|
macro = re.sub(r'\s', '', macro)
|
||||||
|
logger.spam('preparing macro %s for later execution', macro)
|
||||||
try:
|
try:
|
||||||
logger.spam('input %s', macro)
|
|
||||||
return _parse_recurse(macro, handler)
|
return _parse_recurse(macro, handler)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Failed to parse macro "%s": %s', macro, e)
|
logger.error('Failed to parse macro "%s": %s', macro, e)
|
||||||
|
@ -41,10 +41,10 @@ class TestMacros(unittest.TestCase):
|
|||||||
self.assertListEqual(self.result, [(1, 1), (1, 0)])
|
self.assertListEqual(self.result, [(1, 1), (1, 0)])
|
||||||
|
|
||||||
def test_1(self):
|
def test_1(self):
|
||||||
macro = 'k(1 2).k(a).k(3)'
|
macro = 'k(1).k(a).k(3)'
|
||||||
self.loop.run_until_complete(parse(macro, self.handler).run())
|
self.loop.run_until_complete(parse(macro, self.handler).run())
|
||||||
self.assertListEqual(self.result, [
|
self.assertListEqual(self.result, [
|
||||||
('1 2', 1), ('1 2', 0),
|
(1, 1), (1, 0),
|
||||||
('a', 1), ('a', 0),
|
('a', 1), ('a', 0),
|
||||||
(3, 1), (3, 0),
|
(3, 1), (3, 0),
|
||||||
])
|
])
|
||||||
@ -77,7 +77,7 @@ class TestMacros(unittest.TestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
def test_4(self):
|
def test_4(self):
|
||||||
macro = ' r(2,\nk(\rr ).k(-\n )).k(m) '
|
macro = ' r(2,\nk(\nr ).k(-\n )).k(m) '
|
||||||
self.loop.run_until_complete(parse(macro, self.handler).run())
|
self.loop.run_until_complete(parse(macro, self.handler).run())
|
||||||
self.assertListEqual(self.result, [
|
self.assertListEqual(self.result, [
|
||||||
('r', 1), ('r', 0),
|
('r', 1), ('r', 0),
|
||||||
@ -89,7 +89,7 @@ class TestMacros(unittest.TestCase):
|
|||||||
|
|
||||||
def test_5(self):
|
def test_5(self):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
macro = 'w(200).r(2,m(w,\rr(2,\tk(r))).w(10).k(k))'
|
macro = 'w(200).r(2,m(w,\nr(2,\tk(r))).w(10).k(k))'
|
||||||
self.loop.run_until_complete(parse(macro, self.handler).run())
|
self.loop.run_until_complete(parse(macro, self.handler).run())
|
||||||
|
|
||||||
num_pauses = 8 + 6 + 4
|
num_pauses = 8 + 6 + 4
|
||||||
|
Loading…
Reference in New Issue
Block a user