properly reads keycode device for devices that are being injected into

pull/14/head
sezanzeb 4 years ago
parent 2afde0039f
commit 06a10c64b4

@ -35,8 +35,7 @@ CONFIG_PATH = os.path.join(CONFIG, 'config')
# an empty config with basic expected substructures
INITIAL_CONFIG = {
'autoload': {},
'map_EV_REL_devices': True
'autoload': {}
}
@ -53,25 +52,6 @@ class _Config:
"""get tuples of (device, preset)."""
return self._config['autoload'].items()
def set_modify_movement_devices(self, active):
"""Set if devices that control movements should also be mapped.
This causes many movements event to be passed through python code,
and if this ever seems to affect the responsiveness of mouse movements,
it can be disabled. This is just an optional precaution. Disabling this
may make mapping some keys of the device impossible.
"""
self._config['map_EV_REL_devices'] = active
def may_modify_movement_devices(self):
"""Get if devices that control movements may be modified as well.
Since movement events happen quite often and fast, I'd like to
add the option to disabling mapping those if it affects their
performance. TODO figure out which devices to inject to instead?
"""
return self._config['map_EV_REL_devices']
def load_config(self):
"""Load the config from the file system."""
if not os.path.exists(CONFIG_PATH):

@ -64,24 +64,16 @@ class _GetDevicesProcess(multiprocessing.Process):
# "Logitech USB Keyboard" and "Logitech USB Keyboard Consumer Control"
grouped = {}
for device in devices:
if device.phys.startswith('key-mapper'):
# injector device, not really periphery
continue
# only keyboard devices
# https://www.kernel.org/doc/html/latest/input/event-codes.html
capabilities = device.capabilities().keys()
if evdev.ecodes.EV_KEY not in capabilities:
continue
if (
not config.may_modify_movement_devices()
and evdev.ecodes.EV_REL in capabilities
):
# TODO add checkbox to automatically load
# a preset on login
logger.debug(
'Skipping %s to avoid impairing mouse movement',
device.path
)
continue
usb = device.phys.split('/')[0]
if grouped.get(usb) is None:
grouped[usb] = []
@ -117,7 +109,7 @@ def refresh_devices():
return get_devices()
def get_devices(include_keymapper=False):
def get_devices():
"""Group devices and get relevant infos per group.
Returns a list containing mappings of
@ -128,6 +120,10 @@ def get_devices(include_keymapper=False):
paths is a list of files in /dev/input that belong to the devices.
They are grouped by usb port.
Since this needs to do some stuff with /dev and spawn processes the
result is cached. Use refresh_devices if you need up to date
devices.
"""
global _devices
if _devices is None:
@ -141,13 +137,4 @@ def get_devices(include_keymapper=False):
names = [f'"{name}"' for name in _devices]
logger.info('Found %s', ', '.join(names))
# filter the result
result = {}
for device in _devices.keys():
if include_keymapper and device.startswith('key-mapper'):
result[device] = _devices[device]
continue
result[device] = _devices[device]
return result
return _devices

@ -226,6 +226,9 @@ class Window:
CTX_APPLY,
f'Applied the system default'
)
# restart reading because after injecting the device landscape
# changes a bit
keycode_reader.start_reading(self.selected_device)
def on_save_preset_clicked(self, button):
"""Save changes to a preset to the file system."""
@ -281,6 +284,10 @@ class Window:
f'Could not grab device "{self.selected_device}"'
)
# restart reading because after injecting the device landscape
# changes a bit
keycode_reader.start_reading(self.selected_device)
def on_select_device(self, dropdown):
"""List all presets, create one if none exist yet."""
if dropdown.get_active_id() == self.selected_device:

@ -264,9 +264,6 @@ class KeycodeInjector:
if len(self.processes) == 0:
raise OSError('Could not grab any device')
# key-mapper devices were added, freshly scan /dev/input
refresh_devices()
@ensure_numlock
def stop_injecting(self):
"""Stop injecting keycodes."""
@ -278,5 +275,3 @@ class KeycodeInjector:
if process.is_alive():
process.terminate()
self.processes[i] = None
refresh_devices()

@ -25,7 +25,7 @@
import evdev
from keymapper.logger import logger
from keymapper.getdevices import get_devices
from keymapper.getdevices import get_devices, refresh_devices
class _KeycodeReader:
@ -50,25 +50,22 @@ class _KeycodeReader:
If read is called without prior start_reading, no keycodes
will be available.
Parameters
----------
device : string
The name of the device.
"""
groups = get_devices(include_keymapper=True)
for name, group in groups.items():
# make sure this sees up to date devices
refresh_devices()
self.virtual_devices = []
for name, group in get_devices().items():
# also find stuff like "key-mapper {device}"
if device not in name:
return
paths = group['paths']
continue
# Watch over each one of the potentially multiple devices per
# hardware
self.virtual_devices = [
self.virtual_devices += [
evdev.InputDevice(path)
for path in paths
for path in group['paths']
]
logger.debug(

@ -48,7 +48,7 @@ fixtures = {
'name': 'device 1 foo'
},
'/dev/input/event10': {
'capabilities': {evdev.ecodes.EV_KEY: []},
'capabilities': {evdev.ecodes.EV_KEY: list(evdev.ecodes.keys.keys())},
'phys': 'usb-0000:03:00.0-1/input3',
'name': 'device 1'
},
@ -65,7 +65,7 @@ fixtures = {
# device 2
'/dev/input/event20': {
'capabilities': {evdev.ecodes.EV_KEY: []},
'capabilities': {evdev.ecodes.EV_KEY: list(evdev.ecodes.keys.keys())},
'phys': 'usb-0000:03:00.0-2/input1',
'name': 'device 2'
},
@ -77,10 +77,10 @@ fixtures = {
'name': 'device 3'
},
# key-mapper devices are also ignored, another instance of key-mapper
# key-mapper devices are also ignored, some instance of key-mapper
# started injecting apparently.
'/dev/input/event40': {
'capabilities': {evdev.ecodes.EV_KEY: []},
'capabilities': {evdev.ecodes.EV_KEY: list(evdev.ecodes.keys.keys())},
'phys': 'key-mapper/input1',
'name': 'key-mapper device 2'
},
@ -170,6 +170,7 @@ def patch_evdev():
class UInput:
def __init__(self, *args, **kwargs):
self.fd = 0
self.device = InputDevice('/dev/input/event40')
pass
def write(self, type, code, value):

@ -48,11 +48,9 @@ class TestConfig(unittest.TestCase):
def test_save_load(self):
config.set_autoload_preset('d1', 'a')
config.set_autoload_preset('d2', 'b')
config.set_modify_movement_devices(True)
config.save_config()
# ignored after load
config.set_modify_movement_devices(False)
config.set_autoload_preset('d3', 'c')
config.load_config()
@ -60,7 +58,6 @@ class TestConfig(unittest.TestCase):
list(config.iterate_autoload_presets()),
[('d1', 'a'), ('d2', 'b')]
)
self.assertTrue(config.may_modify_movement_devices())
if __name__ == "__main__":

@ -22,7 +22,6 @@
import unittest
from keymapper.getdevices import _GetDevicesProcess
from keymapper.config import config
class FakePipe:
@ -57,29 +56,6 @@ class TestGetDevices(unittest.TestCase):
}
})
def test_map_movement_devices(self):
pipe = FakePipe()
config.set_modify_movement_devices(False)
_GetDevicesProcess(pipe).run()
self.assertDictEqual(pipe.devices, {
'device 1': {
'paths': [
'/dev/input/event11',
'/dev/input/event10',
'/dev/input/event13'
],
'devices': [
'device 1 foo',
'device 1',
'device 1'
]
},
'device 2': {
'paths': ['/dev/input/event20'],
'devices': ['device 2']
}
})
if __name__ == "__main__":
unittest.main()

Loading…
Cancel
Save