From f06d33ad349c2a6200fbd3c2c78ad3caef87b88e Mon Sep 17 00:00:00 2001 From: sezanzeb Date: Fri, 12 Feb 2021 21:43:40 +0100 Subject: [PATCH] writing combinations by using 'key + key + ...' --- keymapper/dev/macros.py | 34 +++++++++++++++ readme/development.md | 2 +- readme/plus.png | Bin 0 -> 3453 bytes readme/screenshot.png | Bin 29535 -> 29872 bytes readme/usage.md | 10 +++++ tests/test.py | 24 ++++++++--- tests/testcases/test_config.py | 4 +- tests/testcases/test_control.py | 4 +- tests/testcases/test_event_producer.py | 4 +- tests/testcases/test_injector.py | 6 +-- tests/testcases/test_keycode_mapper.py | 4 +- tests/testcases/test_macros.py | 57 ++++++++++++++++++++++++- tests/testcases/test_mapping.py | 6 +-- tests/testcases/test_paths.py | 4 +- tests/testcases/test_reader.py | 4 +- 15 files changed, 137 insertions(+), 26 deletions(-) create mode 100644 readme/plus.png diff --git a/keymapper/dev/macros.py b/keymapper/dev/macros.py index 852ce6d7..47d082ee 100644 --- a/keymapper/dev/macros.py +++ b/keymapper/dev/macros.py @@ -55,6 +55,10 @@ def is_this_a_macro(output): if not isinstance(output, str): return False + if '+' in output.strip(): + # for example "a + b" + return True + return '(' in output and ')' in output and len(output) >= 4 @@ -441,6 +445,34 @@ def _parse_recurse(macro, mapping, macro_instance=None, depth=0): return macro +def handle_plus_syntax(macro): + """transform a + b + c to m(a, m(b, m(c, h())))""" + if '+' not in macro: + return macro + + if '(' in macro or ')' in macro: + logger.error('Mixing "+" and macros is unsupported: "%s"', macro) + return macro + + chunks = [chunk.strip() for chunk in macro.split('+')] + output = '' + depth = 0 + for chunk in chunks: + if chunk == '': + # invalid syntax + logger.error('Invalid syntax for "%s"', macro) + return macro + + depth += 1 + output += f'm({chunk},' + + output += 'h()' + output += depth * ')' + + logger.debug('Transformed "%s" to "%s"', macro, output) + return output + + def parse(macro, mapping, return_errors=False): """parse and generate a _Macro that can be run as often as you want. @@ -460,6 +492,8 @@ def parse(macro, mapping, return_errors=False): If True, returns errors as a string or None if parsing worked. If False, returns the parsed macro. """ + macro = handle_plus_syntax(macro) + # whitespaces, tabs, newlines and such don't serve a purpose. make # the log output clearer and the parsing easier. macro = re.sub(r'\s', '', macro) diff --git a/readme/development.md b/readme/development.md index c43e80f7..e104e38d 100644 --- a/readme/development.md +++ b/readme/development.md @@ -30,7 +30,7 @@ requests. - [x] mapping joystick directions as buttons, making it act like a D-Pad - [x] mapping mouse wheel events to buttons - [x] automatically load presets when devices get plugged in after login (udev) -- [ ] map keys using a `modifier + modifier + ... + key` syntax +- [x] map keys using a `modifier + modifier + ... + key` syntax - [ ] injecting keys that aren't available in the systems keyboard layout ## Tests diff --git a/readme/plus.png b/readme/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..2d44daa380519eee7c48bbc892d09038459b62c8 GIT binary patch literal 3453 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 EZ{@4+82|tP literal 29535 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 JbH(3&_#cLr(OCch diff --git a/readme/usage.md b/readme/usage.md index 3e5b6047..25a35268 100644 --- a/readme/usage.md +++ b/readme/usage.md @@ -60,6 +60,16 @@ your focused application.

+## Writing Combinations + +You can write `control_l + a` as mapping, which will inject those two +keycodes into your system on a single key press. An arbitrary number of +names can be chained using ` + `. + +

+ +

+ ## Macros It is possible to write timed macros into the center column: diff --git a/tests/test.py b/tests/test.py index a1b6341f..3a798ab7 100644 --- a/tests/test.py +++ b/tests/test.py @@ -411,9 +411,11 @@ _fixture_copy = copy.deepcopy(fixtures) environ_copy = copy.deepcopy(os.environ) -def cleanup(): +def quick_cleanup(log=True): """Reset the applications state.""" - print('cleanup') + if log: + print('quick cleanup') + keycode_reader.stop_reading() keycode_reader.__init__() @@ -421,10 +423,6 @@ def cleanup(): for task in asyncio.all_tasks(): task.cancel() - os.system('pkill -f key-mapper-service') - - time.sleep(0.05) - if os.path.exists(tmp): shutil.rmtree(tmp) @@ -459,6 +457,20 @@ def cleanup(): if key not in environ_copy: del os.environ[key] + +def cleanup(): + """Reset the applications state. + + Using this is very slow, usually quick_cleanup() is sufficient. + """ + print('cleanup') + + os.system('pkill -f key-mapper-service') + + time.sleep(0.05) + + quick_cleanup(log=False) + refresh_devices() diff --git a/tests/testcases/test_config.py b/tests/testcases/test_config.py index 848970aa..052834b6 100644 --- a/tests/testcases/test_config.py +++ b/tests/testcases/test_config.py @@ -25,12 +25,12 @@ import unittest from keymapper.config import config, GlobalConfig from keymapper.paths import touch, CONFIG_PATH -from tests.test import cleanup, tmp +from tests.test import quick_cleanup, tmp class TestConfig(unittest.TestCase): def tearDown(self): - cleanup() + quick_cleanup() self.assertEqual(len(config.iterate_autoload_presets()), 0) def test_migrate(self): diff --git a/tests/testcases/test_control.py b/tests/testcases/test_control.py index a38fe13c..216d9cdf 100644 --- a/tests/testcases/test_control.py +++ b/tests/testcases/test_control.py @@ -35,7 +35,7 @@ from keymapper.daemon import Daemon from keymapper.mapping import Mapping from keymapper.paths import get_preset_path -from tests.test import cleanup, tmp +from tests.test import quick_cleanup, tmp def import_control(): @@ -63,7 +63,7 @@ options = collections.namedtuple( class TestControl(unittest.TestCase): def tearDown(self): - cleanup() + quick_cleanup() def test_autoload(self): devices = ['device 1', 'device 2'] diff --git a/tests/testcases/test_event_producer.py b/tests/testcases/test_event_producer.py index 9dd518d4..85f84371 100644 --- a/tests/testcases/test_event_producer.py +++ b/tests/testcases/test_event_producer.py @@ -30,7 +30,7 @@ from keymapper.mapping import Mapping from keymapper.dev.event_producer import EventProducer, MOUSE, WHEEL from tests.test import InputDevice, UInput, MAX_ABS, clear_write_history, \ - uinput_write_history, cleanup, new_event + uinput_write_history, quick_cleanup, new_event abs_state = [0, 0, 0, 0] @@ -55,7 +55,7 @@ class TestEventProducer(unittest.TestCase): config.set('gamepad.joystick.y_scroll_speed', 1) def tearDown(self): - cleanup() + quick_cleanup() def test_debounce_1(self): loop = asyncio.get_event_loop() diff --git a/tests/testcases/test_injector.py b/tests/testcases/test_injector.py index 510bbf93..d605a7b0 100644 --- a/tests/testcases/test_injector.py +++ b/tests/testcases/test_injector.py @@ -41,7 +41,7 @@ from keymapper.getdevices import get_devices, is_gamepad from tests.test import new_event, pending_events, fixtures, \ EVENT_READ_TIMEOUT, uinput_write_history_pipe, \ - MAX_ABS, cleanup, read_write_history_pipe, InputDevice + MAX_ABS, quick_cleanup, read_write_history_pipe, InputDevice original_smeab = utils.should_map_event_as_btn @@ -75,7 +75,7 @@ class TestInjector(unittest.TestCase): self.injector = None evdev.InputDevice.grab = self.grab - cleanup() + quick_cleanup() def test_grab(self): # path is from the fixtures @@ -827,7 +827,7 @@ class TestModifyCapabilities(unittest.TestCase): self.assertNotIn(DISABLE_CODE, keys) def tearDown(self): - cleanup() + quick_cleanup() def test_modify_capabilities(self): self.injector = Injector('foo', self.mapping) diff --git a/tests/testcases/test_keycode_mapper.py b/tests/testcases/test_keycode_mapper.py index 9cc2cd9f..f15a2c39 100644 --- a/tests/testcases/test_keycode_mapper.py +++ b/tests/testcases/test_keycode_mapper.py @@ -34,7 +34,7 @@ from keymapper.config import config, BUTTONS from keymapper.mapping import Mapping, DISABLE_CODE from tests.test import new_event, UInput, uinput_write_history, \ - cleanup, InputDevice, MAX_ABS + quick_cleanup, InputDevice, MAX_ABS def wait(func, timeout=1.0): @@ -84,7 +84,7 @@ class TestKeycodeMapper(unittest.TestCase): self.assertFalse(macro.is_holding()) self.assertFalse(macro.running) - cleanup() + quick_cleanup() def test_subsets(self): a = subsets(((1,), (2,), (3,))) diff --git a/tests/testcases/test_macros.py b/tests/testcases/test_macros.py index 1656e84b..eff79620 100644 --- a/tests/testcases/test_macros.py +++ b/tests/testcases/test_macros.py @@ -24,11 +24,13 @@ import unittest import asyncio from keymapper.dev.macros import parse, _Macro, _extract_params, \ - is_this_a_macro, _parse_recurse + is_this_a_macro, _parse_recurse, handle_plus_syntax from keymapper.config import config from keymapper.mapping import Mapping from keymapper.state import system_mapping +from tests.test import quick_cleanup + class TestMacros(unittest.TestCase): def setUp(self): @@ -39,6 +41,7 @@ class TestMacros(unittest.TestCase): def tearDown(self): self.result = [] self.mapping.clear_config() + quick_cleanup() def handler(self, code, value): """Where macros should write codes to.""" @@ -55,6 +58,58 @@ class TestMacros(unittest.TestCase): self.assertFalse(is_this_a_macro('minus')) self.assertFalse(is_this_a_macro('k')) + self.assertTrue(is_this_a_macro('a+b')) + self.assertTrue(is_this_a_macro('a+b+c')) + self.assertTrue(is_this_a_macro('a + b')) + self.assertTrue(is_this_a_macro('a + b + c')) + + def test_handle_plus_syntax(self): + self.assertEqual(handle_plus_syntax('a + b'), 'm(a,m(b,h()))') + self.assertEqual(handle_plus_syntax('a + b + c'), 'm(a,m(b,m(c,h())))') + self.assertEqual(handle_plus_syntax(' a+b+c '), 'm(a,m(b,m(c,h())))') + + # invalid + self.assertEqual(handle_plus_syntax('+'), '+') + self.assertEqual(handle_plus_syntax('a+'), 'a+') + self.assertEqual(handle_plus_syntax('+b'), '+b') + self.assertEqual(handle_plus_syntax('k(a + b)'), 'k(a + b)') + self.assertEqual(handle_plus_syntax('a'), 'a') + self.assertEqual(handle_plus_syntax('k(a)'), 'k(a)') + self.assertEqual(handle_plus_syntax(''), '') + + def test_run_plus_syntax(self): + macro = parse('a + b + c + d', self.mapping) + macro.set_handler(self.handler) + self.assertSetEqual(macro.get_capabilities(), { + system_mapping.get('a'), + system_mapping.get('b'), + system_mapping.get('c'), + system_mapping.get('d') + }) + + macro.press_key() + asyncio.ensure_future(macro.run()) + self.loop.run_until_complete(asyncio.sleep(0.2)) + self.assertTrue(macro.is_holding()) + print(self.mapping.get('macros.keystroke_sleep_ms')) + print(self.result) + + # starting from the left, presses each one down + self.assertEqual(self.result[0], (system_mapping.get('a'), 1)) + self.assertEqual(self.result[1], (system_mapping.get('b'), 1)) + self.assertEqual(self.result[2], (system_mapping.get('c'), 1)) + self.assertEqual(self.result[3], (system_mapping.get('d'), 1)) + + # and then releases starting with the previously pressed key + macro.release_key() + self.loop.run_until_complete(asyncio.sleep(0.2)) + self.assertFalse(macro.is_holding()) + print(self.result) + self.assertEqual(self.result[4], (system_mapping.get('d'), 0)) + self.assertEqual(self.result[5], (system_mapping.get('c'), 0)) + self.assertEqual(self.result[6], (system_mapping.get('b'), 0)) + self.assertEqual(self.result[7], (system_mapping.get('a'), 0)) + def test_extract_params(self): def expect(raw, expectation): self.assertListEqual(_extract_params(raw), expectation) diff --git a/tests/testcases/test_mapping.py b/tests/testcases/test_mapping.py index 318a0e28..b3e4e82a 100644 --- a/tests/testcases/test_mapping.py +++ b/tests/testcases/test_mapping.py @@ -31,12 +31,12 @@ from keymapper.config import config from keymapper.paths import get_preset_path from keymapper.key import Key -from tests.test import tmp, cleanup +from tests.test import tmp, quick_cleanup class TestSystemMapping(unittest.TestCase): def tearDown(self): - cleanup() + quick_cleanup() def test_update(self): system_mapping = SystemMapping() @@ -113,7 +113,7 @@ class TestMapping(unittest.TestCase): self.assertFalse(self.mapping.changed) def tearDown(self): - cleanup() + quick_cleanup() def test_config(self): self.mapping.save(get_preset_path('foo', 'bar2')) diff --git a/tests/testcases/test_paths.py b/tests/testcases/test_paths.py index f6d226cb..4a355822 100644 --- a/tests/testcases/test_paths.py +++ b/tests/testcases/test_paths.py @@ -25,7 +25,7 @@ import unittest from keymapper.paths import get_user, touch, mkdir, \ get_preset_path, get_config_path -from tests.test import cleanup, tmp +from tests.test import quick_cleanup, tmp original_getlogin = os.getlogin() @@ -37,7 +37,7 @@ def _raise(error): class TestPaths(unittest.TestCase): def tearDown(self): - cleanup() + quick_cleanup() os.getlogin = original_getlogin def test_get_user(self): diff --git a/tests/testcases/test_reader.py b/tests/testcases/test_reader.py index a66c217e..d312b5ec 100644 --- a/tests/testcases/test_reader.py +++ b/tests/testcases/test_reader.py @@ -34,7 +34,7 @@ from keymapper.config import BUTTONS, MOUSE from keymapper.key import Key from tests.test import new_event, pending_events, EVENT_READ_TIMEOUT, \ - cleanup, MAX_ABS + quick_cleanup, MAX_ABS CODE_1 = 100 @@ -59,7 +59,7 @@ class TestReader(unittest.TestCase): self.assertEqual(keycode_reader.read(), None) def tearDown(self): - cleanup() + quick_cleanup() def test_will_report_up(self): self.assertFalse(will_report_up(EV_REL))