def test_gamepad_purpose_none_2(self): # forward abs joystick events for the left joystick only custom_mapping.set('gamepad.joystick.left_purpose', NONE) config.set('gamepad.joystick.right_purpose', MOUSE) self.injector = Injector(groups.find(name='gamepad'), custom_mapping) self.injector.context = Context(custom_mapping) path = '/dev/input/event30' device = self.injector._grab_device(path) # the right joystick maps as mouse, so it is grabbed # even with an empty mapping self.assertIsNotNone(device) gamepad = classify(device) == GAMEPAD self.assertTrue(gamepad) capabilities = self.injector._construct_capabilities(gamepad) self.assertNotIn(EV_ABS, capabilities) self.assertIn(EV_REL, capabilities) custom_mapping.change(Key(EV_KEY, BTN_A, 1), 'a') device = self.injector._grab_device(path) gamepad = classify(device) == GAMEPAD self.assertIsNotNone(device) self.assertTrue(gamepad) capabilities = self.injector._construct_capabilities(gamepad) self.assertNotIn(EV_ABS, capabilities) self.assertIn(EV_REL, capabilities) self.assertIn(EV_KEY, capabilities)
def test_abs_to_rel(self): # maps gamepad joystick events to mouse events config.set('gamepad.joystick.non_linearity', 1) pointer_speed = 80 config.set('gamepad.joystick.pointer_speed', pointer_speed) rel_x = evdev.ecodes.REL_X rel_y = evdev.ecodes.REL_Y # they need to sum up before something is written divisor = 10 x = MAX_ABS / pointer_speed / divisor y = MAX_ABS / pointer_speed / divisor pending_events['gamepad'] = [ InputEvent(EV_ABS, rel_x, x), InputEvent(EV_ABS, rel_y, y), InputEvent(EV_ABS, rel_x, -x), InputEvent(EV_ABS, rel_y, -y), ] self.injector = KeycodeInjector('gamepad', custom_mapping) self.injector.start_injecting() # wait for the injector to start sending, at most 1s uinput_write_history_pipe[0].poll(1) # wait a bit more for it to sum up sleep = 0.5 time.sleep(sleep) # convert the write history to some easier to manage list history = [] while uinput_write_history_pipe[0].poll(): event = uinput_write_history_pipe[0].recv() history.append((event.type, event.code, event.value)) if history[0][0] == EV_ABS: raise AssertionError( 'The injector probably just forwarded them unchanged') # movement is written at 60hz and it takes `divisor` steps to # move 1px. take it times 2 for both x and y events. self.assertGreater(len(history), 60 * sleep * 0.9 * 2 / divisor) self.assertLess(len(history), 60 * sleep * 1.1 * 2 / divisor) # those may be in arbitrary order, the injector happens to write # y first self.assertEqual(history[-1][0], EV_REL) self.assertEqual(history[-1][1], rel_x) self.assertAlmostEqual(history[-1][2], -1) self.assertEqual(history[-2][0], EV_REL) self.assertEqual(history[-2][1], rel_y) self.assertAlmostEqual(history[-2][2], -1)
def setUp(self): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) self.mapping = Mapping() device = InputDevice('/dev/input/event30') uinput = UInput() asyncio.ensure_future( ev_abs_mapper(abs_state, device, uinput, self.mapping)) config.set('gamepad.joystick.x_scroll_speed', 1) config.set('gamepad.joystick.y_scroll_speed', 1)
def test_construct_capabilities_buttons_buttons(self): self.mapping.change(Key(EV_KEY, 60, 1), self.macro.code) # those settings shouldn't have an effect with gamepad=False config.set('gamepad.joystick.left_purpose', BUTTONS) self.mapping.set('gamepad.joystick.right_purpose', BUTTONS) self.injector = Injector(groups.find(name='foo'), self.mapping) self.injector.context = Context(self.mapping) capabilities = self.injector._construct_capabilities(gamepad=False) self.check_keys(capabilities) self.assertNotIn(EV_ABS, capabilities) self.assertNotIn(EV_REL, capabilities)
def test_joystick_purpose_4(self): config.set('gamepad.joystick.left_purpose', WHEEL) config.set('gamepad.joystick.right_purpose', WHEEL) self.mapping.set('gamepad.joystick.x_scroll_speed', 2) self.mapping.set('gamepad.joystick.y_scroll_speed', 3) self.do(MAX_ABS, 0, 0, 0, (EV_REL, REL_HWHEEL, 2)) self.do(-MAX_ABS, 0, 0, 0, (EV_REL, REL_HWHEEL, -2)) self.do(0, MAX_ABS, 0, 0, (EV_REL, REL_WHEEL, -3)) self.do(0, -MAX_ABS, 0, 0, (EV_REL, REL_WHEEL, 3)) # vertical wheel event values are negative self.do(0, 0, MAX_ABS, 0, (EV_REL, REL_HWHEEL, 2)) self.do(0, 0, -MAX_ABS, 0, (EV_REL, REL_HWHEEL, -2)) self.do(0, 0, 0, MAX_ABS, (EV_REL, REL_WHEEL, -3)) self.do(0, 0, 0, -MAX_ABS, (EV_REL, REL_WHEEL, 3))
def test_joystick_purpose_3(self): speed = 40 self.mapping.set('gamepad.joystick.non_linearity', 1) config.set('gamepad.joystick.pointer_speed', speed) self.mapping.set('gamepad.joystick.left_purpose', MOUSE) config.set('gamepad.joystick.right_purpose', MOUSE) self.do(MAX_ABS, 0, 0, 0, (EV_REL, REL_X, speed)) self.do(-MAX_ABS, 0, 0, 0, (EV_REL, REL_X, -speed)) self.do(0, MAX_ABS, 0, 0, (EV_REL, REL_Y, speed)) self.do(0, -MAX_ABS, 0, 0, (EV_REL, REL_Y, -speed)) self.do(0, 0, MAX_ABS, 0, (EV_REL, REL_X, speed)) self.do(0, 0, -MAX_ABS, 0, (EV_REL, REL_X, -speed)) self.do(0, 0, 0, MAX_ABS, (EV_REL, REL_Y, speed)) self.do(0, 0, 0, -MAX_ABS, (EV_REL, REL_Y, -speed))
def test_construct_capabilities_gamepad_none_none(self): self.mapping.change(Key(EV_KEY, 60, 1), self.macro.code) config.set('gamepad.joystick.left_purpose', NONE) self.mapping.set('gamepad.joystick.right_purpose', NONE) self.injector = Injector(groups.find(name='foo'), self.mapping) self.injector.context = Context(self.mapping) self.assertFalse(self.injector.context.maps_joystick()) self.assertFalse(self.injector.context.joystick_as_mouse()) self.assertFalse(self.injector.context.joystick_as_dpad()) capabilities = self.injector._construct_capabilities(gamepad=True) self.assertNotIn(EV_ABS, capabilities) self.check_keys(capabilities)
def setUp(self): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) self.mapping = Mapping() self.context = Context(self.mapping) uinput = UInput() self.context.uinput = uinput device = InputDevice('/dev/input/event30') self.event_producer = EventProducer(self.context) self.event_producer.set_abs_range_from(device) asyncio.ensure_future(self.event_producer.run()) config.set('gamepad.joystick.x_scroll_speed', 1) config.set('gamepad.joystick.y_scroll_speed', 1)
def test_construct_capabilities_gamepad_buttons_buttons(self): self.mapping.change(Key((EV_KEY, 60, 1)), self.macro.code) config.set('gamepad.joystick.left_purpose', BUTTONS) self.mapping.set('gamepad.joystick.right_purpose', BUTTONS) self.injector = Injector('foo', self.mapping) self.injector.context = Context(self.mapping) self.assertTrue(self.injector.context.maps_joystick()) self.assertFalse(self.injector.context.joystick_as_mouse()) self.assertTrue(self.injector.context.joystick_as_dpad()) capabilities = self.injector._construct_capabilities(gamepad=True) self.check_keys(capabilities) self.assertNotIn(EV_ABS, capabilities) self.assertNotIn(EV_REL, capabilities)
def test_gamepad_purpose_none(self): # forward abs joystick events custom_mapping.set('gamepad.joystick.left_purpose', NONE) config.set('gamepad.joystick.right_purpose', NONE) self.injector = Injector(groups.find(name='gamepad'), custom_mapping) self.injector.context = Context(custom_mapping) path = '/dev/input/event30' device = self.injector._grab_device(path) self.assertIsNone(device) # no capability is used, so it won't grab custom_mapping.change(Key(EV_KEY, BTN_A, 1), 'a') device = self.injector._grab_device(path) self.assertIsNotNone(device) gamepad = classify(device) == GAMEPAD self.assertTrue(gamepad) capabilities = self.injector._construct_capabilities(gamepad) self.assertNotIn(EV_ABS, capabilities)
def test_keystroke_sleep_config(self): # global config as fallback config.set('macros.keystroke_sleep_ms', 100) start = time.time() macro = parse('k(a).k(b)', self.mapping) self.loop.run_until_complete(macro.run(self.handler)) delta = time.time() - start # is currently over 400, k(b) adds another sleep afterwards # that doesn't do anything self.assertGreater(delta, 0.300) # now set the value in the mapping, which is prioritized self.mapping.set('macros.keystroke_sleep_ms', 50) start = time.time() macro = parse('k(a).k(b)', self.mapping) self.loop.run_until_complete(macro.run(self.handler)) delta = time.time() - start self.assertGreater(delta, 0.150) self.assertLess(delta, 0.300)
def test_construct_capabilities_gamepad(self): self.mapping.change(Key((EV_KEY, 60, 1)), self.macro.code) config.set('gamepad.joystick.left_purpose', MOUSE) self.mapping.set('gamepad.joystick.right_purpose', WHEEL) self.injector = Injector(groups.find(name='foo'), self.mapping) self.injector.context = Context(self.mapping) self.assertTrue(self.injector.context.maps_joystick()) self.assertTrue(self.injector.context.joystick_as_mouse()) self.assertFalse(self.injector.context.joystick_as_dpad()) capabilities = self.injector._construct_capabilities(gamepad=True) self.assertNotIn(EV_ABS, capabilities) self.check_keys(capabilities) keys = capabilities[EV_KEY] # now that it is told that it is a gamepad, btn_left is inserted # to ensure the operating system interprets it as mouse. self.assertIn(self.left, keys)
def test_gamepad_config(self): # select a device that is not a gamepad self.window.on_select_device(FakeDropdown('device 1')) self.assertFalse(self.window.get('gamepad_config').is_visible()) self.assertFalse(custom_mapping.changed) # select a gamepad self.window.on_select_device(FakeDropdown('gamepad')) self.assertTrue(self.window.get('gamepad_config').is_visible()) self.assertFalse(custom_mapping.changed) # set stuff self.window.get('left_joystick_purpose').set_active_id(WHEEL) self.window.get('right_joystick_purpose').set_active_id(WHEEL) joystick_mouse_speed = 5 self.window.get('joystick_mouse_speed').set_value(joystick_mouse_speed) # it should be stored in custom_mapping, which overwrites the # global config config.set('gamepad.joystick.left_purpose', MOUSE) config.set('gamepad.joystick.right_purpose', MOUSE) config.set('gamepad.joystick.pointer_speed', 50) self.assertTrue(custom_mapping.changed) left_purpose = custom_mapping.get('gamepad.joystick.left_purpose') right_purpose = custom_mapping.get('gamepad.joystick.right_purpose') pointer_speed = custom_mapping.get('gamepad.joystick.pointer_speed') self.assertEqual(left_purpose, WHEEL) self.assertEqual(right_purpose, WHEEL) self.assertEqual(pointer_speed, 2**joystick_mouse_speed) # select a device that is not a gamepad again self.window.on_select_device(FakeDropdown('device 1')) self.assertFalse(self.window.get('gamepad_config').is_visible()) self.assertFalse(custom_mapping.changed)
def test_gamepad_to_mouse(self): # maps gamepad joystick events to mouse events config.set('gamepad.joystick.non_linearity', 1) pointer_speed = 80 config.set('gamepad.joystick.pointer_speed', pointer_speed) config.set('gamepad.joystick.left_purpose', MOUSE) # they need to sum up before something is written divisor = 10 x = MAX_ABS / pointer_speed / divisor y = MAX_ABS / pointer_speed / divisor push_events('gamepad', [ new_event(EV_ABS, ABS_X, x), new_event(EV_ABS, ABS_Y, y), new_event(EV_ABS, ABS_X, -x), new_event(EV_ABS, ABS_Y, -y), ]) self.injector = Injector(groups.find(name='gamepad'), custom_mapping) self.injector.start() # wait for the injector to start sending, at most 1s uinput_write_history_pipe[0].poll(1) # wait a bit more for it to sum up sleep = 0.5 time.sleep(sleep) # convert the write history to some easier to manage list history = read_write_history_pipe() if history[0][0] == EV_ABS: raise AssertionError( 'The injector probably just forwarded them unchanged' # possibly in addition to writing mouse events ) # movement is written at 60hz and it takes `divisor` steps to # move 1px. take it times 2 for both x and y events. self.assertGreater(len(history), 60 * sleep * 0.9 * 2 / divisor) self.assertLess(len(history), 60 * sleep * 1.1 * 2 / divisor) # those may be in arbitrary order count_x = history.count((EV_REL, REL_X, -1)) count_y = history.count((EV_REL, REL_Y, -1)) self.assertGreater(count_x, 1) self.assertGreater(count_y, 1) # only those two types of events were written self.assertEqual(len(history), count_x + count_y)
def test_basic(self): self.assertEqual(config.get('a'), None) config.set('a', 1) self.assertEqual(config.get('a'), 1) config.remove('a') config.set('a.b', 2) self.assertEqual(config.get('a.b'), 2) self.assertEqual(config._config['a']['b'], 2) config.remove('a.b') config.set('a.b.c', 3) self.assertEqual(config.get('a.b.c'), 3) self.assertEqual(config._config['a']['b']['c'], 3)
def test_should_map_event_as_btn(self): device = InputDevice('/dev/input/event30') mapping = Mapping() # the function name is so horribly long do = utils.should_map_event_as_btn """D-Pad""" self.assertTrue(do(device, InputEvent(EV_ABS, ABS_HAT0X, 1), mapping)) self.assertTrue(do(device, InputEvent(EV_ABS, ABS_HAT0X, -1), mapping)) """Mouse movements""" self.assertFalse(do(device, InputEvent(EV_REL, REL_WHEEL, 1), mapping)) self.assertFalse(do(device, InputEvent(EV_REL, REL_WHEEL, -1), mapping)) self.assertFalse(do(device, InputEvent(EV_REL, REL_HWHEEL, 1), mapping)) self.assertFalse( do(device, InputEvent(EV_REL, REL_HWHEEL, -1), mapping)) self.assertFalse(do(device, InputEvent(EV_REL, REL_X, -1), mapping)) """regular keys and buttons""" self.assertTrue(do(device, InputEvent(EV_KEY, KEY_A, 1), mapping)) self.assertTrue(do(device, InputEvent(EV_ABS, ABS_HAT0X, -1), mapping)) """mousepad events""" self.assertFalse( do(device, InputEvent(EV_ABS, ecodes.ABS_MT_SLOT, 1), mapping)) self.assertFalse( do(device, InputEvent(EV_ABS, ecodes.ABS_MT_TOOL_Y, 1), mapping)) self.assertFalse( do(device, InputEvent(EV_ABS, ecodes.ABS_MT_POSITION_X, 1), mapping)) """joysticks""" self.assertFalse( do(device, InputEvent(EV_ABS, ecodes.ABS_RX, 1234), mapping)) self.assertFalse( do(device, InputEvent(EV_ABS, ecodes.ABS_Y, -1), mapping)) mapping.set('gamepad.joystick.left_purpose', BUTTONS) event = InputEvent(EV_ABS, ecodes.ABS_RX, MAX_ABS) self.assertFalse(do(device, event, mapping)) self.assertEqual(event.value, MAX_ABS) event = InputEvent(EV_ABS, ecodes.ABS_Y, -MAX_ABS) self.assertTrue(do(device, event, mapping)) self.assertEqual(event.value, -1) event = InputEvent(EV_ABS, ecodes.ABS_X, -MAX_ABS / 4) self.assertTrue(do(device, event, mapping)) self.assertEqual(event.value, 0) config.set('gamepad.joystick.right_purpose', BUTTONS) event = InputEvent(EV_ABS, ecodes.ABS_RX, MAX_ABS) self.assertTrue(do(device, event, mapping)) self.assertEqual(event.value, 1) event = InputEvent(EV_ABS, ecodes.ABS_Y, MAX_ABS) self.assertTrue(do(device, event, mapping)) self.assertEqual(event.value, 1) event = InputEvent(EV_ABS, ecodes.ABS_X, MAX_ABS / 4) self.assertTrue(do(device, event, mapping)) self.assertEqual(event.value, 0)
def test_joystick_purpose_2(self): speed = 30 config.set('gamepad.joystick.non_linearity', 1) config.set('gamepad.joystick.pointer_speed', speed) config.set('gamepad.joystick.left_purpose', WHEEL) config.set('gamepad.joystick.right_purpose', MOUSE) config.set('gamepad.joystick.x_scroll_speed', 1) config.set('gamepad.joystick.y_scroll_speed', 2) # vertical wheel event values are negative self.do(MAX_ABS, 0, 0, 0, (EV_REL, REL_HWHEEL, 1)) self.do(-MAX_ABS, 0, 0, 0, (EV_REL, REL_HWHEEL, -1)) self.do(0, MAX_ABS, 0, 0, (EV_REL, REL_WHEEL, -2)) self.do(0, -MAX_ABS, 0, 0, (EV_REL, REL_WHEEL, 2)) self.do(0, 0, MAX_ABS, 0, (EV_REL, REL_X, speed)) self.do(0, 0, -MAX_ABS, 0, (EV_REL, REL_X, -speed)) self.do(0, 0, 0, MAX_ABS, (EV_REL, REL_Y, speed)) self.do(0, 0, 0, -MAX_ABS, (EV_REL, REL_Y, -speed))
def test_get_default(self): config._config = {} self.assertEqual(config.get('gamepad.joystick.non_linearity'), 4) config.set('gamepad.joystick.non_linearity', 3) self.assertEqual(config.get('gamepad.joystick.non_linearity'), 3)
def test_should_map_as_btn(self): mapping = Mapping() def do(gamepad, event): return utils.should_map_as_btn(event, mapping, gamepad) """D-Pad""" self.assertTrue(do(1, new_event(EV_ABS, ABS_HAT0X, 1))) self.assertTrue(do(0, new_event(EV_ABS, ABS_HAT0X, -1))) """Mouse movements""" self.assertTrue(do(1, new_event(EV_REL, REL_WHEEL, 1))) self.assertTrue(do(0, new_event(EV_REL, REL_WHEEL, -1))) self.assertTrue(do(1, new_event(EV_REL, REL_HWHEEL, 1))) self.assertTrue(do(0, new_event(EV_REL, REL_HWHEEL, -1))) self.assertFalse(do(1, new_event(EV_REL, REL_X, -1))) """regular keys and buttons""" self.assertTrue(do(1, new_event(EV_KEY, KEY_A, 1))) self.assertTrue(do(0, new_event(EV_KEY, KEY_A, 1))) self.assertTrue(do(1, new_event(EV_ABS, ABS_HAT0X, -1))) self.assertTrue(do(0, new_event(EV_ABS, ABS_HAT0X, -1))) """mousepad events""" self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_MT_SLOT, 1))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_MT_SLOT, 1))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_MT_TOOL_Y, 1))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_MT_TOOL_Y, 1))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_MT_POSITION_X, 1))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_MT_POSITION_X, 1))) self.assertFalse(do(1, new_event(EV_KEY, ecodes.BTN_TOUCH, 1))) self.assertFalse(do(0, new_event(EV_KEY, ecodes.BTN_TOUCH, 1))) """stylus movements""" self.assertFalse(do(0, new_event(EV_KEY, ecodes.BTN_DIGI, 1))) self.assertFalse(do(1, new_event(EV_KEY, ecodes.BTN_DIGI, 1))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_TILT_X, 1))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_TILT_X, 1))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_TILT_Y, 1))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_TILT_Y, 1))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_DISTANCE, 1))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_DISTANCE, 1))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_PRESSURE, 1))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_PRESSURE, 1))) """joysticks""" # without a purpose of BUTTONS it won't map any button, even for # gamepads self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_RX, 1234))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_RX, 1234))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_Y, -1))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_Y, -1))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_RY, -1))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_RY, -1))) mapping.set('gamepad.joystick.right_purpose', BUTTONS) config.set('gamepad.joystick.left_purpose', BUTTONS) # but only for gamepads self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_Y, -1))) self.assertTrue(do(1, new_event(EV_ABS, ecodes.ABS_Y, -1))) self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_RY, -1))) self.assertTrue(do(1, new_event(EV_ABS, ecodes.ABS_RY, -1))) """weird events""" self.assertFalse(do(0, new_event(EV_ABS, ecodes.ABS_MISC, -1))) self.assertFalse(do(1, new_event(EV_ABS, ecodes.ABS_MISC, -1)))
def test_fallback(self): config.set('d.e.f', 5) self.assertEqual(self.mapping.get('d.e.f'), 5) self.mapping.set('d.e.f', 3) self.assertEqual(self.mapping.get('d.e.f'), 3)