-
Notifications
You must be signed in to change notification settings - Fork 1k
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
HID keyboard won't release keys when called via schedule #873
Comments
Hi @mischif, Thanks for the very clear report. At the moment calling send_keys() will block for up to the timeout (default 100ms) waiting for the USB endpoint to be available to queue a new transfer, and then returns True for success or False for failure. In your scheduled send_keys() function I'm guessing the second call is returning False indicating that the transfer wasn't able to queue to be sent to the host. Probably this is not ideal behaviour for this function, it should throw an exception on timeout. I'll look at changing it. However, the underlying problem will still be there. An operation like send_keys() returns when the transfer is queued for sending to the host, but this may still take some time before the USB host actually performs the transfer. In the meantime, the USB endpoint isn't available. The reason why the USB endpoint never becomes available, even after 100ms, is that the transfer completion callback is also processed via a If you need to send and release a keypress with def send_and_release(keys):
if not KBD.is_open():
print("Can't send, USB disconnected")
elif not KBD.send_keys(keys, 0):
schedule(send_and_release, keys) # Try again after other callbacks run
elif keys:
schedule(send_and_release, []) # Schedule the release if needed However it might be better to look into approaches other than schedule to send more than one keyboard transfer in a sequence. Possibly a thread, possibly asyncio, or handling it in the normal "main" execution somehow. |
The way I envisioned my code working is a button press triggers an ISR which determines if a keypress needs to be sent; if so, it calls a handler function via If I'm understanding correctly this means there's no best way to call As a workaround I have the scheduled function update a global the main loop can call |
Yes, that's pretty much right. You can technically call send_keys() from a soft ISR, but you can't guarantee the call is going to succeed so it's best to structure it in some other way. USB devices are a bit limited in what they can do here because all USB transfers are initiated by the USB host. So calling "send_keys" is really only preparing the key data to go to the host the next time it asks for it. The USB library is written in a way where only one transfer can be queued at a time.
I think this is actually a good way to structure it, if your code is going to have a main loop anyway.
Not sure I understand the question, can you please give some more detail? |
That's not true (if you're referring to |
I was wondering about calling
AIUI, a single keypress requires two calls to |
I wouldn't recommend trying to do this exactly, but if you already have an async task created and blocked on something like a ThreadSafeFlag then you could signal that from the ISR to wake the task up. Then it could send the key down event, |
Calling
KeyboardInterface().send_keys()
from a function called viamicropython.schedule()
doesn't seem to allow keys to be released, causing a spamming issue. This code reproduces the issue:running🅱️ , this is on a Pico running 1.23.0 and whatever the latest version of usb-device-keyboard is currently in mip.
schedule(send_keys, None)
instead ofsend_keys(None)
causes a flood ofThe text was updated successfully, but these errors were encountered: