Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: How to waif for key event? #155

Open
dennyh opened this issue Mar 21, 2021 · 4 comments
Open

Question: How to waif for key event? #155

dennyh opened this issue Mar 21, 2021 · 4 comments

Comments

@dennyh
Copy link

dennyh commented Mar 21, 2021

How would I get my script to wait for one of two key presses in mpv?
I want to wait for the user to press one of two keys and then do things based on what key was pressed.

Currently I have hacked together a an ugly way of waiting for keypresses using wait_for_event and on_key_press sending some text to the osd.

# send client-message
@player.on_key_press("ENTER")
	def my_ENTER_binding():
		player.show_text("text")
# waiting for key press
player.wait_for_event("CLIENT_MESSAGE", cond=lambda evt : evt["event"]["args"][2:4] == ["d-", "ENTER"])

You might be able to tell I am fairly new to python.

@jaseg
Copy link
Owner

jaseg commented Mar 21, 2021

The "pythonic" way to do this through python-mpv's interfaces I think would be to register two key press handlers that notify your interaction thread through a condition object from python's threading module. Here's some (untested) code as a starting point:

import threading
cond = threading.Condition()

key = None

@player.on_key_press("a")
def on_a():
    nonlocal key
    key = 'a'
    with cond:
        cond.notify()

@player.on_key_press("b")
def on_b():
    nonlocal key
    key = 'b'
    with cond:
        cond.notify()

with cond:
    cond.wait(timeout=None)
on_a.unregister_mpv_key_bindings()
on_b.unregister_mpv_key_bindings()


print(f'User pressed {key}')

Execution will stop at cond.wait until either callback fires. The callbacks are called on python-mpv's internal event handler thread, so they will work even while the thread that created them is waiting in cond.wait.

@dennyh
Copy link
Author

dennyh commented Mar 22, 2021

Thanks for the help! This was what I was looking for.

When trying this out I did notice something I am unsure if it is intended behavior.

import threading
import mpv

def wait_a_or_b(player: mpv.MPV) -> str:
	
	cond = threading.Condition()
	key = None
	
	@player.on_key_press("a")
	def on_a():
		nonlocal key
		key = 'a'
		with cond:
			cond.notify()
	
	@player.on_key_press("b")
	def on_b():
		nonlocal key
		key = 'b'
		with cond:
			cond.notify()
	
	with cond:
		cond.wait(timeout=None)
	on_a.unregister_mpv_key_bindings()
	on_b.unregister_mpv_key_bindings()
	
	return key

player = mpv.MPV(input_default_bindings=False, input_vo_keyboard=True, osc=True, volume=10)

# Register a keybinding
@player.on_key_press("r")
def my_r_binding():
	pass
	
player.loop = True

player.play("ThreeEditions.mkv")
player.wait_until_playing()

keyPressed = wait_a_or_b(player) # <----
#print(f'User pressed {keyPressed}')

my_r_binding.unregister_mpv_key_bindings() # <----

input("Press enter to continue...")

This code runs fine and does what is expected. However, if we comment out my_r_binding.unregister_mpv_key_bindings() and hits the last row input("Press enter to continue...") it throws exeptions. If we also comment out the call to wait_a_or_b then no exceptions are thrown.
This also happens if input is switched for time.sleep.

exception:

Exception inside python-mpv event loop:
Traceback (most recent call last):
  File "C:\Python38\lib\site-packages\mpv.py", line 881, in _loop
    self._message_handlers[target](*args)
  File "C:\Python38\lib\site-packages\mpv.py", line 1550, in _handle_key_binding_message
    self._key_binding_handlers[binding_name](key_state, key_name, key_char)
KeyError: 'py_kb_d09505b79a7d8a10'

@jaseg
Copy link
Owner

jaseg commented Mar 23, 2021

Oh, that looks like a bug. I'll try to reproduce this and commit a fix.

@dennyh
Copy link
Author

dennyh commented Mar 29, 2021

Let me know if you need any more input from me.
On another note:
The docstring of observe_property in mpv.py mentions the unregister_mpv_properties attribute. I think this is meant to be unobserve_mpv_properties as it is defined in property_observer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants