[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:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user