""" Part of the tagit module. A copy of the license is provided with the project. Author: Matthias Baumgartner, 2022 """ # kivy imports from kivy.uix.widget import Widget import kivy.properties as kp # exports __all__ = [] ## code ## class Keyboard(Widget): """Captures key events and turns them into simplified events. Keeps a record of currently pressed modifiers (CTRL, SHIFT, etc.). """ # modifiers MODIFIERS_NONE = 0b00000 # 0 MODIFIERS_CTRL = 0b00001 # 1 MODIFIERS_SHIFT = 0b00010 # 2 MODIFIERS_ALT = 0b00100 # 4 MODIFIERS_ALTGR = 0b01000 # 8 MODIFIERS_CMD = 0b10000 # 16 # modifier keymaps keymap = { 303: MODIFIERS_SHIFT, # right shift 304: MODIFIERS_SHIFT, # left shift 305: MODIFIERS_CTRL, # left ctrl 306: MODIFIERS_CTRL, # right ctrl 307: MODIFIERS_ALTGR, 308: MODIFIERS_ALT, 309: MODIFIERS_CMD, # a.k.a. windows key } modemap = { MODIFIERS_SHIFT: (303, 304), MODIFIERS_CTRL: (305, 306), MODIFIERS_ALTGR: (307, ), MODIFIERS_ALT: (308, ), MODIFIERS_CMD: (309, ), } # current mode mode = kp.NumericProperty(MODIFIERS_NONE) # state access via properties @property def none_pressed(self): return self.mode & self.MODIFIERS_NONE @property def ctrl_pressed(self): return self.mode & self.MODIFIERS_CTRL @property def shift_pressed(self): return self.mode & self.MODIFIERS_SHIFT @property def alt_pressed(self): return self.mode & self.MODIFIERS_ALT @property def altgr_pressed(self): return self.mode & self.MODIFIERS_ALTGR @property def cmd_pressed(self): return self.mode & self.MODIFIERS_CMD ## outbound events __events__ = ('on_press', 'on_release') def on_press(sender, evt): """Key press event prototype.""" pass def on_release(sender, evt): """Key release event prototype.""" pass ## event rewriting def __init__ (self, **kwargs): super(Keyboard, self).__init__(**kwargs) # keybindings from kivy.core.window import Window Window.bind(on_key_up=self.on_key_up) Window.bind(on_key_down=self.on_key_down) Window.bind(on_keyboard=self.on_keyboard) def __del__(self): from kivy.core.window import Window Window.unbind(on_key_up=self.on_key_up) Window.unbind(on_key_down=self.on_key_down) Window.unbind(on_keyboard=self.on_keyboard) def on_key_up(self, wx, key, scancode): """Record modifier release.""" mode = self.keymap.get(key, self.MODIFIERS_NONE) self.mode -= self.mode & mode self.dispatch('on_release', key) def on_key_down(self, wx, key, scancode, char, modifiers): """Record modifiers press.""" mode = self.keymap.get(key, self.MODIFIERS_NONE) self.mode |= mode def on_keyboard(self, wx, key, scancode, char, modifiers): """Forward key presses Handles keybindings. Is called when a key press is detected. *key* : ASCII or ASCII-like value *scancode* : Key code returned by the input provider (e.g. keyboard) *char* : String representation (if A-Z, a-z) *modifiers* : 'ctrl', 'shift', 'alt', or any combination thereof, if pressed """ if False: # print key event for debugging print(f"""Keybindings: Event Key : {key} Scancode : {scancode} Codepoint : {char} Modifiers : {modifiers} """) # forward compact event to widgets self.dispatch('on_press', (key, char, modifiers)) # prevent further event propagation return True ## EOF ##