[FIX] hw_drivers: read modifier keys in the event loop

Key input is handled in an evdev event loop. Before this commit the
state of modifier keys like shift, caps lock, ... were read when the
event was being processed. This doesn't always work because the evdev
events are processed asynchronously, i.e. when key A is being processed
in Python key B may have already been pressed.

Some devices that type fast, notably the Magtek card reader, this leads
to modifiers being applied to the wrong characters. Here's an example
before the patch:

5895000020000006^TEST/VAnTIV^251200000000000000?;4895000020000006=251200
000000000/\0600\0dD15ac71B75BA468E51F4e657529ADF6E3BDAC0A86A59B7adA12029
22F64BB55E74880A1908AD08AFC9372ADe21FD1E74D409C912C1A5|5C3D07B727DE46DaF
B6D8ED2007DB219F49FAC1311F0fa01474FC5BC621F33F915BE77D8DAF5E69A||6140300
0|076C0B3B0704CD78D7CF7Dc5B2ED3F0Ca3ad2e6c88d1F2310B7DB96973b4D556c2f9e4
016C60a7DB581990567FE5656E02C27276FA43BFE|B2ECCDE070215AA|336a4f78bb3c4C
\901209b2eCde000f3\4fC\100

This is what it looks like after the patch:

%B4895000020000006^TEST/VANTIV^251200000000000000?;4895000020000006=2512
00000000000?|0600|FE511F7BA7C38A4FA85D0135E58DDC798E557819356DADA132ECBE
D95184CCC77D7E2B1AE7E8AB076488B9757CA2A046C70590D01FA86217|5DAFE6EC44372
A3EF0358D42D08D9246DD8D2837150954B758199207697EFEB08A71B38B2E1690CE||614
03000|584CB8EBE3B17D2828C3B010DFB4E63E9F5036705CF7E547707DC75A9408E958DC
A3052B03031EA0F3B1F1163E40EF3F542B70F9FFD7912D|B2ECCDE070215AA|21352532D
D6E7334|90CDE0001FA|06A6||1000

These are some of the issues visible in the above example:
- there's a 5 instead of a % (on QWERTY SHIFT-5 is %)
- the n in VAnTIV is lowercase
- there's many /'s which should be ? (on QWERTY SHIFT-/ is ?)
- there's many \'s which should be | (once again on QWERTY SHIFT-\ is |)

To solve the issue, we read the state of the modifiers in the same event
loop.

opw-2122553

closes odoo/odoo#42767

X-original-commit: caa4c7ef6d23f695827b58e60a013a9438eb67cf
Signed-off-by: Quentin Lejeune (qle) <qle@odoo.com>
This commit is contained in:
Joren Van Onder
2020-01-06 13:54:07 +00:00
parent d8b384e6cd
commit e1a99b5027
+27 -11
View File
@@ -41,6 +41,17 @@ class KeyboardUSBDriver(Driver):
self._device_type = 'keyboard'
self._device_connection = 'direct'
self._device_name = self._set_name()
# from https://github.com/xkbcommon/libxkbcommon/blob/master/test/evdev-scancodes.h
self._scancode_to_modifier = {
42: 'left_shift',
54: 'right_shift',
58: 'caps_lock',
69: 'num_lock',
100: 'alt_gr', # right alt
}
self._tracked_modifiers = {modifier: False for modifier in self._scancode_to_modifier.values()}
self.load_layout()
if not KeyboardUSBDriver.available_layouts:
@@ -130,12 +141,22 @@ class KeyboardUSBDriver(Driver):
def run(self):
key_input = self._barcode_scanner_input if self._device_type == "scanner" else self._keyboard_input
try:
for event in self.input_device.read_loop():
if event.type == evdev.ecodes.EV_KEY:
data = evdev.categorize(event)
if data.keystate == 1:
modifier_name = self._scancode_to_modifier.get(data.scancode)
if modifier_name:
if modifier_name in ('caps_lock', 'num_lock'):
if data.keystate == 1:
self._tracked_modifiers[modifier_name] = not self._tracked_modifiers[modifier_name]
else:
self._tracked_modifiers[modifier_name] = bool(data.keystate) # 1 for keydown, 0 for keyup
elif data.keystate == 1:
key_input(data.scancode)
except Exception as err:
_logger.warning(err)
@@ -264,19 +285,14 @@ class KeyboardUSBDriver(Driver):
2 -- AltGr
3 -- Highercase + AltGr
"""
keyboard_leds = self.input_device.leds()
num_lock = 0 in keyboard_leds # Led Num 0
caps_lock = 1 in keyboard_leds # Led Num 1
keyboard_pressed = self.input_device.active_keys()
shift = bool([x for x in [42, 54] if x in keyboard_pressed]) # 42 = Left Shift, 54 = Right Shift
alt_gr = 100 in keyboard_pressed
modifiers = 0
if (scancode in [71, 72, 73, 75, 76, 77, 79, 80, 81, 82, 83] and num_lock) or (shift ^ caps_lock):
uppercase = (self._tracked_modifiers['right_shift'] or self._tracked_modifiers['left_shift']) ^ self._tracked_modifiers['caps_lock']
if uppercase or (scancode in [71, 72, 73, 75, 76, 77, 79, 80, 81, 82, 83] and self._tracked_modifiers['num_lock']):
modifiers += 1
if alt_gr:
if self._tracked_modifiers['alt_gr']:
modifiers += 2
return modifiers
def read_next_barcode(self):