pull/14/head
sezanzeb 4 years ago
parent 17445558fb
commit 3d2095f988

@ -63,11 +63,11 @@ class _Config:
if len(chunks) == 0:
# child is the value _resolve is looking for
return func(parent, child, chunk)
else:
# child is another object
if child is None:
parent[chunk] = {}
child = parent[chunk]
# child is another object
if child is None:
parent[chunk] = {}
child = parent[chunk]
def remove(self, path):
"""Remove a config key.
@ -104,8 +104,12 @@ class _Config:
----------
path : string
For example 'macros.keystroke_sleep_ms'
default : any
If the configured value is not available or None, return this
instead
"""
return self._resolve(path, lambda parent, child, chunk: child)
resolved = self._resolve(path, lambda parent, child, chunk: child)
return resolved if resolved is not None else default
def set_autoload_preset(self, device, preset):
"""Set a preset to be automatically applied on start.

@ -22,6 +22,7 @@
"""Get stuff from /usr/share/key-mapper, depending on the prefix."""
import sys
import os
import site
import pkg_resources
@ -39,7 +40,7 @@ def get_data_path(filename=''):
data_path = '/usr/share/key-mapper'
if not os.path.exists(data_path):
logger.error('key-mapper data was not properly installed')
raise SystemExit(1)
sys.exit(1)
return os.path.join('/usr/share/key-mapper', filename)
# depending on where this file is installed to, make sure to use the proper

@ -110,6 +110,12 @@ class KeycodeInjector:
self._process = None
self._msg_pipe = multiprocessing.Pipe()
# some EV_ABS mapping stuff
self.abs_x = 0
self.abs_y = 0
self.pending_x_rel = 0
self.pending_y_rel = 0
def start_injecting(self):
"""Start injecting keycodes."""
self._process = multiprocessing.Process(target=self._start_injecting)
@ -136,8 +142,8 @@ class KeycodeInjector:
needed = True
break
map_ABS = self.map_ABS(device)
if map_ABS:
map_ev_abs = self.map_ev_abs(device)
if map_ev_abs:
needed = True
if not needed:
@ -168,20 +174,20 @@ class KeycodeInjector:
time.sleep(0.15)
return device, map_ABS
return device, map_ev_abs
def map_ABS(self, device):
def map_ev_abs(self, device):
# TODO offer configuration via the UI if a gamepad is elected
capabilities = device.capabilities(absinfo=False)
return evdev.ecodes.ABS_X in capabilities.get(EV_ABS, [])
def _modify_capabilities(self, input_device, map_ABS):
def _modify_capabilities(self, input_device, map_ev_abs):
"""Adds all keycode into a copy of a devices capabilities.
Prameters
---------
input_device : evdev.InputDevice
map_ABS : bool
map_ev_abs : bool
if ABS capabilities should be removed in favor of REL
"""
ecodes = evdev.ecodes
@ -199,7 +205,7 @@ class KeycodeInjector:
if keycode is not None:
capabilities[ecodes.EV_KEY].append(keycode - KEYCODE_OFFSET)
if map_ABS:
if map_ev_abs:
del capabilities[ecodes.EV_ABS]
capabilities[ecodes.EV_REL] = [
evdev.ecodes.REL_X,
@ -246,7 +252,7 @@ class KeycodeInjector:
# Watch over each one of the potentially multiple devices per hardware
for path in paths:
input_device, map_ABS = self._prepare_device(path)
input_device, map_ev_abs = self._prepare_device(path)
if input_device is None:
continue
@ -256,17 +262,17 @@ class KeycodeInjector:
uinput = evdev.UInput(
name=f'{DEV_NAME} {self.device}',
phys=DEV_NAME,
events=self._modify_capabilities(input_device, map_ABS)
events=self._modify_capabilities(input_device, map_ev_abs)
)
# TODO separate file
# keycode injection
coroutine = self._keycode_loop(input_device, uinput, map_ABS)
coroutine = self._keycode_loop(input_device, uinput, map_ev_abs)
coroutines.append(coroutine)
# TODO separate file
# mouse movement injection
if map_ABS:
if map_ev_abs:
self.abs_x = 0
self.abs_y = 0
# events only take ints, so a movement of 0.3 needs to add
@ -291,9 +297,9 @@ class KeycodeInjector:
if len(coroutines) > 0:
logger.debug('asyncio coroutines ended')
def _write(self, device, type, keycode, value):
def _write(self, device, ev_type, keycode, value):
"""Actually inject."""
device.write(type, keycode, value)
device.write(ev_type, keycode, value)
device.syn()
def _macro_write(self, character, value, keymapper_device):
@ -360,7 +366,7 @@ class KeycodeInjector:
rel_x
)
async def _keycode_loop(self, device, keymapper_device, map_ABS):
async def _keycode_loop(self, device, keymapper_device, map_ev_abs):
"""Inject keycodes for one of the virtual devices.
Parameters
@ -369,8 +375,8 @@ class KeycodeInjector:
where to read keycodes from
keymapper_device : evdev.UInput
where to write keycodes to
map_ABS : bool
the value of map_ABS() for the original device
map_ev_abs : bool
the value of map_ev_abs() for the original device
"""
# Parse all macros beforehand
logger.debug('Parsing macros')
@ -389,7 +395,7 @@ class KeycodeInjector:
)
async for event in device.async_read_loop():
if map_ABS and event.type == EV_ABS:
if map_ev_abs and event.type == EV_ABS:
if event.code not in [evdev.ecodes.ABS_X, evdev.ecodes.ABS_Y]:
continue
if event.code == evdev.ecodes.ABS_X:

@ -189,7 +189,7 @@ def _count_brackets(macro):
if brackets != 0:
raise Exception(f'There are {brackets} closing brackets missing')
return brackets, position
return position
def _parse_recurse(macro, handler, macro_instance=None, depth=0):
@ -239,7 +239,7 @@ def _parse_recurse(macro, handler, macro_instance=None, depth=0):
raise Exception(f'Unknown function {call}')
# get all the stuff inbetween
brackets, position = _count_brackets(macro)
position = _count_brackets(macro)
inner = macro[2:position - 1]

@ -22,7 +22,6 @@
"""To check if access to devices in /dev is possible."""
import os
import grp
import getpass

@ -22,10 +22,12 @@
"""Keeps reading keycodes in the background for the UI to use."""
import evdev
import sys
import select
import multiprocessing
import evdev
from keymapper.logger import logger
from keymapper.getdevices import get_devices, refresh_devices
from keymapper.state import KEYCODE_OFFSET
@ -104,7 +106,7 @@ class _KeycodeReader:
# value: 1 for down, 0 for up, 2 for hold.
if self._pipe[1].closed:
logger.debug('Pipe closed, reader stops.')
exit(0)
sys.exit(0)
if event.type == evdev.ecodes.EV_KEY and event.value == 1:
logger.spam(

@ -28,15 +28,14 @@ import shutil
from keymapper.logger import logger
# try to find the user who called sudo
try:
USER = os.getlogin()
USER = os.getlogin()
except OSError:
# failed in some ubuntu installations
USER = os.environ['USER']
if USER == 'root':
USER = os.envron.get('SUDO_USER', USER)
# failed in some ubuntu installations
USER = os.environ['USER']
if USER == 'root':
USER = os.envron.get('SUDO_USER', USER)
CONFIG = os.path.join('/home', USER, '.config/key-mapper')

@ -9,13 +9,13 @@
</mask>
<g mask="url(#a)">
<path fill="#555" d="M0 0h63v20H0z"/>
<path fill="#97CA00" d="M63 0h36v20H63z"/>
<path fill="#a4a61d" d="M63 0h36v20H63z"/>
<path fill="url(#b)" d="M0 0h99v20H0z"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
<text x="31.5" y="14">coverage</text>
<text x="80" y="15" fill="#010101" fill-opacity=".3">90%</text>
<text x="80" y="14">90%</text>
<text x="80" y="15" fill="#010101" fill-opacity=".3">76%</text>
<text x="80" y="14">76%</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 904 B

After

Width:  |  Height:  |  Size: 904 B

@ -17,7 +17,7 @@
<text x="22.0" y="14">pylint</text>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="63.0" y="15" fill="#010101" fill-opacity=".3">9.83</text>
<text x="62.0" y="14">9.83</text>
<text x="63.0" y="15" fill="#010101" fill-opacity=".3">9.71</text>
<text x="62.0" y="14">9.71</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -2,7 +2,7 @@
coverage_badge() {
# https://github.com/dbrgn/coverage-badge
coverage run --branch --source=/usr/lib/python3.8/site-packages/keymapper tests/test.py
coverage run tests/test.py
python3 -m coverage_badge > readme/coverage.svg
coverage combine
coverage report -m

@ -31,6 +31,9 @@ class TestConfig(unittest.TestCase):
config.save_config()
def test_basic(self):
self.assertEqual(config.get('a'), None)
self.assertEqual(config.get('a', 'foo'), 'foo')
config.set('a', 1)
self.assertEqual(config.get('a'), 1)

@ -84,7 +84,7 @@ class TestInjector(unittest.TestCase):
fake_device = FakeDevice()
capabilities = self.injector._modify_capabilities(
fake_device,
map_ABS=False
map_ev_abs=False
)
self.assertIn(EV_KEY, capabilities)
@ -102,8 +102,8 @@ class TestInjector(unittest.TestCase):
path = '/dev/input/event10'
# this test needs to pass around all other constraints of
# _prepare_device
device, map_ABS = self.injector._prepare_device(path)
self.assertFalse(map_ABS)
device, map_ev_abs = self.injector._prepare_device(path)
self.assertFalse(map_ev_abs)
self.assertEqual(self.failed, 2)
# success on the third try
device.name = fixtures[path]['name']
@ -112,10 +112,10 @@ class TestInjector(unittest.TestCase):
self.injector = KeycodeInjector('gamepad', custom_mapping)
path = '/dev/input/event30'
device, map_ABS = self.injector._prepare_device(path)
self.assertTrue(map_ABS)
device, map_ev_abs = self.injector._prepare_device(path)
self.assertTrue(map_ev_abs)
capabilities = self.injector._modify_capabilities(device, map_ABS)
capabilities = self.injector._modify_capabilities(device, map_ev_abs)
self.assertNotIn(evdev.ecodes.EV_ABS, capabilities)
self.assertIn(evdev.ecodes.EV_REL, capabilities)
@ -124,8 +124,8 @@ class TestInjector(unittest.TestCase):
custom_mapping.change(10, 'a')
self.injector = KeycodeInjector('device 1', custom_mapping)
path = '/dev/input/event11'
device, map_ABS = self.injector._prepare_device(path)
self.assertFalse(map_ABS)
device, map_ev_abs = self.injector._prepare_device(path)
self.assertFalse(map_ev_abs)
self.assertEqual(self.failed, 0)
self.assertIsNone(device)
@ -163,7 +163,7 @@ class TestInjector(unittest.TestCase):
def test_abs_to_rel(self):
# maps gamepad joystick events to mouse events
# TODO enable this somewhere so that map_ABS returns true
# TODO enable this somewhere so that map_ev_abs returns true
# in the .json file of the mapping.
config.set('gamepad.non_linearity', 1)
pointer_speed = 80

Loading…
Cancel
Save