def test_hold_3(self): # test irregular input patterns code_a = 100 code_b = 101 code_c = 102 system_mapping.clear() system_mapping._set('a', code_a) system_mapping._set('b', code_b) system_mapping._set('c', code_c) macro_mapping = { ((EV_KEY, 1, 1),): parse('k(a).h(k(b)).k(c)', self.mapping), } history = [] def handler(*args): history.append(args) context = Context(self.mapping) context.macros = macro_mapping keycode_mapper = KeycodeMapper(context, self.source, None) keycode_mapper.macro_write = handler keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 1)) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.sleep(0.1)) for _ in range(5): self.assertTrue(active_macros[(EV_KEY, 1)].is_holding()) self.assertTrue(active_macros[(EV_KEY, 1)].running) keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 1)) loop.run_until_complete(asyncio.sleep(0.05)) # duplicate key down events don't do anything self.assertEqual(history.count((EV_KEY, code_a, 1)), 1) self.assertEqual(history.count((EV_KEY, code_a, 0)), 1) self.assertEqual(history.count((EV_KEY, code_c, 1)), 0) self.assertEqual(history.count((EV_KEY, code_c, 0)), 0) # stop keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 0)) loop.run_until_complete(asyncio.sleep(0.1)) self.assertEqual(history.count((EV_KEY, code_a, 1)), 1) self.assertEqual(history.count((EV_KEY, code_a, 0)), 1) self.assertEqual(history.count((EV_KEY, code_c, 1)), 1) self.assertEqual(history.count((EV_KEY, code_c, 0)), 1) self.assertFalse(active_macros[(EV_KEY, 1)].is_holding()) self.assertFalse(active_macros[(EV_KEY, 1)].running) # it's stopped and won't write stuff anymore count_before = len(history) loop.run_until_complete(asyncio.sleep(0.1)) count_after = len(history) self.assertEqual(count_before, count_after)
def test_two_d_pad_macros(self): # executing two macros that stop automatically at the same time code_1 = 61 code_2 = 62 system_mapping.clear() system_mapping._set('1', code_1) system_mapping._set('2', code_2) # try two concurrent macros with D-Pad events because they are # more difficult to manage, since their only difference is their # value, and one of them is negative. right = (EV_ABS, ABS_HAT0X, 1) release = (EV_ABS, ABS_HAT0X, 0) left = (EV_ABS, ABS_HAT0X, -1) repeats = 10 macro_mapping = { (right,): parse(f'r({repeats}, k(1))', self.mapping), (left,): parse(f'r({repeats}, k(2))', self.mapping) } history = [] def handler(*args): history.append(args) context = Context(self.mapping) context.macros = macro_mapping keycode_mapper = KeycodeMapper(context, self.source, None) keycode_mapper.macro_write = handler keycode_mapper.macro_write = handler keycode_mapper.handle_keycode(new_event(*right)) self.assertIn((EV_ABS, ABS_HAT0X), unreleased) keycode_mapper.handle_keycode(new_event(*release)) self.assertNotIn((EV_ABS, ABS_HAT0X), unreleased) keycode_mapper.handle_keycode(new_event(*left)) self.assertIn((EV_ABS, ABS_HAT0X), unreleased) loop = asyncio.get_event_loop() sleeptime = config.get('macros.keystroke_sleep_ms') / 1000 loop.run_until_complete(asyncio.sleep(1.1 * repeats * 2 * sleeptime)) self.assertEqual(history.count((EV_KEY, code_1, 1)), 10) self.assertEqual(history.count((EV_KEY, code_1, 0)), 10) self.assertEqual(history.count((EV_KEY, code_2, 1)), 10) self.assertEqual(history.count((EV_KEY, code_2, 0)), 10) self.assertEqual(len(history), repeats * 4)
def test_handle_keycode_macro(self): history = [] code_a = 100 code_b = 101 system_mapping.clear() system_mapping._set('a', code_a) system_mapping._set('b', code_b) macro_mapping = { ((EV_KEY, 1, 1),): parse('k(a)', self.mapping), ((EV_KEY, 2, 1),): parse('r(5, k(b))', self.mapping) } context = Context(self.mapping) context.macros = macro_mapping keycode_mapper = KeycodeMapper(context, self.source, None) keycode_mapper.macro_write = lambda *args: history.append(args) keycode_mapper.macro_write = lambda *args: history.append(args) keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 1)) keycode_mapper.handle_keycode(new_event(EV_KEY, 2, 1)) loop = asyncio.get_event_loop() sleeptime = config.get('macros.keystroke_sleep_ms', 10) * 12 # let the mainloop run for some time so that the macro does its stuff loop.run_until_complete(asyncio.sleep(sleeptime / 1000 + 0.1)) # 6 keycodes written, with down and up events self.assertEqual(len(history), 12) self.assertIn((EV_KEY, code_a, 1), history) self.assertIn((EV_KEY, code_a, 0), history) self.assertIn((EV_KEY, code_b, 1), history) self.assertIn((EV_KEY, code_b, 0), history) # releasing stuff self.assertIn((EV_KEY, 1), unreleased) self.assertIn((EV_KEY, 2), unreleased) keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 0)) keycode_mapper.handle_keycode(new_event(EV_KEY, 2, 0)) self.assertNotIn((EV_KEY, 1), unreleased) self.assertNotIn((EV_KEY, 2), unreleased) loop.run_until_complete(asyncio.sleep(0.1)) self.assertEqual(len(history), 12)
def test_macro_writes_to_context_uinput(self): macro_mapping = { ((EV_KEY, 1, 1),): parse('k(a)', self.mapping) } context = Context(self.mapping) context.macros = macro_mapping context.uinput = UInput() forward_to = UInput() keycode_mapper = KeycodeMapper(context, self.source, forward_to) keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 1)) loop = asyncio.get_event_loop() sleeptime = config.get('macros.keystroke_sleep_ms', 10) * 12 loop.run_until_complete(asyncio.sleep(sleeptime / 1000 + 0.1)) self.assertEqual(context.uinput.write_count, 2) # down and up self.assertEqual(forward_to.write_count, 0) keycode_mapper.handle_keycode(new_event(EV_KEY, 2, 1)) self.assertEqual(forward_to.write_count, 1)
def test_hold_two(self): # holding two macros at the same time, # the first one is triggered by a combination history = [] code_1 = 100 code_2 = 101 code_3 = 102 code_a = 103 code_b = 104 code_c = 105 system_mapping.clear() system_mapping._set('1', code_1) system_mapping._set('2', code_2) system_mapping._set('3', code_3) system_mapping._set('a', code_a) system_mapping._set('b', code_b) system_mapping._set('c', code_c) key_0 = (EV_KEY, 10) key_1 = (EV_KEY, 11) key_2 = (EV_ABS, ABS_HAT0X) down_0 = (*key_0, 1) down_1 = (*key_1, 1) down_2 = (*key_2, -1) up_0 = (*key_0, 0) up_1 = (*key_1, 0) up_2 = (*key_2, 0) macro_mapping = { (down_0, down_1): parse('k(1).h(k(2)).k(3)', self.mapping), (down_2,): parse('k(a).h(k(b)).k(c)', self.mapping) } def handler(*args): history.append(args) loop = asyncio.get_event_loop() context = Context(self.mapping) context.macros = macro_mapping uinput_1 = UInput() context.uinput = uinput_1 keycode_mapper = KeycodeMapper(context, self.source, uinput_1) keycode_mapper.macro_write = handler # key up won't do anything keycode_mapper.handle_keycode(new_event(*up_0)) keycode_mapper.handle_keycode(new_event(*up_1)) keycode_mapper.handle_keycode(new_event(*up_2)) loop.run_until_complete(asyncio.sleep(0.1)) self.assertEqual(len(active_macros), 0) """start macros""" uinput_2 = UInput() context.uinput = uinput_2 keycode_mapper = KeycodeMapper(context, self.source, uinput_2) keycode_mapper.macro_write = handler keycode_mapper.handle_keycode(new_event(*down_0)) self.assertEqual(uinput_2.write_count, 1) keycode_mapper.handle_keycode(new_event(*down_1)) keycode_mapper.handle_keycode(new_event(*down_2)) self.assertEqual(uinput_2.write_count, 1) # let the mainloop run for some time so that the macro does its stuff sleeptime = 500 keystroke_sleep = config.get('macros.keystroke_sleep_ms', 10) loop.run_until_complete(asyncio.sleep(sleeptime / 1000)) self.assertEqual(len(active_macros), 2) self.assertTrue(active_macros[key_1].is_holding()) self.assertTrue(active_macros[key_1].running) self.assertTrue(active_macros[key_2].is_holding()) self.assertTrue(active_macros[key_2].running) self.assertIn(down_0[:2], unreleased) self.assertIn(down_1[:2], unreleased) self.assertIn(down_2[:2], unreleased) """stop macros""" keycode_mapper = KeycodeMapper(context, self.source, None) # releasing the last key of a combination releases the whole macro keycode_mapper.handle_keycode(new_event(*up_1)) keycode_mapper.handle_keycode(new_event(*up_2)) self.assertIn(down_0[:2], unreleased) self.assertNotIn(down_1[:2], unreleased) self.assertNotIn(down_2[:2], unreleased) loop.run_until_complete(asyncio.sleep(keystroke_sleep * 10 / 1000)) self.assertFalse(active_macros[key_1].is_holding()) self.assertFalse(active_macros[key_1].running) self.assertFalse(active_macros[key_2].is_holding()) self.assertFalse(active_macros[key_2].running) events = calculate_event_number(sleeptime, 1, 1) * 2 self.assertGreater(len(history), events * 0.9) self.assertLess(len(history), events * 1.1) self.assertIn((EV_KEY, code_a, 1), history) self.assertIn((EV_KEY, code_a, 0), history) self.assertIn((EV_KEY, code_b, 1), history) self.assertIn((EV_KEY, code_b, 0), history) self.assertIn((EV_KEY, code_c, 1), history) self.assertIn((EV_KEY, code_c, 0), history) self.assertIn((EV_KEY, code_1, 1), history) self.assertIn((EV_KEY, code_1, 0), history) self.assertIn((EV_KEY, code_2, 1), history) self.assertIn((EV_KEY, code_2, 0), history) self.assertIn((EV_KEY, code_3, 1), history) self.assertIn((EV_KEY, code_3, 0), history) self.assertGreater(history.count((EV_KEY, code_b, 1)), 1) self.assertGreater(history.count((EV_KEY, code_b, 0)), 1) self.assertGreater(history.count((EV_KEY, code_2, 1)), 1) self.assertGreater(history.count((EV_KEY, code_2, 0)), 1) # it's stopped and won't write stuff anymore count_before = len(history) loop.run_until_complete(asyncio.sleep(0.2)) count_after = len(history) self.assertEqual(count_before, count_after)
def test_hold_2(self): # test irregular input patterns code_a = 100 code_b = 101 code_c = 102 code_d = 103 system_mapping.clear() system_mapping._set('a', code_a) system_mapping._set('b', code_b) system_mapping._set('c', code_c) system_mapping._set('d', code_d) macro_mapping = { ((EV_KEY, 1, 1),): parse('h(k(b))', self.mapping), ((EV_KEY, 2, 1),): parse('k(c).r(1, r(1, r(1, h(k(a))))).k(d)', self.mapping), ((EV_KEY, 3, 1),): parse('h(k(b))', self.mapping) } history = [] def handler(*args): history.append(args) context = Context(self.mapping) context.macros = macro_mapping keycode_mapper = KeycodeMapper(context, self.source, None) keycode_mapper.macro_write = handler keycode_mapper.macro_write = handler keycode_mapper.macro_write = handler """start macro 2""" keycode_mapper.handle_keycode(new_event(EV_KEY, 2, 1)) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.sleep(0.1)) # starting code_c written self.assertEqual(history.count((EV_KEY, code_c, 1)), 1) self.assertEqual(history.count((EV_KEY, code_c, 0)), 1) # spam garbage events for _ in range(5): keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 1)) keycode_mapper.handle_keycode(new_event(EV_KEY, 3, 1)) loop.run_until_complete(asyncio.sleep(0.05)) self.assertTrue(active_macros[(EV_KEY, 1)].is_holding()) self.assertTrue(active_macros[(EV_KEY, 1)].running) self.assertTrue(active_macros[(EV_KEY, 2)].is_holding()) self.assertTrue(active_macros[(EV_KEY, 2)].running) self.assertTrue(active_macros[(EV_KEY, 3)].is_holding()) self.assertTrue(active_macros[(EV_KEY, 3)].running) # there should only be one code_c in the events, because no key # up event was ever done so the hold just continued self.assertEqual(history.count((EV_KEY, code_c, 1)), 1) self.assertEqual(history.count((EV_KEY, code_c, 0)), 1) # without an key up event on 2, it won't write code_d self.assertNotIn((code_d, 1), history) self.assertNotIn((code_d, 0), history) # stop macro 2 keycode_mapper.handle_keycode(new_event(EV_KEY, 2, 0)) loop.run_until_complete(asyncio.sleep(0.1)) # it stopped and didn't restart, so the count stays at 1 self.assertEqual(history.count((EV_KEY, code_c, 1)), 1) self.assertEqual(history.count((EV_KEY, code_c, 0)), 1) # and the trailing d was written self.assertEqual(history.count((EV_KEY, code_d, 1)), 1) self.assertEqual(history.count((EV_KEY, code_d, 0)), 1) # it's stopped and won't write stuff anymore count_before = history.count((EV_KEY, code_a, 1)) self.assertGreater(count_before, 1) loop.run_until_complete(asyncio.sleep(0.1)) count_after = history.count((EV_KEY, code_a, 1)) self.assertEqual(count_before, count_after) """restart macro 2""" history = [] keycode_mapper.handle_keycode(new_event(EV_KEY, 2, 1)) loop.run_until_complete(asyncio.sleep(0.1)) self.assertEqual(history.count((EV_KEY, code_c, 1)), 1) self.assertEqual(history.count((EV_KEY, code_c, 0)), 1) # spam garbage events again, this time key-up events on all other # macros for _ in range(5): keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 0)) keycode_mapper.handle_keycode(new_event(EV_KEY, 3, 0)) loop.run_until_complete(asyncio.sleep(0.05)) self.assertFalse(active_macros[(EV_KEY, 1)].is_holding()) self.assertFalse(active_macros[(EV_KEY, 1)].running) self.assertTrue(active_macros[(EV_KEY, 2)].is_holding()) self.assertTrue(active_macros[(EV_KEY, 2)].running) self.assertFalse(active_macros[(EV_KEY, 3)].is_holding()) self.assertFalse(active_macros[(EV_KEY, 3)].running) # stop macro 2 keycode_mapper.handle_keycode(new_event(EV_KEY, 2, 0)) loop.run_until_complete(asyncio.sleep(0.1)) # was started only once self.assertEqual(history.count((EV_KEY, code_c, 1)), 1) self.assertEqual(history.count((EV_KEY, code_c, 0)), 1) # and the trailing d was also written only once self.assertEqual(history.count((EV_KEY, code_d, 1)), 1) self.assertEqual(history.count((EV_KEY, code_d, 0)), 1) # stop all macros keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 0)) keycode_mapper.handle_keycode(new_event(EV_KEY, 3, 0)) loop.run_until_complete(asyncio.sleep(0.1)) # it's stopped and won't write stuff anymore count_before = len(history) loop.run_until_complete(asyncio.sleep(0.1)) count_after = len(history) self.assertEqual(count_before, count_after) self.assertFalse(active_macros[(EV_KEY, 1)].is_holding()) self.assertFalse(active_macros[(EV_KEY, 1)].running) self.assertFalse(active_macros[(EV_KEY, 2)].is_holding()) self.assertFalse(active_macros[(EV_KEY, 2)].running) self.assertFalse(active_macros[(EV_KEY, 3)].is_holding()) self.assertFalse(active_macros[(EV_KEY, 3)].running)
def test_hold(self): history = [] code_a = 100 code_b = 101 code_c = 102 system_mapping.clear() system_mapping._set('a', code_a) system_mapping._set('b', code_b) system_mapping._set('c', code_c) macro_mapping = { ((EV_KEY, 1, 1),): parse('k(a).h(k(b)).k(c)', self.mapping) } def handler(*args): history.append(args) context = Context(self.mapping) context.macros = macro_mapping keycode_mapper = KeycodeMapper(context, self.source, None) keycode_mapper.macro_write = handler """start macro""" keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 1)) loop = asyncio.get_event_loop() # let the mainloop run for some time so that the macro does its stuff sleeptime = 500 keystroke_sleep = config.get('macros.keystroke_sleep_ms', 10) loop.run_until_complete(asyncio.sleep(sleeptime / 1000)) self.assertTrue(active_macros[(EV_KEY, 1)].is_holding()) self.assertTrue(active_macros[(EV_KEY, 1)].running) """stop macro""" keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 0)) loop.run_until_complete(asyncio.sleep(keystroke_sleep * 10 / 1000)) events = calculate_event_number(sleeptime, 1, 1) self.assertGreater(len(history), events * 0.9) self.assertLess(len(history), events * 1.1) self.assertIn((EV_KEY, code_a, 1), history) self.assertIn((EV_KEY, code_a, 0), history) self.assertIn((EV_KEY, code_b, 1), history) self.assertIn((EV_KEY, code_b, 0), history) self.assertIn((EV_KEY, code_c, 1), history) self.assertIn((EV_KEY, code_c, 0), history) self.assertGreater(history.count((EV_KEY, code_b, 1)), 1) self.assertGreater(history.count((EV_KEY, code_b, 0)), 1) # it's stopped and won't write stuff anymore count_before = len(history) loop.run_until_complete(asyncio.sleep(0.2)) count_after = len(history) self.assertEqual(count_before, count_after) self.assertFalse(active_macros[(EV_KEY, 1)].is_holding()) self.assertFalse(active_macros[(EV_KEY, 1)].running)
def test_combination_keycode_macro_mix(self): # ev_1 triggers macro, ev_1 + ev_2 triggers key while the macro is # still running system_mapping.clear() system_mapping._set('a', 92) down_1 = (EV_ABS, ABS_HAT1X, 1) down_2 = (EV_ABS, ABS_HAT1Y, -1) up_1 = (EV_ABS, ABS_HAT1X, 0) up_2 = (EV_ABS, ABS_HAT1Y, 0) macro_mapping = {(down_1,): parse('h(k(a))', self.mapping)} _key_to_code = {(down_1, down_2): 91} macro_history = [] def handler(*args): # handler prevents uinput_write_history form growing macro_history.append(args) uinput = UInput() forward_to = UInput() loop = asyncio.get_event_loop() context = Context(self.mapping) context.uinput = uinput context.key_to_code = _key_to_code context.macros = macro_mapping keycode_mapper = KeycodeMapper(context, self.source, forward_to) keycode_mapper.macro_write = handler # macro starts keycode_mapper.handle_keycode(new_event(*down_1)) loop.run_until_complete(asyncio.sleep(0.05)) self.assertEqual(len(uinput_write_history), 0) self.assertGreater(len(macro_history), 1) self.assertIn(down_1[:2], unreleased) self.assertIn((EV_KEY, 92, 1), macro_history) # combination triggered keycode_mapper.handle_keycode(new_event(*down_2)) self.assertIn(down_1[:2], unreleased) self.assertIn(down_2[:2], unreleased) self.assertEqual(uinput_write_history[0].t, (EV_KEY, 91, 1)) len_a = len(macro_history) loop.run_until_complete(asyncio.sleep(0.05)) len_b = len(macro_history) # still running self.assertGreater(len_b, len_a) # release keycode_mapper.handle_keycode(new_event(*up_1)) self.assertNotIn(down_1[:2], unreleased) self.assertIn(down_2[:2], unreleased) loop.run_until_complete(asyncio.sleep(0.05)) len_c = len(macro_history) loop.run_until_complete(asyncio.sleep(0.05)) len_d = len(macro_history) # not running anymore self.assertEqual(len_c, len_d) keycode_mapper.handle_keycode(new_event(*up_2)) self.assertEqual(uinput_write_history[1].t, (EV_KEY, 91, 0)) self.assertEqual(len(uinput_write_history), 2) self.assertNotIn(down_1[:2], unreleased) self.assertNotIn(down_2[:2], unreleased)