71 lines
1.9 KiB
TypeScript
71 lines
1.9 KiB
TypeScript
/**
|
|
* Global multimedia key handler hook.
|
|
*
|
|
* Captures media-related key events (play/pause, volume, speed)
|
|
* regardless of which component is focused. Uses the event bus to
|
|
* decouple key detection from audio control logic.
|
|
*
|
|
* Volume and speed are app-level settings — adjustable with or without
|
|
* an episode loaded (they apply to the next playback and persist). Seek
|
|
* is NOT handled here: it lives on the yazi keybind router (`<` / `>` =
|
|
* shift+, / shift+.), so the arrow keys stay free for navigation.
|
|
*/
|
|
|
|
import { useKeyboard } from "@opentui/solid";
|
|
import { emit } from "../utils/event-bus";
|
|
|
|
export type MediaKeyAction =
|
|
| "media.toggle"
|
|
| "media.volumeUp"
|
|
| "media.volumeDown"
|
|
| "media.speedCycle";
|
|
|
|
export interface MultimediaKeysOptions {
|
|
/** When true, skip handling (Player.tsx handles keys locally) */
|
|
playerFocused?: () => boolean;
|
|
/** When true, skip handling (text input has focus) */
|
|
inputFocused?: () => boolean;
|
|
}
|
|
|
|
/**
|
|
* Registers a global keyboard listener that emits media events on the
|
|
* event bus. Call once at the app level (e.g. in App.tsx).
|
|
*/
|
|
export function useMultimediaKeys(options: MultimediaKeysOptions = {}) {
|
|
useKeyboard((key) => {
|
|
// Don't intercept when a text input owns the keyboard
|
|
if (options.inputFocused?.()) return;
|
|
|
|
// Don't intercept when Player component handles its own keys
|
|
if (options.playerFocused?.()) return;
|
|
|
|
// Ctrl/Meta combos are app-level shortcuts, not media keys
|
|
if (key.ctrl || key.meta) return;
|
|
|
|
switch (key.name) {
|
|
case "space":
|
|
// Toggle play/pause — always valid (may start a loaded episode)
|
|
emit("media.toggle", {});
|
|
break;
|
|
|
|
case "up":
|
|
emit("media.volumeUp", {});
|
|
break;
|
|
|
|
case "down":
|
|
emit("media.volumeDown", {});
|
|
break;
|
|
|
|
case "s":
|
|
// Speed is shift+s (S) so plain `s` stays free for search.
|
|
if (!key.shift) return;
|
|
emit("media.speedCycle", {});
|
|
break;
|
|
|
|
default:
|
|
// Not a media key — do nothing
|
|
break;
|
|
}
|
|
});
|
|
}
|