0
# Key Bindings and Events
1
2
Global and widget-specific key binding system for handling user input, navigation, and custom commands in both overview and focus modes.
3
4
## Capabilities
5
6
### Global Key Bindings
7
8
System for binding keys to functions that work in overview mode (when no widget is focused).
9
10
```python { .api }
11
def add_key_command(key: Union[int, List[int]], command: Callable[[], Any]) -> None:
12
"""
13
Add a global key binding for overview mode.
14
15
Parameters:
16
- key: Key code or list of key codes to bind
17
- command: No-argument function to execute when key is pressed
18
"""
19
```
20
21
Usage example:
22
```python
23
import py_cui
24
25
def save_action():
26
print('Save action triggered')
27
28
def quit_action():
29
print('Quitting application')
30
root.stop()
31
32
def help_action():
33
root.show_message_popup('Help', 'F1: Help, S: Save, Q: Quit')
34
35
root = py_cui.PyCUI(3, 3)
36
37
# Single key binding
38
root.add_key_command(py_cui.keys.KEY_S_LOWER, save_action)
39
40
# Multiple keys for same action
41
root.add_key_command([py_cui.keys.KEY_Q_LOWER, py_cui.keys.KEY_ESCAPE], quit_action)
42
43
# Function key binding
44
root.add_key_command(py_cui.keys.KEY_F1, help_action)
45
```
46
47
### Widget Key Bindings
48
49
System for binding keys to functions that work when a specific widget is in focus mode.
50
51
```python { .api }
52
# Widget method for adding key commands
53
def add_key_command(key: Union[int, List[int]], command: Callable[[], Any]) -> None:
54
"""
55
Add a key binding specific to this widget (focus mode).
56
57
Parameters:
58
- key: Key code or list of key codes to bind
59
- command: No-argument function to execute when key is pressed in focus mode
60
"""
61
```
62
63
Usage example:
64
```python
65
import py_cui
66
67
root = py_cui.PyCUI(3, 3)
68
menu = root.add_scroll_menu('Options', 0, 0)
69
text_box = root.add_text_box('Input', 1, 0)
70
71
# Menu-specific key bindings
72
def delete_item():
73
menu.remove_selected_item()
74
75
def clear_menu():
76
menu.clear()
77
78
menu.add_key_command(py_cui.keys.KEY_DELETE, delete_item)
79
menu.add_key_command(py_cui.keys.KEY_CTRL_K, clear_menu)
80
81
# Text box specific key bindings
82
def clear_text():
83
text_box.clear()
84
85
def insert_timestamp():
86
import datetime
87
text_box.write(f' [{datetime.datetime.now()}]')
88
89
text_box.add_key_command(py_cui.keys.KEY_CTRL_L, clear_text)
90
text_box.add_key_command(py_cui.keys.KEY_F5, insert_timestamp)
91
```
92
93
### Widget Navigation Control
94
95
Configuration for navigation keys and widget cycling behavior.
96
97
```python { .api }
98
def set_widget_cycle_key(forward_cycle_key: int = None,
99
reverse_cycle_key: int = None) -> None:
100
"""
101
Set keys for cycling between widgets.
102
103
Parameters:
104
- forward_cycle_key: Key for forward widget cycling (default: Ctrl+Right)
105
- reverse_cycle_key: Key for reverse widget cycling (default: Ctrl+Left)
106
"""
107
```
108
109
Usage example:
110
```python
111
root = py_cui.PyCUI(3, 3)
112
113
# Use Tab/Shift+Tab for widget cycling
114
root.set_widget_cycle_key(
115
forward_cycle_key=py_cui.keys.KEY_TAB,
116
reverse_cycle_key=py_cui.keys.KEY_SHIFT_TAB
117
)
118
119
# Add some widgets to cycle through
120
menu = root.add_scroll_menu('Menu', 0, 0)
121
text_box = root.add_text_box('Input', 0, 1)
122
button = root.add_button('Submit', 0, 2)
123
```
124
125
### Mouse Event Bindings
126
127
System for handling mouse clicks and events on widgets.
128
129
```python { .api }
130
# Widget method for adding mouse commands
131
def add_mouse_command(mouse_event: int, command: Callable[[], Any]) -> None:
132
"""
133
Add a mouse event binding to this widget.
134
135
Parameters:
136
- mouse_event: Mouse event code (button click, double-click, etc.)
137
- command: No-argument function to execute on mouse event
138
"""
139
```
140
141
Usage example:
142
```python
143
import py_cui
144
145
def handle_right_click():
146
root.show_menu_popup('Context Menu', ['Edit', 'Delete', 'Properties'],
147
lambda x: print(f'Selected: {x}'))
148
149
def handle_double_click():
150
print('Double-clicked on menu item')
151
152
root = py_cui.PyCUI(3, 3)
153
menu = root.add_scroll_menu('File List', 0, 0, row_span=2)
154
155
# Add mouse event handlers
156
menu.add_mouse_command(py_cui.keys.MOUSE_RIGHT_CLICK, handle_right_click)
157
menu.add_mouse_command(py_cui.keys.MOUSE_DOUBLE_CLICK, handle_double_click)
158
```
159
160
### Key Constants and Utilities
161
162
Key codes and utilities for working with keyboard input.
163
164
```python { .api }
165
# Common key constants
166
KEY_ENTER: int
167
KEY_ESCAPE: int
168
KEY_TAB: int
169
KEY_BACKSPACE: int
170
KEY_DELETE: int
171
172
# Arrow keys
173
KEY_UP_ARROW: int
174
KEY_DOWN_ARROW: int
175
KEY_LEFT_ARROW: int
176
KEY_RIGHT_ARROW: int
177
ARROW_KEYS: List[int] # List of all arrow key codes
178
179
# Function keys
180
KEY_F1: int
181
KEY_F2: int
182
# ... F3 through F12
183
184
# Control key combinations
185
KEY_CTRL_A: int
186
KEY_CTRL_C: int
187
KEY_CTRL_V: int
188
KEY_CTRL_X: int
189
KEY_CTRL_Z: int
190
# ... other Ctrl combinations
191
192
# Letter keys (upper and lower case)
193
KEY_A_UPPER: int
194
KEY_A_LOWER: int
195
# ... other letters
196
197
# Number keys
198
KEY_0: int
199
KEY_1: int
200
# ... other numbers
201
202
# Special keys
203
KEY_SPACE: int
204
KEY_SHIFT_TAB: int
205
206
# Mouse events
207
MOUSE_LEFT_CLICK: int
208
MOUSE_RIGHT_CLICK: int
209
MOUSE_DOUBLE_CLICK: int
210
211
# Utility functions
212
def get_char_from_ascii(key_code: int) -> Optional[str]:
213
"""
214
Convert key code to character representation.
215
216
Parameters:
217
- key_code: ASCII key code
218
219
Returns:
220
String representation of key or None if not printable
221
"""
222
```
223
224
Usage example:
225
```python
226
import py_cui
227
228
def handle_key_press():
229
# Example of using key constants
230
print('Key pressed!')
231
232
def show_key_help():
233
help_text = f"""
234
Available Keys:
235
{py_cui.keys.get_char_from_ascii(py_cui.keys.KEY_F1)} - Help
236
{py_cui.keys.get_char_from_ascii(py_cui.keys.KEY_S_LOWER)} - Save
237
{py_cui.keys.get_char_from_ascii(py_cui.keys.KEY_Q_LOWER)} - Quit
238
Arrows - Navigate
239
Enter - Select
240
Escape - Cancel
241
"""
242
root.show_message_popup('Key Help', help_text)
243
244
root = py_cui.PyCUI(3, 3)
245
246
# Bind various key types
247
root.add_key_command(py_cui.keys.KEY_F1, show_key_help)
248
root.add_key_command(py_cui.keys.KEY_CTRL_H, show_key_help)
249
root.add_key_command(py_cui.keys.KEY_SPACE, handle_key_press)
250
251
# Check if keys are arrow keys
252
def handle_any_key(key_code: int):
253
if key_code in py_cui.keys.ARROW_KEYS:
254
print('Arrow key pressed')
255
char = py_cui.keys.get_char_from_ascii(key_code)
256
if char:
257
print(f'Printable key: {char}')
258
```
259
260
### Advanced Key Binding Patterns
261
262
Examples of complex key binding scenarios and patterns.
263
264
```python { .api }
265
# Advanced binding patterns (examples)
266
```
267
268
Usage example:
269
```python
270
import py_cui
271
272
class KeyBindingDemo:
273
def __init__(self):
274
self.root = py_cui.PyCUI(3, 3)
275
self.mode = 'normal'
276
277
# Create widgets
278
self.setup_widgets()
279
self.setup_key_bindings()
280
281
def setup_widgets(self):
282
self.menu = self.root.add_scroll_menu('Commands', 0, 0)
283
self.output = self.root.add_text_block('Output', 0, 1, column_span=2)
284
self.input_box = self.root.add_text_box('Input', 1, 0, column_span=3)
285
286
def setup_key_bindings(self):
287
# Modal key bindings - different behavior based on mode
288
self.root.add_key_command(py_cui.keys.KEY_I_LOWER, self.enter_insert_mode)
289
self.root.add_key_command(py_cui.keys.KEY_ESCAPE, self.enter_normal_mode)
290
291
# Conditional key bindings
292
self.root.add_key_command(py_cui.keys.KEY_ENTER, self.context_sensitive_enter)
293
294
# Multi-key sequences (simple implementation)
295
self.last_key = None
296
self.root.add_key_command(py_cui.keys.KEY_G_LOWER, self.handle_g_key)
297
298
def enter_insert_mode(self):
299
self.mode = 'insert'
300
self.root.set_status_bar_text('-- INSERT MODE --')
301
self.root.move_focus(self.input_box)
302
303
def enter_normal_mode(self):
304
self.mode = 'normal'
305
self.root.set_status_bar_text('-- NORMAL MODE --')
306
self.root.lose_focus()
307
308
def context_sensitive_enter(self):
309
if self.mode == 'normal':
310
selected = self.root.get_selected_widget()
311
if selected == self.menu:
312
self.execute_command()
313
elif self.mode == 'insert':
314
self.process_input()
315
316
def handle_g_key(self):
317
# Simple two-key sequence: 'gg' to go to top
318
if self.last_key == py_cui.keys.KEY_G_LOWER:
319
self.goto_top()
320
self.last_key = None
321
else:
322
self.last_key = py_cui.keys.KEY_G_LOWER
323
324
def execute_command(self):
325
command = self.menu.get_selected_item()
326
self.output.write(f'Executing: {command}\n')
327
328
def process_input(self):
329
text = self.input_box.get()
330
self.output.write(f'Input: {text}\n')
331
self.input_box.clear()
332
333
def goto_top(self):
334
self.menu.set_selected_item_index(0)
335
self.output.write('Jumped to top\n')
336
337
def run(self):
338
self.menu.add_item_list(['save', 'load', 'quit', 'help'])
339
self.root.start()
340
341
# Usage
342
demo = KeyBindingDemo()
343
demo.run()
344
```