summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjaseg <code@jaseg.net>2017-08-21 15:36:03 +0200
committerjaseg <code@jaseg.net>2017-08-21 15:36:03 +0200
commit2ca5c7b9c88960994a9b1494f46bd01c0388a21f (patch)
tree9e35987d3ffcf389954cb748b62ca82f88461bce
parent14783b2193759ee5a45654634a0bb863576df4d9 (diff)
downloadpython-mpv-2ca5c7b9c88960994a9b1494f46bd01c0388a21f.tar.gz
python-mpv-2ca5c7b9c88960994a9b1494f46bd01c0388a21f.tar.bz2
python-mpv-2ca5c7b9c88960994a9b1494f46bd01c0388a21f.zip
Add on_key_press
-rw-r--r--README.rst18
-rwxr-xr-xmpv-test.py35
-rw-r--r--mpv.py32
3 files changed, 74 insertions, 11 deletions
diff --git a/README.rst b/README.rst
index a1f0987..16f4f48 100644
--- a/README.rst
+++ b/README.rst
@@ -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)
-
- 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('q')
+ def my_q_binding():
+ print('THERE IS NO ESCAPE')
+
+ @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()
diff --git a/mpv-test.py b/mpv-test.py
index d829dba..96bf225 100755
--- a/mpv-test.py
+++ b/mpv-test.py
@@ -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() ]
diff --git a/mpv.py b/mpv.py
index c53deb8..1c32e10 100644
--- a/mpv.py
+++ b/mpv.py
@@ -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".