0
# Input and Key Binding
1
2
Input event handling, custom key bindings, mouse interaction, and OSD (On-Screen Display) control. Provides comprehensive control over user input and visual feedback systems.
3
4
## Capabilities
5
6
### Keyboard Input
7
8
Send keyboard events and manage key bindings for interactive control.
9
10
```python { .api }
11
def keypress(self, name: str):
12
"""
13
Send a key press event.
14
15
Parameters:
16
- name: Key name (e.g., 'SPACE', 'Enter', 'Esc', 'LEFT', 'a', 'ctrl+c')
17
"""
18
19
def keydown(self, name: str):
20
"""
21
Send a key down event (without release).
22
23
Parameters:
24
- name: Key name
25
"""
26
27
def keyup(self, name: str = None):
28
"""
29
Send a key up event.
30
31
Parameters:
32
- name: Key name (None for last key pressed)
33
"""
34
35
def keybind(self, name: str, command: str):
36
"""
37
Create a simple key binding to mpv command.
38
39
Parameters:
40
- name: Key combination
41
- command: mpv command string to execute
42
"""
43
```
44
45
### Advanced Key Binding
46
47
Register Python callbacks for key events with flexible binding modes.
48
49
```python { .api }
50
def register_key_binding(self, keydef: str, callback_or_cmd, mode: str = 'force'):
51
"""
52
Register a key binding with callback or command.
53
54
Parameters:
55
- keydef: Key definition string
56
- callback_or_cmd: Python function or mpv command string
57
- mode: Binding mode ('force', 'weak')
58
'force': Override existing bindings
59
'weak': Only bind if no existing binding
60
"""
61
62
def unregister_key_binding(self, keydef: str):
63
"""
64
Remove a key binding.
65
66
Parameters:
67
- keydef: Key definition to remove
68
"""
69
70
def key_binding(self, keydef: str, mode: str = 'force'):
71
"""
72
Decorator for registering key binding callbacks.
73
74
Parameters:
75
- keydef: Key definition string
76
- mode: Binding mode ('force', 'weak')
77
78
Returns:
79
Decorator function for callback registration
80
"""
81
82
def on_key_press(self, keydef: str, mode: str = 'force', repetition: bool = False):
83
"""
84
Decorator for key press event handling.
85
86
Parameters:
87
- keydef: Key definition string
88
- mode: Binding mode ('force', 'weak')
89
- repetition: Whether to handle key repetition
90
91
Returns:
92
Decorator function for callback registration
93
"""
94
```
95
96
### Mouse Input
97
98
Handle mouse events including clicks, movement, and scroll wheel.
99
100
```python { .api }
101
def mouse(self, x: int, y: int, button: int = None, mode: str = 'single'):
102
"""
103
Send mouse event.
104
105
Parameters:
106
- x, y: Mouse coordinates
107
- button: Mouse button (0=left, 1=middle, 2=right)
108
- mode: Click mode ('single', 'double')
109
"""
110
```
111
112
### On-Screen Display (OSD)
113
114
Control mpv's built-in OSD for displaying information and status.
115
116
```python { .api }
117
def toggle_osd(self):
118
"""Toggle OSD visibility through different states."""
119
120
def print_text(self, text: str):
121
"""
122
Print text to terminal/console.
123
124
Parameters:
125
- text: Text to print
126
"""
127
128
def show_text(self, string: str, duration: str = '-1', level: int = 0):
129
"""
130
Display text on the OSD.
131
132
Parameters:
133
- string: Text to display (supports property expansion)
134
- duration: Display duration in milliseconds ('-1' for default)
135
- level: OSD level (0=subtitles, 1=seek bar, 2=always visible)
136
"""
137
138
def show_progress(self):
139
"""Show progress bar on OSD."""
140
```
141
142
### Text Processing
143
144
Process text templates with property expansion for dynamic content.
145
146
```python { .api }
147
def expand_text(self, text: str) -> str:
148
"""
149
Expand text template with property values.
150
151
Parameters:
152
- text: Template text with ${property} placeholders
153
154
Returns:
155
Expanded text with property values substituted
156
"""
157
158
def expand_path(self, path: str) -> str:
159
"""
160
Expand path template with mpv path expansion.
161
162
Parameters:
163
- path: Path template
164
165
Returns:
166
Expanded path string
167
"""
168
```
169
170
## Key Definition Format
171
172
Key definitions use mpv's key naming convention:
173
174
### Basic Keys
175
- Letter keys: `a`, `b`, `c`, etc.
176
- Number keys: `0`, `1`, `2`, etc.
177
- Function keys: `F1`, `F2`, `F3`, etc.
178
- Arrow keys: `LEFT`, `RIGHT`, `UP`, `DOWN`
179
- Special keys: `SPACE`, `Enter`, `Esc`, `Tab`, `Backspace`
180
181
### Modifier Keys
182
- `ctrl+key`: Control modifier
183
- `alt+key`: Alt modifier
184
- `shift+key`: Shift modifier
185
- `meta+key`: Meta/Windows modifier
186
187
### Mouse Events
188
- `MOUSE_BTN0`: Left mouse button
189
- `MOUSE_BTN1`: Middle mouse button
190
- `MOUSE_BTN2`: Right mouse button
191
- `WHEEL_UP`, `WHEEL_DOWN`: Mouse wheel
192
193
### Combined Modifiers
194
- `ctrl+alt+key`: Multiple modifiers
195
- `shift+ctrl+F1`: Function key with modifiers
196
197
## Usage Examples
198
199
### Basic Key Bindings
200
201
```python
202
import mpv
203
204
player = mpv.MPV()
205
206
# Simple command bindings
207
player.keybind('SPACE', 'cycle pause')
208
player.keybind('f', 'cycle fullscreen')
209
player.keybind('m', 'cycle mute')
210
player.keybind('LEFT', 'seek -10')
211
player.keybind('RIGHT', 'seek 10')
212
213
# Volume control
214
player.keybind('UP', 'add volume 5')
215
player.keybind('DOWN', 'add volume -5')
216
217
# Subtitle controls
218
player.keybind('s', 'cycle sub-visibility')
219
player.keybind('j', 'cycle sub')
220
```
221
222
### Python Callback Bindings
223
224
```python
225
# Using decorator
226
@player.key_binding('q')
227
def quit_handler():
228
print("Quit requested")
229
player.quit()
230
231
@player.key_binding('i')
232
def info_handler():
233
print(f"Playing: {player.filename}")
234
print(f"Position: {player.time_pos}/{player.duration}")
235
player.show_text(f"Time: ${time-pos}/${duration}")
236
237
# Using method registration
238
def screenshot_handler():
239
filename = f"screenshot_{int(player.time_pos)}.png"
240
player.screenshot_to_file(filename)
241
player.show_text(f"Screenshot saved: {filename}", duration='2000')
242
243
player.register_key_binding('p', screenshot_handler)
244
245
# Advanced callback with key info
246
def debug_key_handler():
247
pos = player.time_pos or 0
248
vol = player.volume
249
paused = player.pause
250
251
debug_info = f"Pos:{pos:.1f} Vol:{vol} Paused:{paused}"
252
print(debug_info)
253
player.show_text(debug_info, level=1)
254
255
player.register_key_binding('d', debug_key_handler)
256
```
257
258
### Mouse Interaction
259
260
```python
261
# Mouse click handlers
262
def handle_mouse_click():
263
# Toggle pause on mouse click
264
player.pause = not player.pause
265
266
player.register_key_binding('MOUSE_BTN0', handle_mouse_click)
267
268
# Mouse wheel for volume
269
def wheel_up():
270
player.property_add('volume', 5)
271
player.show_text(f"Volume: ${volume}")
272
273
def wheel_down():
274
player.property_add('volume', -5)
275
player.show_text(f"Volume: ${volume}")
276
277
player.register_key_binding('WHEEL_UP', wheel_up)
278
player.register_key_binding('WHEEL_DOWN', wheel_down)
279
280
# Programmatic mouse events
281
def click_center():
282
width = player.width or 800
283
height = player.height or 600
284
player.mouse(width // 2, height // 2, button=0)
285
286
# Double-click for fullscreen
287
def double_click_fullscreen():
288
player.mouse(400, 300, mode='double')
289
player.fullscreen = not player.fullscreen
290
291
player.register_key_binding('ctrl+MOUSE_BTN0', double_click_fullscreen)
292
```
293
294
### Advanced Key Binding
295
296
```python
297
# Context-sensitive bindings
298
def smart_seek():
299
"""Smart seeking based on current position."""
300
pos = player.time_pos or 0
301
duration = player.duration or 1
302
303
# Larger jumps near beginning/end
304
if pos < duration * 0.1 or pos > duration * 0.9:
305
seek_amount = 30
306
else:
307
seek_amount = 10
308
309
player.seek(seek_amount)
310
player.show_text(f"Seek +{seek_amount}s")
311
312
player.register_key_binding('ctrl+RIGHT', smart_seek)
313
314
# Multi-key sequences (custom implementation)
315
class MultiKeyHandler:
316
def __init__(self, player):
317
self.player = player
318
self.sequence = []
319
self.timeout = None
320
321
def handle_key(self, key):
322
self.sequence.append(key)
323
324
# Check for known sequences
325
seq_str = ''.join(self.sequence)
326
if seq_str == 'gg': # Go to beginning
327
self.player.seek(0, reference='absolute')
328
self.reset()
329
elif seq_str == 'GG': # Go to end
330
self.player.seek(100, reference='percent')
331
self.reset()
332
elif len(self.sequence) >= 2:
333
self.reset()
334
335
def reset(self):
336
self.sequence = []
337
338
multi_key = MultiKeyHandler(player)
339
340
@player.key_binding('g')
341
def handle_g():
342
multi_key.handle_key('g')
343
344
@player.key_binding('G')
345
def handle_G():
346
multi_key.handle_key('G')
347
```
348
349
### OSD and Text Display
350
351
```python
352
# Property-based text display
353
@player.key_binding('t')
354
def show_time():
355
player.show_text("Time: ${time-pos} / ${duration}")
356
357
@player.key_binding('v')
358
def show_volume():
359
player.show_text("Volume: ${volume}%", duration='1500')
360
361
@player.key_binding('r')
362
def show_resolution():
363
text = "Resolution: ${width}x${height} @ ${fps} FPS"
364
player.show_text(text, level=1)
365
366
# Custom OSD formatting
367
def format_time_display():
368
pos = player.time_pos or 0
369
dur = player.duration or 0
370
371
pos_min, pos_sec = divmod(int(pos), 60)
372
dur_min, dur_sec = divmod(int(dur), 60)
373
374
time_str = f"{pos_min:02d}:{pos_sec:02d} / {dur_min:02d}:{dur_sec:02d}"
375
return time_str
376
377
@player.key_binding('T')
378
def show_formatted_time():
379
time_display = format_time_display()
380
player.show_text(time_display, duration='2000', level=2)
381
382
# Progress indicator
383
@player.key_binding('P')
384
def show_progress_info():
385
player.show_progress()
386
387
# Additional info
388
percent = player.percent_pos or 0
389
player.show_text(f"Progress: {percent:.1f}%", level=1)
390
```
391
392
### Interactive Controls
393
394
```python
395
class InteractivePlayer:
396
def __init__(self):
397
self.player = mpv.MPV()
398
self.help_visible = False
399
self.setup_bindings()
400
401
def setup_bindings(self):
402
"""Setup all key bindings."""
403
404
# Help system
405
@self.player.key_binding('h')
406
def toggle_help():
407
self.toggle_help_display()
408
409
# Playback controls
410
@self.player.key_binding('SPACE')
411
def toggle_pause():
412
self.player.pause = not self.player.pause
413
state = "Paused" if self.player.pause else "Playing"
414
self.player.show_text(state, duration='1000')
415
416
# Seeking with feedback
417
@self.player.key_binding('l')
418
def seek_forward():
419
self.player.seek(10)
420
pos = self.player.time_pos or 0
421
self.player.show_text(f"→ {pos:.1f}s", duration='800')
422
423
@self.player.key_binding('j')
424
def seek_backward():
425
self.player.seek(-10)
426
pos = self.player.time_pos or 0
427
self.player.show_text(f"← {pos:.1f}s", duration='800')
428
429
# Volume with visual feedback
430
@self.player.key_binding('+')
431
def volume_up():
432
self.player.property_add('volume', 5)
433
vol = self.player.volume
434
self.player.show_text(f"Volume: {vol:.0f}%", duration='1000')
435
436
@self.player.key_binding('-')
437
def volume_down():
438
self.player.property_add('volume', -5)
439
vol = self.player.volume
440
self.player.show_text(f"Volume: {vol:.0f}%", duration='1000')
441
442
def toggle_help_display(self):
443
"""Toggle help text display."""
444
if self.help_visible:
445
self.player.show_text("", duration='0') # Clear text
446
self.help_visible = False
447
else:
448
help_text = """
449
Key Bindings:
450
SPACE - Play/Pause h - Toggle Help
451
l/j - Seek ±10s +/- - Volume ±5
452
f - Fullscreen q - Quit
453
""".strip()
454
self.player.show_text(help_text, duration='-1', level=2)
455
self.help_visible = True
456
457
# Usage
458
interactive_player = InteractivePlayer()
459
interactive_player.player.play('/path/to/video.mp4')
460
```
461
462
### Dynamic Key Binding
463
464
```python
465
class DynamicControls:
466
def __init__(self, player):
467
self.player = player
468
self.mode = 'normal'
469
self.setup_mode_switching()
470
471
def setup_mode_switching(self):
472
"""Setup mode-based key bindings."""
473
474
@self.player.key_binding('ESC')
475
def exit_mode():
476
self.set_mode('normal')
477
478
@self.player.key_binding('1')
479
def number_mode():
480
self.set_mode('numbers')
481
482
@self.player.key_binding('2')
483
def seek_mode():
484
self.set_mode('seeking')
485
486
def set_mode(self, mode):
487
"""Change control mode and update bindings."""
488
self.mode = mode
489
490
# Clear existing dynamic bindings
491
for key in ['a', 'b', 'c', 'd']:
492
try:
493
self.player.unregister_key_binding(key)
494
except:
495
pass
496
497
# Setup mode-specific bindings
498
if mode == 'numbers':
499
self.setup_number_mode()
500
elif mode == 'seeking':
501
self.setup_seek_mode()
502
503
self.player.show_text(f"Mode: {mode}", duration='1500')
504
505
def setup_number_mode(self):
506
"""Number input mode bindings."""
507
def make_number_handler(num):
508
def handler():
509
self.player.show_text(f"Number: {num}")
510
return handler
511
512
for i in range(10):
513
self.player.register_key_binding(
514
str(i), make_number_handler(i))
515
516
def setup_seek_mode(self):
517
"""Seek mode bindings."""
518
@self.player.key_binding('a')
519
def seek_10():
520
self.player.seek(10)
521
522
@self.player.key_binding('b')
523
def seek_60():
524
self.player.seek(60)
525
526
@self.player.key_binding('c')
527
def seek_300():
528
self.player.seek(300)
529
530
# Usage
531
dynamic = DynamicControls(player)
532
```