feat(overlay): add optional subtitle selection modal (#265)

This commit is contained in:
sudacode authored and GitHub committed 2026-09-22 18:30:26 -07:00
1 parent a7a302bdd0
commit b0fb39a8f5
54 files changed
+1397 -52

No files matched your search

+43 -1
View File
@@ -12,6 +12,10 @@ import type {
SessionKeySpec,
} from '../../types/session-bindings';
import { SPECIAL_COMMANDS } from '../../config';
import {
resolveSessionSequenceConflicts,
type SessionKeyReservation,
} from '../../shared/session-key-sequences';
type PlatformKeyModel = 'darwin' | 'win32' | 'linux';
@@ -56,6 +60,7 @@ const SESSION_SHORTCUT_ACTIONS: Array<{
{ key: 'openRuntimeOptions', actionId: 'openRuntimeOptions' },
{ key: 'openJimaku', actionId: 'openJimaku' },
{ key: 'openTsukihime', actionId: 'openTsukihime' },
{ key: 'openSubtitleSelection', actionId: 'openSubtitleSelection' },
{ key: 'openSubtitleGeneration', actionId: 'openSubtitleGeneration' },
{ key: 'openSessionHelp', actionId: 'openSessionHelp' },
{ key: 'openControllerSelect', actionId: 'openControllerSelect' },
@@ -81,6 +86,13 @@ function normalizeCodeToken(
): string | null {
const normalized = token.trim();
if (!normalized) return null;
// Two lowercase letters use mpv's sequential-key syntax, for example g-s.
if (/^[a-z]-[a-z]$/.test(normalized)) {
return normalized
.split('-')
.map((letter) => `Key${letter.toUpperCase()}`)
.join('-');
}
if (options.allowMouseButtons === true) {
const normalizedMouse = normalized.toUpperCase();
if (MPV_MOUSE_BUTTON_CODES.has(normalizedMouse)) {
@@ -543,7 +555,37 @@ export function compileSessionBindings(input: CompileSessionBindingsInput): {
}
bindings.sort((left, right) => left.sourcePath.localeCompare(right.sourcePath));
return { bindings, warnings };
const reservations: SessionKeyReservation[] = [
{ key: { code: 'KeyY', modifiers: [] }, path: 'built-in y sequences' },
{ key: { code: 'KeyV', modifiers: [] }, path: 'primary subtitle visibility key' },
{ key: { code: 'KeyY', modifiers: ['ctrl'] }, path: 'lookup window toggle' },
{ key: { code: 'KeyY', modifiers: ['meta'] }, path: 'lookup window toggle' },
{ key: { code: 'KeyY', modifiers: ['ctrl', 'shift'] }, path: 'keyboard-driven mode toggle' },
{ key: { code: 'KeyY', modifiers: ['shift', 'meta'] }, path: 'keyboard-driven mode toggle' },
...[...candidates.values()].flatMap((drafts) =>
drafts.map(({ binding }) => ({
key: binding.key,
path: binding.sourcePath,
})),
),
];
const sidebarKey = input.rawConfig?.subtitleSidebar?.toggleKey;
if (sidebarKey) {
const { key } = parseSessionBindingKey(sidebarKey, input.platform);
if (key) {
// The sidebar accepts DOM codes with either Shift state, or literal characters.
if (/^[A-Z]$/.test(sidebarKey)) key.modifiers = ['shift'];
reservations.push({ key, path: 'subtitleSidebar.toggleKey' });
if (/^Key[A-Z]$/.test(sidebarKey)) {
reservations.push({
key: { ...key, modifiers: ['shift'] },
path: 'subtitleSidebar.toggleKey',
});
}
}
}
const result = resolveSessionSequenceConflicts(bindings, reservations);
return { bindings: result.bindings, warnings: [...warnings, ...result.warnings] };
}
export function buildPluginSessionBindingsArtifact(input: {