Add on_key_press

This commit is contained in:
jaseg 2017-08-21 15:36:03 +02:00
parent 14783b2193
commit 2ca5c7b9c8
3 changed files with 73 additions and 10 deletions

View file

@ -85,16 +85,14 @@ Advanced Usage
# Option access, in general these require the core to reinitialize
player['vo'] = 'opengl'
def my_q_binding(state, key):
if state[0] == 'd':
print('THERE IS NO ESCAPE')
player.register_key_binding('q', my_q_binding)
@player.on_key_press('q')
def my_q_binding():
print('THERE IS NO ESCAPE')
def my_s_binding(state, key):
if state[0] == 'd':
pillow_img = player.screenshot_raw()
pillow_img.save('screenshot.png')
player.register_key_binding('s', my_s_binding)
@player.on_key_press('s')
def my_s_binding():
pillow_img = player.screenshot_raw()
pillow_img.save('screenshot.png')
player.play('https://youtu.be/DLzxrzFCyOs')
player.wait_for_playback()

View file

@ -316,6 +316,41 @@ class KeyBindingTest(MpvTestCase):
self.assertNotIn(b('b'), self.m._key_binding_handlers)
self.assertIn(b('c'), self.m._key_binding_handlers)
def test_register_simple_decorator_fun_chaining(self):
b = mpv.MPV._binding_name
handler1, handler2 = mock.Mock(), mock.Mock()
@self.m.on_key_press('a')
@self.m.on_key_press('b')
def reg_test_fun(*args, **kwargs):
handler1(*args, **kwargs)
@self.m.on_key_press('c')
def reg_test_fun_2_stay_intact(*args, **kwargs):
handler2(*args, **kwargs)
self.assertEqual(reg_test_fun.mpv_key_bindings, ['b', 'a'])
self.assertIn(b('a'), self.m._key_binding_handlers)
self.assertIn(b('b'), self.m._key_binding_handlers)
self.assertIn(b('c'), self.m._key_binding_handlers)
self.m._key_binding_handlers[b('a')]('p-', 'q')
handler1.assert_has_calls([ mock.call() ])
handler2.assert_has_calls([])
handler1.reset_mock()
self.m._key_binding_handlers[b('b')]('p-', 'q')
handler1.assert_has_calls([ mock.call() ])
handler2.assert_has_calls([])
self.m._key_binding_handlers[b('c')]('p-', 'q')
handler1.assert_has_calls([])
handler2.assert_has_calls([ mock.call() ])
reg_test_fun.unregister_mpv_key_bindings()
self.assertNotIn(b('a'), self.m._key_binding_handlers)
self.assertNotIn(b('b'), self.m._key_binding_handlers)
self.assertIn(b('c'), self.m._key_binding_handlers)
class TestLifecycle(unittest.TestCase):
def test_create_destroy(self):
thread_names = lambda: [ t.name for t in threading.enumerate() ]

32
mpv.py
View file

@ -915,8 +915,38 @@ class MPV(object):
def _binding_name(callback_or_cmd):
return 'py_kb_{:016x}'.format(hash(callback_or_cmd)&0xffffffffffffffff)
def on_key_press(self, keydef, mode='force'):
""" Function decorator to register a simplified key binding. The callback is called whenever the key
given is *pressed*.
To unregister the callback function, you can call its ```unregister_mpv_key_bindings``` attribute:
```
player = mpv.MPV()
@player.on_key_press('Q')
def binding():
print('blep')
binding.unregister_mpv_key_bindings()
```
WARNING: For a single keydef only a single callback/command can be registered at the same time. If you register
a binding multiple times older bindings will be overwritten and there is a possibility of references leaking. So
don't do that.
The BIG FAT WARNING regarding untrusted keydefs from the key_binding method applies here as well. """
def register(fun):
@self.key_binding(keydef, mode)
@wraps(fun)
def wrapper(state='p-', name=None):
if state[0] in ('d', 'p'):
fun()
return wrapper
return register
def key_binding(self, keydef, mode='force'):
""" Function decorator to register a key binding.
""" Function decorator to register a low-level key binding.
The callback function signature is ```fun(key_state, key_name)``` where ```key_state``` is either ```'U'``` for
"key up" or ```'D'``` for "key down".