Init
This commit is contained in:
198
barcode_server/keyevent_reader.py
Normal file
198
barcode_server/keyevent_reader.py
Normal file
@ -0,0 +1,198 @@
|
||||
import logging
|
||||
|
||||
from evdev import KeyEvent, InputDevice, categorize
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
US_EN_UPPER_DICT = {
|
||||
"`": "~",
|
||||
"1": "!",
|
||||
"2": "@",
|
||||
"3": "#",
|
||||
"4": "$",
|
||||
"5": "%",
|
||||
"6": "^",
|
||||
"7": "&",
|
||||
"8": "*",
|
||||
"9": "(",
|
||||
"0": ")",
|
||||
"-": "_",
|
||||
"=": "+",
|
||||
",": "<",
|
||||
".": ">",
|
||||
"/": "?",
|
||||
";": ":",
|
||||
"'": "\"",
|
||||
"\\": "|",
|
||||
"[": "{",
|
||||
"]": "}"
|
||||
}
|
||||
|
||||
|
||||
class KeyEventReader:
|
||||
"""
|
||||
Class used to convert a sequence of KeyEvents to text
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._shift = False
|
||||
self._caps = False
|
||||
self._alt = False
|
||||
self._unicode_number_input_buffer = ""
|
||||
|
||||
self._line = ""
|
||||
|
||||
def read_line(self, input_device: InputDevice) -> str:
|
||||
"""
|
||||
Reads a line
|
||||
:param input_device: the device to read from
|
||||
:return: line
|
||||
"""
|
||||
self._line = ""
|
||||
# While there is a function called async_read_loop, it tends
|
||||
# to skip input events, so we use the non-async read-loop here.
|
||||
|
||||
# async for event in input_device.async_read_loop():
|
||||
for event in input_device.read_loop():
|
||||
try:
|
||||
event = categorize(event)
|
||||
|
||||
if hasattr(event, "event"):
|
||||
if not hasattr(event, "keystate") and hasattr(event.event, "keystate"):
|
||||
event.keystate = event.event.keystate
|
||||
|
||||
if not hasattr(event, "keystate") or not hasattr(event, "keycode"):
|
||||
continue
|
||||
|
||||
keycode = event.keycode
|
||||
keystate = event.keystate
|
||||
|
||||
if isinstance(event, KeyEvent):
|
||||
if self._on_key_event(keycode, keystate):
|
||||
return self._line
|
||||
elif hasattr(event, "event") and event.event.type == 1:
|
||||
if self._on_key_event(keycode, keystate):
|
||||
return self._line
|
||||
except Exception as ex:
|
||||
LOGGER.exception(ex)
|
||||
|
||||
def _on_key_event(self, code: str, state: int) -> bool:
|
||||
if code in ["KEY_ENTER", "KEY_KPENTER"]:
|
||||
if state == KeyEvent.key_up:
|
||||
# line is finished
|
||||
self._reset_modifiers()
|
||||
return True
|
||||
elif code in ["KEY_RIGHTSHIFT", "KEY_LEFTSHIFT"]:
|
||||
if state in [KeyEvent.key_down, KeyEvent.key_hold]:
|
||||
self._shift = True
|
||||
else:
|
||||
self._shift = False
|
||||
elif code in ["KEY_LEFTALT", "KEY_RIGHTALT"]:
|
||||
if state in [KeyEvent.key_down, KeyEvent.key_hold]:
|
||||
self._alt = True
|
||||
else:
|
||||
self._alt = False
|
||||
|
||||
character = self._unicode_numbers_to_character(self._unicode_number_input_buffer)
|
||||
self._unicode_number_input_buffer = ""
|
||||
|
||||
if character is not None:
|
||||
self._line += character
|
||||
|
||||
elif code == "KEY_BACKSPACE":
|
||||
self._line = self._line[:-1]
|
||||
elif state == KeyEvent.key_down:
|
||||
character = self._code_to_character(code)
|
||||
if self._alt:
|
||||
self._unicode_number_input_buffer += character
|
||||
else:
|
||||
if character is not None and not self._alt:
|
||||
# append the current character
|
||||
self._line += character
|
||||
|
||||
return False
|
||||
|
||||
def _code_to_character(self, code: str) -> chr or None:
|
||||
character = None
|
||||
|
||||
if len(code) == 5:
|
||||
character = code[-1]
|
||||
elif code.startswith("KEY_KP") and len(code) == 7:
|
||||
character = code[-1]
|
||||
|
||||
elif code in ["KEY_DOWN"]:
|
||||
character = '\n'
|
||||
elif code in ["KEY_SPACE"]:
|
||||
character = ' '
|
||||
elif code in ["KEY_ASTERISK", "KEY_KPASTERISK"]:
|
||||
character = '*'
|
||||
elif code in ["KEY_MINUS", "KEY_KPMINUS"]:
|
||||
character = '-'
|
||||
elif code in ["KEY_PLUS", "KEY_KPPLUS"]:
|
||||
character = '+'
|
||||
elif code in ["KEY_QUESTION"]:
|
||||
character = '?'
|
||||
elif code in ["KEY_COMMA", "KEY_KPCOMMA"]:
|
||||
character = ','
|
||||
elif code in ["KEY_DOT", "KEY_KPDOT"]:
|
||||
character = '.'
|
||||
elif code in ["KEY_EQUAL", "KEY_KPEQUAL"]:
|
||||
character = '='
|
||||
elif code in ["KEY_LEFTPAREN", "KEY_KPLEFTPAREN"]:
|
||||
character = '('
|
||||
elif code in ["KEY_PLUSMINUS", "KEY_KPPLUSMINUS"]:
|
||||
character = '+-'
|
||||
elif code in ["KEY_RIGHTPAREN", "KEY_KPRIGHTPAREN"]:
|
||||
character = ')'
|
||||
elif code in ["KEY_RIGHTBRACE"]:
|
||||
character = ']'
|
||||
elif code in ["KEY_LEFTBRACE"]:
|
||||
character = '['
|
||||
elif code in ["KEY_SLASH", "KEY_KPSLASH"]:
|
||||
character = '/'
|
||||
elif code in ["KEY_BACKSLASH"]:
|
||||
character = '\\'
|
||||
elif code in ["KEY_COLON"]:
|
||||
character = ';'
|
||||
elif code in ["KEY_SEMICOLON"]:
|
||||
character = ';'
|
||||
elif code in ["KEY_APOSTROPHE"]:
|
||||
character = '\''
|
||||
elif code in ["KEY_GRAVE"]:
|
||||
character = '`'
|
||||
|
||||
if character is None:
|
||||
character = code[4:]
|
||||
if len(character) > 1:
|
||||
LOGGER.warning(f"Unhandled Keycode: {code}")
|
||||
|
||||
if self._shift or self._caps:
|
||||
character = character.upper()
|
||||
if character in US_EN_UPPER_DICT.keys():
|
||||
character = US_EN_UPPER_DICT[character]
|
||||
else:
|
||||
character = character.lower()
|
||||
|
||||
return character
|
||||
|
||||
@staticmethod
|
||||
def _unicode_numbers_to_character(code: str) -> chr or None:
|
||||
if code is None or len(code) <= 0:
|
||||
return None
|
||||
|
||||
try:
|
||||
# convert to hex
|
||||
i = int(code)
|
||||
h = hex(i)
|
||||
s = f"{h}"
|
||||
|
||||
return bytearray.fromhex(s[2:]).decode('utf-8')
|
||||
except Exception as ex:
|
||||
LOGGER.exception(ex)
|
||||
return None
|
||||
|
||||
def _reset_modifiers(self):
|
||||
self._alt = False
|
||||
self._unicode_number_input_buffer = ""
|
||||
self._shift = False
|
||||
self._caps = False
|
Reference in New Issue
Block a user