mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
Standardize core service module and export names to reduce naming ambiguity and make imports predictable across runtime, tests, scripts, and docs.
134 lines
3.2 KiB
TypeScript
134 lines
3.2 KiB
TypeScript
interface GlobalShortcutLike {
|
|
register: (accelerator: string, callback: () => void) => boolean;
|
|
unregister: (accelerator: string) => void;
|
|
}
|
|
|
|
export interface NumericShortcutRuntimeOptions {
|
|
globalShortcut: GlobalShortcutLike;
|
|
showMpvOsd: (text: string) => void;
|
|
setTimer: (
|
|
handler: () => void,
|
|
timeoutMs: number,
|
|
) => ReturnType<typeof setTimeout>;
|
|
clearTimer: (timer: ReturnType<typeof setTimeout>) => void;
|
|
}
|
|
|
|
export function createNumericShortcutRuntime(
|
|
options: NumericShortcutRuntimeOptions,
|
|
) {
|
|
const createSession = () =>
|
|
createNumericShortcutSession({
|
|
registerShortcut: (accelerator, handler) =>
|
|
options.globalShortcut.register(accelerator, handler),
|
|
unregisterShortcut: (accelerator) =>
|
|
options.globalShortcut.unregister(accelerator),
|
|
setTimer: options.setTimer,
|
|
clearTimer: options.clearTimer,
|
|
showMpvOsd: options.showMpvOsd,
|
|
});
|
|
|
|
return {
|
|
createSession,
|
|
};
|
|
}
|
|
|
|
export interface NumericShortcutSessionMessages {
|
|
prompt: string;
|
|
timeout: string;
|
|
cancelled?: string;
|
|
}
|
|
|
|
export interface NumericShortcutSessionDeps {
|
|
registerShortcut: (accelerator: string, handler: () => void) => boolean;
|
|
unregisterShortcut: (accelerator: string) => void;
|
|
setTimer: (handler: () => void, timeoutMs: number) => ReturnType<typeof setTimeout>;
|
|
clearTimer: (timer: ReturnType<typeof setTimeout>) => void;
|
|
showMpvOsd: (text: string) => void;
|
|
}
|
|
|
|
export interface NumericShortcutSessionStartParams {
|
|
timeoutMs: number;
|
|
onDigit: (digit: number) => void;
|
|
messages: NumericShortcutSessionMessages;
|
|
}
|
|
|
|
export function createNumericShortcutSession(
|
|
deps: NumericShortcutSessionDeps,
|
|
) {
|
|
let active = false;
|
|
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
let digitShortcuts: string[] = [];
|
|
let escapeShortcut: string | null = null;
|
|
|
|
let cancelledMessage = "Cancelled";
|
|
|
|
const cancel = (showCancelled = false): void => {
|
|
if (!active) return;
|
|
active = false;
|
|
|
|
if (timeout) {
|
|
deps.clearTimer(timeout);
|
|
timeout = null;
|
|
}
|
|
|
|
for (const shortcut of digitShortcuts) {
|
|
deps.unregisterShortcut(shortcut);
|
|
}
|
|
digitShortcuts = [];
|
|
|
|
if (escapeShortcut) {
|
|
deps.unregisterShortcut(escapeShortcut);
|
|
escapeShortcut = null;
|
|
}
|
|
|
|
if (showCancelled) {
|
|
deps.showMpvOsd(cancelledMessage);
|
|
}
|
|
};
|
|
|
|
const start = ({
|
|
timeoutMs,
|
|
onDigit,
|
|
messages,
|
|
}: NumericShortcutSessionStartParams): void => {
|
|
cancel();
|
|
cancelledMessage = messages.cancelled ?? "Cancelled";
|
|
active = true;
|
|
|
|
for (let i = 1; i <= 9; i++) {
|
|
const shortcut = i.toString();
|
|
if (
|
|
deps.registerShortcut(shortcut, () => {
|
|
if (!active) return;
|
|
cancel();
|
|
onDigit(i);
|
|
})
|
|
) {
|
|
digitShortcuts.push(shortcut);
|
|
}
|
|
}
|
|
|
|
if (
|
|
deps.registerShortcut("Escape", () => {
|
|
cancel(true);
|
|
})
|
|
) {
|
|
escapeShortcut = "Escape";
|
|
}
|
|
|
|
timeout = deps.setTimer(() => {
|
|
if (!active) return;
|
|
cancel();
|
|
deps.showMpvOsd(messages.timeout);
|
|
}, timeoutMs);
|
|
|
|
deps.showMpvOsd(messages.prompt);
|
|
};
|
|
|
|
return {
|
|
start,
|
|
cancel,
|
|
isActive: (): boolean => active,
|
|
};
|
|
}
|