#46 written key combination didn't release

xkb
sezanzeb 4 years ago committed by sezanzeb
parent 441a7c44ab
commit 017aa9ab43

@ -93,9 +93,8 @@ class Injector(multiprocessing.Process):
self._event_producer = None
self._state = UNKNOWN
self._msg_pipe = multiprocessing.Pipe()
self.context = Context(mapping)
self.mapping = mapping
self.context = None # only needed inside the injection process
super().__init__()
"""Functions to interact with the running process"""
@ -314,6 +313,10 @@ class Injector(multiprocessing.Process):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# create this within the process after the event loop creation,
# so that the macros use the correct loop
self.context = Context(self.mapping)
self._event_producer = EventProducer(self.context)
numlock_state = is_numlock_on()

@ -151,10 +151,15 @@ class _Macro:
# wait until the key is released. Only then it will be
# able to acquire the lock. Release it right after so that
# it can be acquired by press_key again.
await self._holding_lock.acquire()
self._holding_lock.release()
# this seems to be much more efficient on the CPU than
# looping `await asyncio.sleep(0.001)`
try:
await self._holding_lock.acquire()
self._holding_lock.release()
except RuntimeError as error:
# The specific bug in question has been fixed already,
# but lets keep this check here for the future. Not
# catching errors here causes the macro to never be
# released
logger.error('Failed h(): %s', error)
self.tasks.append((1234, task))
else:

@ -343,6 +343,7 @@ class TestDaemon(unittest.TestCase):
self.assertTrue(daemon.autoload_history.may_autoload(device, preset))
# start
config.save_config()
daemon.set_config_dir(get_config_path())
daemon.start_injecting(path, preset)
# explicit start, not autoload, so the history stays empty
@ -350,10 +351,6 @@ class TestDaemon(unittest.TestCase):
self.assertTrue(daemon.autoload_history.may_autoload(device, preset))
# path got translated to the device name
self.assertIn(device, daemon.injectors)
# after passing device and preset, the correct preset is read
# from the path
injector = daemon.injectors[device]
self.assertEqual(injector.context.mapping.get_character(Key(3, 2, 1)), 'a')
# start again
previous_injector = daemon.injectors[device]
@ -366,8 +363,6 @@ class TestDaemon(unittest.TestCase):
# a different injetor is now running
self.assertNotEqual(previous_injector, daemon.injectors[device])
self.assertNotEqual(daemon.injectors[device].get_state(), STOPPED)
injector = daemon.injectors[device]
self.assertEqual(injector.context.mapping.get_character(Key(3, 2, 1)), 'a')
# trying to inject a non existing preset keeps the previous inejction
# alive

@ -26,7 +26,7 @@ import copy
import evdev
from evdev.ecodes import EV_REL, EV_KEY, EV_ABS, ABS_HAT0X, BTN_LEFT, KEY_A, \
REL_X, REL_Y, REL_WHEEL, REL_HWHEEL, BTN_A, ABS_X, ABS_Y, \
ABS_Z, ABS_RZ, ABS_VOLUME, KEY_B
ABS_Z, ABS_RZ, ABS_VOLUME, KEY_B, KEY_C
from keymapper.injection.injector import Injector, is_in_capabilities, \
STARTING, RUNNING, STOPPED, NO_GRAB, UNKNOWN
@ -37,6 +37,7 @@ from keymapper.mapping import Mapping, DISABLE_CODE, DISABLE_NAME
from keymapper.config import config, NONE, MOUSE, WHEEL, BUTTONS
from keymapper.key import Key
from keymapper.injection.macros import parse
from keymapper.injection.context import Context
from keymapper import utils
from keymapper.getdevices import get_devices, is_gamepad
@ -86,6 +87,7 @@ class TestInjector(unittest.TestCase):
path = '/dev/input/event10'
# this test needs to pass around all other constraints of
# _grab_device
self.injector.context = Context(custom_mapping)
device = self.injector._grab_device(path)
gamepad = is_gamepad(device)
self.assertFalse(gamepad)
@ -99,6 +101,7 @@ class TestInjector(unittest.TestCase):
self.injector = Injector('device 1', custom_mapping)
path = '/dev/input/event10'
self.injector.context = Context(custom_mapping)
device = self.injector._grab_device(path)
self.assertIsNone(device)
self.assertGreaterEqual(self.failed, 1)
@ -116,6 +119,7 @@ class TestInjector(unittest.TestCase):
# according to the fixtures, /dev/input/event30 can do ABS_HAT0X
custom_mapping.change(Key(EV_ABS, ABS_HAT0X, 1), 'a')
self.injector = Injector('foobar', custom_mapping)
self.injector.context = Context(custom_mapping)
_grab_device = self.injector._grab_device
self.assertIsNone(_grab_device('/dev/input/event10'))
@ -124,12 +128,14 @@ class TestInjector(unittest.TestCase):
def test_grab_device_non_existing(self):
custom_mapping.change(Key(EV_ABS, ABS_HAT0X, 1), 'a')
self.injector = Injector('foobar', custom_mapping)
self.injector.context = Context(custom_mapping)
_grab_device = self.injector._grab_device
self.assertIsNone(_grab_device('/dev/input/event1234'))
def test_gamepad_capabilities(self):
self.injector = Injector('gamepad', custom_mapping)
self.injector.context = Context(custom_mapping)
path = '/dev/input/event30'
device = self.injector._grab_device(path)
@ -155,6 +161,7 @@ class TestInjector(unittest.TestCase):
config.set('gamepad.joystick.right_purpose', NONE)
self.injector = Injector('gamepad', custom_mapping)
self.injector.context = Context(custom_mapping)
path = '/dev/input/event30'
device = self.injector._grab_device(path)
@ -174,6 +181,7 @@ class TestInjector(unittest.TestCase):
config.set('gamepad.joystick.right_purpose', MOUSE)
self.injector = Injector('gamepad', custom_mapping)
self.injector.context = Context(custom_mapping)
path = '/dev/input/event30'
device = self.injector._grab_device(path)
@ -201,6 +209,7 @@ class TestInjector(unittest.TestCase):
# be able to control the mouse. it probably wants the mouse click.
custom_mapping.change(Key(EV_KEY, BTN_A, 1), 'a')
self.injector = Injector('gamepad 2', custom_mapping)
self.injector.context = Context(custom_mapping)
"""ABS device without any key capability"""
@ -248,6 +257,7 @@ class TestInjector(unittest.TestCase):
# skips a device because its capabilities are not used in the mapping
custom_mapping.change(Key(EV_KEY, 10, 1), 'a')
self.injector = Injector('device 1', custom_mapping)
self.injector.context = Context(custom_mapping)
path = '/dev/input/event11'
device = self.injector._grab_device(path)
self.assertIsNone(device)
@ -256,6 +266,7 @@ class TestInjector(unittest.TestCase):
def test_skip_unknown_device(self):
# skips a device because its capabilities are not used in the mapping
self.injector = Injector('device 1', custom_mapping)
self.injector.context = Context(custom_mapping)
path = '/dev/input/event11'
device = self.injector._grab_device(path)
@ -408,9 +419,17 @@ class TestInjector(unittest.TestCase):
# so run won't block and just stop. all the stuff
# will be initialized though, so that stuff can be tested
self.injector.stop_injecting()
# the context serves no purpose in the main process
self.assertIsNone(self.injector.context)
self.injector.run()
# not in a process, so the event_producer state can be checked
self.assertEqual(self.injector._event_producer.max_abs, MAX_ABS)
self.assertEqual(
self.injector.context.mapping.get('gamepad.joystick.left_purpose'),
MOUSE
)
def test_gamepad_to_buttons_event_producer(self):
custom_mapping.set('gamepad.joystick.left_purpose', BUTTONS)
@ -431,12 +450,29 @@ class TestInjector(unittest.TestCase):
self.assertIsNone(self.injector._event_producer.max_abs)
def test_capabilities_and_uinput_presence(self):
custom_mapping.change(Key(EV_KEY, KEY_A, 1), 'a')
custom_mapping.change(Key(EV_KEY, KEY_A, 1), 'c')
custom_mapping.change(Key(EV_REL, REL_HWHEEL, 1), 'k(b)')
self.injector = Injector('device 1', custom_mapping)
self.injector.stop_injecting()
self.injector.run()
self.assertEqual(
self.injector.context.mapping.get_character(Key(EV_KEY, KEY_A, 1)),
'c'
)
self.assertEqual(
self.injector.context.key_to_code[((EV_KEY, KEY_A, 1),)],
KEY_C
)
self.assertEqual(
self.injector.context.mapping.get_character(Key(EV_REL, REL_HWHEEL, 1)),
'k(b)'
)
self.assertEqual(
self.injector.context.macros[((EV_REL, REL_HWHEEL, 1),)].code,
'k(b)'
)
self.assertListEqual(
sorted(uinputs.keys()),
sorted([
@ -459,7 +495,7 @@ class TestInjector(unittest.TestCase):
# puts the needed capabilities into the new key-mapper device
self.assertIn(EV_KEY, mapped.capabilities())
self.assertEqual(len(mapped.capabilities()[EV_KEY]), 2)
self.assertIn(KEY_A, mapped.capabilities()[EV_KEY])
self.assertIn(KEY_C, mapped.capabilities()[EV_KEY])
self.assertIn(KEY_B, mapped.capabilities()[EV_KEY])
# not a gamepad that maps joysticks to mouse movements
self.assertNotIn(EV_REL, mapped.capabilities())
@ -768,6 +804,7 @@ class TestInjector(unittest.TestCase):
system_mapping._set('b', 52)
injector = Injector('device 1', mapping)
injector.context = Context(mapping)
self.assertEqual(injector.context.key_to_code.get((ev_1,)), 51)
# permutations to make matching combinations easier
self.assertEqual(injector.context.key_to_code.get((ev_2, ev_3, ev_4)), 52)
@ -860,6 +897,7 @@ class TestModifyCapabilities(unittest.TestCase):
self.mapping.change(Key(EV_KEY, 60, 1), self.macro.code)
self.injector = Injector('foo', self.mapping)
self.injector.context = Context(self.mapping)
capabilities = self.injector._construct_capabilities(gamepad=False)
self.assertNotIn(EV_ABS, capabilities)
@ -903,6 +941,7 @@ class TestModifyCapabilities(unittest.TestCase):
self.mapping.set('gamepad.joystick.right_purpose', WHEEL)
self.injector = Injector('foo', self.mapping)
self.injector.context = Context(self.mapping)
self.assertFalse(self.injector.context.forwards_joystick())
self.assertTrue(self.injector.context.maps_joystick())
self.assertTrue(self.injector.context.joystick_as_mouse())
@ -924,6 +963,7 @@ class TestModifyCapabilities(unittest.TestCase):
self.mapping.set('gamepad.joystick.right_purpose', NONE)
self.injector = Injector('foo', self.mapping)
self.injector.context = Context(self.mapping)
self.assertTrue(self.injector.context.forwards_joystick())
self.assertFalse(self.injector.context.maps_joystick())
self.assertFalse(self.injector.context.joystick_as_mouse())
@ -940,6 +980,7 @@ class TestModifyCapabilities(unittest.TestCase):
self.mapping.set('gamepad.joystick.right_purpose', BUTTONS)
self.injector = Injector('foo', self.mapping)
self.injector.context = Context(self.mapping)
self.assertFalse(self.injector.context.forwards_joystick())
self.assertTrue(self.injector.context.maps_joystick())
self.assertFalse(self.injector.context.joystick_as_mouse())
@ -958,6 +999,7 @@ class TestModifyCapabilities(unittest.TestCase):
self.mapping.set('gamepad.joystick.right_purpose', BUTTONS)
self.injector = Injector('foo', self.mapping)
self.injector.context = Context(self.mapping)
capabilities = self.injector._construct_capabilities(gamepad=False)

Loading…
Cancel
Save