tiny-pilot / tiny-pilot/tinypilot
Support for Media Keys
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 3.5k
- Forks
- 291
- PR merge metrics
- No merged PRs in 30d
Description
Media keys that exist on some keyboards, for example "Play/Pause", "Next Track" and "Previous Track could be handled by TinyPilot.
In my case, I am actually using TinyPilot to remote control a variety of media devices. These are usually managed with a bluetooth / IR remote control, or other more-exotic-than-a-keyboard control device, but generally do have support for a keyboard being plugged in. There are a couple of types that only provide full functionality via media keys when using a physical keyboard.
HID Codes
I haven't verified these, but I found a reference to the HID codes with this information:
HID CODE | Key
------------|------------------------
0x07 0x00e8 | Media Keys Play/Pause
0x07 0x00e9 | Media Keys Stop
0x07 0x00ea | Media Keys Previous
0x07 0x00eb | Media Keys Next
0x0c 0x00b3 | Media Keys Fast Forward
0x0c 0x00b4 | Media Keys Rewind
I notice that you already have the Play/Pause HID code in keycodes.py, however I'm not sure how it would be used since the virtual keyboard does not have this key, and I don't believe the UI will capture it and forward it on - please do let me know if I'm wrong about that.
Physical and Virtual Keyboard
Capturing these key strokes from a physical keyboard in a browser is different to normal keypresses. Instead of addEventListener, one must use the MediaSessionApi.
In any case, it seems that the couple of browsers I tested (Firefox and Chrome on macOS) ignore these action handlers if there is no "active" media session (see note*)
That being said, it would obviously be possible to add media keys to the virtual keyboard.
Updated socket API
The "real" callback arguments for the action handlers in the MediaSessionApi are not like normal key events, but much more simplistic:
navigator.mediaSession.actionHandler('play', (arg) => console.log(arg));
// the above outputs `{ action: 'play' }`
Between the different event types, and the different callback arguments, it seems as though it would be wrong to extend the existing keystroke socket API with "fake" media key data. An alternative option would be to introduce a new part to the socket api, specifically for this purpose.
Ultimately pressing these keys could lead to emitting something like the following:
socket.emit('mediaKeystroke', { action: 'play' })
There would then presumably need to be an equivalent request_parsers/media_keystroke.py - this file could be simpler than the existing keystroke.py parser, since it would not have to handle any modifiers. I guess that js_to_hid.py would also need a convert_media(mediaKeystroke) similar to the existing convert(keystroke). And some other updates, most notably to socket_api.py to implement the rest of the parts.
--
*note If I load a youtube video in the browser, the "Play/Pause" button will work to control the video. If I then use the developer console to set my own action handler, it takes over and my handler is called instead of controlling the video when I press the button. However - if I add the same handler on an arbitrary non-video-containing page it does nothing at all.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the existing flow through keycodes.py, request_parsers/keystroke.py, js_to_hid.py, and socket_api.py, then investigate the MediaSession API behavior described in the issue. Define how physical and virtual media-key actions enter the socket API and reach HID output; done means the listed media actions work reliably on supported browsers and devices.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, python, raspberry-pi
- Domain
- api, backend, embedded-iot, frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100