fixed injection

This commit is contained in:
sezanzeb 2020-12-02 17:40:21 +01:00
parent cdbb3c8b39
commit 386879752b
3 changed files with 106 additions and 11 deletions

View File

@ -321,6 +321,8 @@ class KeycodeInjector:
logger.debug('Parsing macros') logger.debug('Parsing macros')
macros = {} macros = {}
for keycode, output in self.mapping: for keycode, output in self.mapping:
keycode -= KEYCODE_OFFSET
if '(' in output and ')' in output and len(output) >= 4: if '(' in output and ')' in output and len(output) >= 4:
# probably a macro # probably a macro
macros[keycode] = parse( macros[keycode] = parse(
@ -332,7 +334,9 @@ class KeycodeInjector:
target_keycode = system_mapping.get(output) target_keycode = system_mapping.get(output)
if target_keycode is None: if target_keycode is None:
logger.error('Don\'t know what %s is', output) logger.error('Don\'t know what %s is', output)
return continue
code_code_mapping[keycode] = target_keycode - KEYCODE_OFFSET
logger.debug( logger.debug(
'Started injecting into %s, fd %s', 'Started injecting into %s, fd %s',

View File

@ -29,14 +29,31 @@ from keymapper.state import KEYCODE_OFFSET
def handle_keycode(code_code_mapping, macros, event, uinput): def handle_keycode(code_code_mapping, macros, event, uinput):
"""Write the mapped keycode.""" """Write the mapped keycode.
Parameters
----------
code_code_mapping : dict
mapping of linux-keycode to linux-keycode. No need to substract
anything before writing to the device.
macros : dict
mapping of linux-keycode to _Macro objects
"""
input_keycode = event.code input_keycode = event.code
# for logging purposes. It should log the same keycode as xev and gtk,
# which is also displayed in the UI.
xkb_keycode = input_keycode + KEYCODE_OFFSET
if input_keycode in macros: if input_keycode in macros:
if event.value != 1:
# only key-down events trigger macros
return
macro = macros[input_keycode] macro = macros[input_keycode]
logger.spam( logger.spam(
'got code:%s value:%s, maps to macro %s', 'got code:%s value:%s, maps to macro %s',
event.code + KEYCODE_OFFSET, xkb_keycode,
event.value, event.value,
macro.code macro.code
) )
@ -47,11 +64,16 @@ def handle_keycode(code_code_mapping, macros, event, uinput):
target_keycode = code_code_mapping[input_keycode] target_keycode = code_code_mapping[input_keycode]
logger.spam( logger.spam(
'got code:%s value:%s, maps to code:%s', 'got code:%s value:%s, maps to code:%s',
event.code + KEYCODE_OFFSET, xkb_keycode,
event.value, event.value,
target_keycode target_keycode + KEYCODE_OFFSET
) )
else: else:
logger.spam(
'got unmapped code:%s value:%s',
xkb_keycode,
event.value,
)
target_keycode = input_keycode target_keycode = input_keycode
uinput.write(event.type, target_keycode, event.value) uinput.write(event.type, target_keycode, event.value)

View File

@ -19,6 +19,7 @@
# along with key-mapper. If not, see <https://www.gnu.org/licenses/>. # along with key-mapper. If not, see <https://www.gnu.org/licenses/>.
import asyncio
import unittest import unittest
import time import time
@ -27,10 +28,12 @@ from evdev.ecodes import EV_REL, EV_KEY, EV_ABS
from keymapper.dev.injector import is_numlock_on, toggle_numlock,\ from keymapper.dev.injector import is_numlock_on, toggle_numlock,\
ensure_numlock, KeycodeInjector ensure_numlock, KeycodeInjector
from keymapper.dev.keycode_mapper import handle_keycode
from keymapper.state import custom_mapping, system_mapping, \ from keymapper.state import custom_mapping, system_mapping, \
clear_system_mapping, KEYCODE_OFFSET clear_system_mapping, KEYCODE_OFFSET
from keymapper.mapping import Mapping from keymapper.mapping import Mapping
from keymapper.config import config from keymapper.config import config
from keymapper.dev.macros import parse
from tests.test import uinput_write_history, Event, pending_events, fixtures, \ from tests.test import uinput_write_history, Event, pending_events, fixtures, \
clear_write_history, EVENT_READ_TIMEOUT, uinput_write_history_pipe, \ clear_write_history, EVENT_READ_TIMEOUT, uinput_write_history_pipe, \
@ -219,11 +222,75 @@ class TestInjector(unittest.TestCase):
self.assertEqual(history[-2][1], rel_y) self.assertEqual(history[-2][1], rel_y)
self.assertAlmostEqual(history[-2][2], -1) self.assertAlmostEqual(history[-2][2], -1)
def test_handle_keycode(self):
code_code_mapping = {
1: 101,
2: 102
}
history = []
class UInput:
def write(self, type, code, value):
history.append((type, code, value))
def syn(self):
pass
uinput = UInput()
EV_KEY = evdev.ecodes.EV_KEY
handle_keycode(code_code_mapping, {}, Event(EV_KEY, 1, 1), uinput)
handle_keycode(code_code_mapping, {}, Event(EV_KEY, 3, 1), uinput)
handle_keycode(code_code_mapping, {}, Event(EV_KEY, 2, 1), uinput)
self.assertEqual(len(history), 3)
self.assertEqual(history[0], (EV_KEY, 101, 1))
self.assertEqual(history[1], (EV_KEY, 3, 1))
self.assertEqual(history[2], (EV_KEY, 102, 1))
def test_handle_keycode_macro(self):
history = []
macro_mapping = {
1: parse('k(a)', lambda *args: history.append(args)),
2: parse('r(5, k(b))', lambda *args: history.append(args))
}
code_a = 100
code_b = 101
system_mapping['a'] = code_a
system_mapping['b'] = code_b
clear_system_mapping()
EV_KEY = evdev.ecodes.EV_KEY
handle_keycode({}, macro_mapping, Event(EV_KEY, 1, 1), None)
handle_keycode({}, macro_mapping, Event(EV_KEY, 2, 1), None)
loop = asyncio.get_event_loop()
sleeptime = config.get('macros.keystroke_sleep_ms', 10) * 12
async def sleep():
await asyncio.sleep(sleeptime / 1000 + 0.1)
loop.run_until_complete(sleep())
# 6 keycodes written, with down and up events
self.assertEqual(len(history), 12)
self.assertIn(('a', 1), history)
self.assertIn(('a', 0), history)
self.assertIn(('b', 1), history)
self.assertIn(('b', 0), history)
def test_injector(self): def test_injector(self):
custom_mapping.change(8, 'k(KEY_Q).k(w)') custom_mapping.change(8, 'k(KEY_Q).k(w)')
custom_mapping.change(9, 'a') custom_mapping.change(9, 'a')
# one mapping that is unknown in the system_mapping on purpose # one mapping that is unknown in the system_mapping on purpose
custom_mapping.change(10, 'b') input_b = 10
custom_mapping.change(input_b, 'b')
clear_system_mapping() clear_system_mapping()
code_a = 100 code_a = 100
@ -242,10 +309,9 @@ class TestInjector(unittest.TestCase):
# normal keystroke # normal keystroke
Event(EV_KEY, 1, 1), Event(EV_KEY, 1, 1),
Event(EV_KEY, 1, 0), Event(EV_KEY, 1, 0),
# ignored because unknown to the system # just pass those over without modifying
Event(EV_KEY, 2, 1), Event(EV_KEY, 2, 1),
Event(EV_KEY, 2, 0), Event(EV_KEY, 2, 0),
# just pass those over without modifying
Event(3124, 3564, 6542), Event(3124, 3564, 6542),
] ]
@ -262,8 +328,9 @@ class TestInjector(unittest.TestCase):
history.append((event.type, event.code, event.value)) history.append((event.type, event.code, event.value))
# 4 events for the macro # 4 events for the macro
# 3 for non-macros # 2 for mapped keys
self.assertEqual(len(history), 7) # 3 for forwarded events
self.assertEqual(len(history), 9)
# since the macro takes a little bit of time to execute, its # since the macro takes a little bit of time to execute, its
# keystrokes are all over the place. # keystrokes are all over the place.
@ -291,7 +358,9 @@ class TestInjector(unittest.TestCase):
# the rest should be in order. # the rest should be in order.
self.assertEqual(history[0], (ev_key, code_a - KEYCODE_OFFSET, 1)) self.assertEqual(history[0], (ev_key, code_a - KEYCODE_OFFSET, 1))
self.assertEqual(history[1], (ev_key, code_a - KEYCODE_OFFSET, 0)) self.assertEqual(history[1], (ev_key, code_a - KEYCODE_OFFSET, 0))
self.assertEqual(history[2], (3124, 3564, 6542)) self.assertEqual(history[2], (ev_key, input_b - KEYCODE_OFFSET, 1))
self.assertEqual(history[3], (ev_key, input_b - KEYCODE_OFFSET, 0))
self.assertEqual(history[4], (3124, 3564, 6542))
if __name__ == "__main__": if __name__ == "__main__":