1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
"""
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 ##
|