mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-04-05 00:12:06 -07:00
fix: restore linux modal shortcuts
This commit is contained in:
@@ -41,6 +41,7 @@ export interface ConfigTemplateSection {
|
||||
export const SPECIAL_COMMANDS = {
|
||||
SUBSYNC_TRIGGER: '__subsync-trigger',
|
||||
RUNTIME_OPTIONS_OPEN: '__runtime-options-open',
|
||||
JIMAKU_OPEN: '__jimaku-open',
|
||||
RUNTIME_OPTION_CYCLE_PREFIX: '__runtime-option-cycle:',
|
||||
REPLAY_SUBTITLE: '__replay-subtitle',
|
||||
PLAY_NEXT_SUBTITLE: '__play-next-subtitle',
|
||||
|
||||
@@ -10,6 +10,7 @@ function createOptions(overrides: Partial<Parameters<typeof handleMpvCommandFrom
|
||||
specialCommands: {
|
||||
SUBSYNC_TRIGGER: '__subsync-trigger',
|
||||
RUNTIME_OPTIONS_OPEN: '__runtime-options-open',
|
||||
JIMAKU_OPEN: '__jimaku-open',
|
||||
RUNTIME_OPTION_CYCLE_PREFIX: '__runtime-option-cycle:',
|
||||
REPLAY_SUBTITLE: '__replay-subtitle',
|
||||
PLAY_NEXT_SUBTITLE: '__play-next-subtitle',
|
||||
@@ -24,6 +25,9 @@ function createOptions(overrides: Partial<Parameters<typeof handleMpvCommandFrom
|
||||
openRuntimeOptionsPalette: () => {
|
||||
calls.push('runtime-options');
|
||||
},
|
||||
openJimaku: () => {
|
||||
calls.push('jimaku');
|
||||
},
|
||||
openYoutubeTrackPicker: () => {
|
||||
calls.push('youtube-picker');
|
||||
},
|
||||
@@ -114,6 +118,14 @@ test('handleMpvCommandFromIpc dispatches special youtube picker open command', (
|
||||
assert.deepEqual(osd, []);
|
||||
});
|
||||
|
||||
test('handleMpvCommandFromIpc dispatches special jimaku open command', () => {
|
||||
const { options, calls, sentCommands, osd } = createOptions();
|
||||
handleMpvCommandFromIpc(['__jimaku-open'], options);
|
||||
assert.deepEqual(calls, ['jimaku']);
|
||||
assert.deepEqual(sentCommands, []);
|
||||
assert.deepEqual(osd, []);
|
||||
});
|
||||
|
||||
test('handleMpvCommandFromIpc dispatches special playlist browser open command', async () => {
|
||||
const { options, calls, sentCommands, osd } = createOptions();
|
||||
handleMpvCommandFromIpc(['__playlist-browser-open'], options);
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface HandleMpvCommandFromIpcOptions {
|
||||
specialCommands: {
|
||||
SUBSYNC_TRIGGER: string;
|
||||
RUNTIME_OPTIONS_OPEN: string;
|
||||
JIMAKU_OPEN: string;
|
||||
RUNTIME_OPTION_CYCLE_PREFIX: string;
|
||||
REPLAY_SUBTITLE: string;
|
||||
PLAY_NEXT_SUBTITLE: string;
|
||||
@@ -19,6 +20,7 @@ export interface HandleMpvCommandFromIpcOptions {
|
||||
};
|
||||
triggerSubsyncFromConfig: () => void;
|
||||
openRuntimeOptionsPalette: () => void;
|
||||
openJimaku: () => void;
|
||||
openYoutubeTrackPicker: () => void | Promise<void>;
|
||||
openPlaylistBrowser: () => void | Promise<void>;
|
||||
runtimeOptionsCycle: (id: RuntimeOptionId, direction: 1 | -1) => RuntimeOptionApplyResult;
|
||||
@@ -94,6 +96,11 @@ export function handleMpvCommandFromIpc(
|
||||
return;
|
||||
}
|
||||
|
||||
if (first === options.specialCommands.JIMAKU_OPEN) {
|
||||
options.openJimaku();
|
||||
return;
|
||||
}
|
||||
|
||||
if (first === options.specialCommands.YOUTUBE_PICKER_OPEN) {
|
||||
void options.openYoutubeTrackPicker();
|
||||
return;
|
||||
|
||||
@@ -4191,6 +4191,7 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
|
||||
mpvCommandMainDeps: {
|
||||
triggerSubsyncFromConfig: () => triggerSubsyncFromConfig(),
|
||||
openRuntimeOptionsPalette: () => openRuntimeOptionsPalette(),
|
||||
openJimaku: () => overlayModalRuntime.openJimaku(),
|
||||
openYoutubeTrackPicker: () => openYoutubeTrackPickerFromPlayback(),
|
||||
openPlaylistBrowser: () => openPlaylistBrowser(),
|
||||
cycleRuntimeOption: (id, direction) => {
|
||||
|
||||
@@ -197,6 +197,7 @@ export interface MpvCommandRuntimeServiceDepsParams {
|
||||
runtimeOptionsCycle: HandleMpvCommandFromIpcOptions['runtimeOptionsCycle'];
|
||||
triggerSubsyncFromConfig: HandleMpvCommandFromIpcOptions['triggerSubsyncFromConfig'];
|
||||
openRuntimeOptionsPalette: HandleMpvCommandFromIpcOptions['openRuntimeOptionsPalette'];
|
||||
openJimaku: HandleMpvCommandFromIpcOptions['openJimaku'];
|
||||
openYoutubeTrackPicker: HandleMpvCommandFromIpcOptions['openYoutubeTrackPicker'];
|
||||
openPlaylistBrowser: HandleMpvCommandFromIpcOptions['openPlaylistBrowser'];
|
||||
showMpvOsd: HandleMpvCommandFromIpcOptions['showMpvOsd'];
|
||||
@@ -368,6 +369,7 @@ export function createMpvCommandRuntimeServiceDeps(
|
||||
specialCommands: params.specialCommands,
|
||||
triggerSubsyncFromConfig: params.triggerSubsyncFromConfig,
|
||||
openRuntimeOptionsPalette: params.openRuntimeOptionsPalette,
|
||||
openJimaku: params.openJimaku,
|
||||
openYoutubeTrackPicker: params.openYoutubeTrackPicker,
|
||||
openPlaylistBrowser: params.openPlaylistBrowser,
|
||||
runtimeOptionsCycle: params.runtimeOptionsCycle,
|
||||
|
||||
@@ -12,6 +12,7 @@ type MpvPropertyClientLike = {
|
||||
export interface MpvCommandFromIpcRuntimeDeps {
|
||||
triggerSubsyncFromConfig: () => void;
|
||||
openRuntimeOptionsPalette: () => void;
|
||||
openJimaku: () => void;
|
||||
openYoutubeTrackPicker: () => void | Promise<void>;
|
||||
openPlaylistBrowser: () => void | Promise<void>;
|
||||
cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => RuntimeOptionApplyResult;
|
||||
@@ -35,6 +36,7 @@ export function handleMpvCommandFromIpcRuntime(
|
||||
specialCommands: SPECIAL_COMMANDS,
|
||||
triggerSubsyncFromConfig: deps.triggerSubsyncFromConfig,
|
||||
openRuntimeOptionsPalette: deps.openRuntimeOptionsPalette,
|
||||
openJimaku: deps.openJimaku,
|
||||
openYoutubeTrackPicker: deps.openYoutubeTrackPicker,
|
||||
openPlaylistBrowser: deps.openPlaylistBrowser,
|
||||
runtimeOptionsCycle: deps.cycleRuntimeOption,
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface OverlayModalRuntime {
|
||||
},
|
||||
) => boolean;
|
||||
openRuntimeOptionsPalette: () => void;
|
||||
openJimaku: () => void;
|
||||
handleOverlayModalClosed: (modal: OverlayHostedModal) => void;
|
||||
notifyOverlayModalOpened: (modal: OverlayHostedModal) => void;
|
||||
waitForModalOpen: (modal: OverlayHostedModal, timeoutMs: number) => Promise<boolean>;
|
||||
@@ -307,6 +308,12 @@ export function createOverlayModalRuntimeService(
|
||||
});
|
||||
};
|
||||
|
||||
const openJimaku = (): void => {
|
||||
sendToActiveOverlayWindow('jimaku:open', undefined, {
|
||||
restoreOnModalClose: 'jimaku',
|
||||
});
|
||||
};
|
||||
|
||||
const handleOverlayModalClosed = (modal: OverlayHostedModal): void => {
|
||||
if (!restoreVisibleOverlayOnModalClose.has(modal)) return;
|
||||
restoreVisibleOverlayOnModalClose.delete(modal);
|
||||
@@ -379,6 +386,7 @@ export function createOverlayModalRuntimeService(
|
||||
return {
|
||||
sendToActiveOverlayWindow,
|
||||
openRuntimeOptionsPalette,
|
||||
openJimaku,
|
||||
handleOverlayModalClosed,
|
||||
notifyOverlayModalOpened,
|
||||
waitForModalOpen,
|
||||
|
||||
@@ -10,6 +10,7 @@ test('composeIpcRuntimeHandlers returns callable IPC handlers and registration b
|
||||
mpvCommandMainDeps: {
|
||||
triggerSubsyncFromConfig: async () => {},
|
||||
openRuntimeOptionsPalette: () => {},
|
||||
openJimaku: () => {},
|
||||
openYoutubeTrackPicker: () => {},
|
||||
openPlaylistBrowser: () => {},
|
||||
cycleRuntimeOption: () => ({ ok: true }),
|
||||
|
||||
@@ -13,6 +13,7 @@ test('ipc bridge action main deps builders map callbacks', async () => {
|
||||
buildMpvCommandDeps: () => ({
|
||||
triggerSubsyncFromConfig: async () => {},
|
||||
openRuntimeOptionsPalette: () => {},
|
||||
openJimaku: () => {},
|
||||
openYoutubeTrackPicker: () => {},
|
||||
openPlaylistBrowser: () => {},
|
||||
cycleRuntimeOption: () => ({ ok: false as const, error: 'x' }),
|
||||
|
||||
@@ -10,6 +10,7 @@ test('handle mpv command handler forwards command and built deps', () => {
|
||||
const deps = {
|
||||
triggerSubsyncFromConfig: () => {},
|
||||
openRuntimeOptionsPalette: () => {},
|
||||
openJimaku: () => {},
|
||||
openYoutubeTrackPicker: () => {},
|
||||
openPlaylistBrowser: () => {},
|
||||
cycleRuntimeOption: () => ({ ok: false as const, error: 'x' }),
|
||||
|
||||
@@ -7,6 +7,7 @@ test('ipc mpv command main deps builder maps callbacks', () => {
|
||||
const deps = createBuildMpvCommandFromIpcRuntimeMainDepsHandler({
|
||||
triggerSubsyncFromConfig: () => calls.push('subsync'),
|
||||
openRuntimeOptionsPalette: () => calls.push('palette'),
|
||||
openJimaku: () => calls.push('jimaku'),
|
||||
openYoutubeTrackPicker: () => {
|
||||
calls.push('youtube-picker');
|
||||
},
|
||||
@@ -28,6 +29,7 @@ test('ipc mpv command main deps builder maps callbacks', () => {
|
||||
|
||||
deps.triggerSubsyncFromConfig();
|
||||
deps.openRuntimeOptionsPalette();
|
||||
deps.openJimaku();
|
||||
void deps.openYoutubeTrackPicker();
|
||||
void deps.openPlaylistBrowser();
|
||||
assert.deepEqual(deps.cycleRuntimeOption('anki.nPlusOneMatchMode', 1), { ok: false, error: 'x' });
|
||||
@@ -42,6 +44,7 @@ test('ipc mpv command main deps builder maps callbacks', () => {
|
||||
assert.deepEqual(calls, [
|
||||
'subsync',
|
||||
'palette',
|
||||
'jimaku',
|
||||
'youtube-picker',
|
||||
'playlist-browser',
|
||||
'osd:hello',
|
||||
|
||||
@@ -6,6 +6,7 @@ export function createBuildMpvCommandFromIpcRuntimeMainDepsHandler(
|
||||
return (): MpvCommandFromIpcRuntimeDeps => ({
|
||||
triggerSubsyncFromConfig: () => deps.triggerSubsyncFromConfig(),
|
||||
openRuntimeOptionsPalette: () => deps.openRuntimeOptionsPalette(),
|
||||
openJimaku: () => deps.openJimaku(),
|
||||
openYoutubeTrackPicker: () => deps.openYoutubeTrackPicker(),
|
||||
openPlaylistBrowser: () => deps.openPlaylistBrowser(),
|
||||
cycleRuntimeOption: (id, direction) => deps.cycleRuntimeOption(id, direction),
|
||||
|
||||
@@ -53,6 +53,21 @@ function installKeyboardTestGlobals() {
|
||||
let playbackPausedResponse: boolean | null = false;
|
||||
let statsToggleKey = 'Backquote';
|
||||
let markWatchedKey = 'KeyW';
|
||||
let configuredShortcuts = {
|
||||
copySubtitle: '',
|
||||
copySubtitleMultiple: '',
|
||||
updateLastCardFromClipboard: '',
|
||||
triggerFieldGrouping: '',
|
||||
triggerSubsync: 'Ctrl+Alt+S',
|
||||
mineSentence: '',
|
||||
mineSentenceMultiple: '',
|
||||
multiCopyTimeoutMs: 1000,
|
||||
toggleSecondarySub: '',
|
||||
markAudioCard: '',
|
||||
openRuntimeOptions: 'CommandOrControl+Shift+O',
|
||||
openJimaku: 'Ctrl+Shift+J',
|
||||
toggleVisibleOverlayGlobal: '',
|
||||
};
|
||||
let markActiveVideoWatchedResult = true;
|
||||
let markActiveVideoWatchedCalls = 0;
|
||||
let statsToggleOverlayCalls = 0;
|
||||
@@ -138,6 +153,7 @@ function installKeyboardTestGlobals() {
|
||||
},
|
||||
electronAPI: {
|
||||
getKeybindings: async () => [],
|
||||
getConfiguredShortcuts: async () => configuredShortcuts,
|
||||
sendMpvCommand: (command: Array<string | number>) => {
|
||||
mpvCommands.push(command);
|
||||
},
|
||||
@@ -273,6 +289,9 @@ function installKeyboardTestGlobals() {
|
||||
setMarkWatchedKey: (value: string) => {
|
||||
markWatchedKey = value;
|
||||
},
|
||||
setConfiguredShortcuts: (value: typeof configuredShortcuts) => {
|
||||
configuredShortcuts = value;
|
||||
},
|
||||
setMarkActiveVideoWatchedResult: (value: boolean) => {
|
||||
markActiveVideoWatchedResult = value;
|
||||
},
|
||||
@@ -315,6 +334,7 @@ function createKeyboardHandlerHarness() {
|
||||
overlay: testGlobals.overlay,
|
||||
},
|
||||
platform: {
|
||||
isLinuxPlatform: false,
|
||||
shouldToggleMouseIgnore: false,
|
||||
isMacOSPlatform: false,
|
||||
isModalLayer: false,
|
||||
@@ -765,6 +785,51 @@ test('youtube picker: unhandled keys still dispatch mpv keybindings', async () =
|
||||
}
|
||||
});
|
||||
|
||||
test('linux overlay shortcut: Ctrl+Alt+S dispatches subsync special command locally', async () => {
|
||||
const { ctx, handlers, testGlobals } = createKeyboardHandlerHarness();
|
||||
|
||||
try {
|
||||
ctx.platform.isLinuxPlatform = true;
|
||||
await handlers.setupMpvInputForwarding();
|
||||
|
||||
testGlobals.dispatchKeydown({ key: 's', code: 'KeyS', ctrlKey: true, altKey: true });
|
||||
|
||||
assert.deepEqual(testGlobals.mpvCommands, [['__subsync-trigger']]);
|
||||
} finally {
|
||||
testGlobals.restore();
|
||||
}
|
||||
});
|
||||
|
||||
test('linux overlay shortcut: Ctrl+Shift+J dispatches jimaku special command locally', async () => {
|
||||
const { ctx, handlers, testGlobals } = createKeyboardHandlerHarness();
|
||||
|
||||
try {
|
||||
ctx.platform.isLinuxPlatform = true;
|
||||
await handlers.setupMpvInputForwarding();
|
||||
|
||||
testGlobals.dispatchKeydown({ key: 'J', code: 'KeyJ', ctrlKey: true, shiftKey: true });
|
||||
|
||||
assert.deepEqual(testGlobals.mpvCommands, [['__jimaku-open']]);
|
||||
} finally {
|
||||
testGlobals.restore();
|
||||
}
|
||||
});
|
||||
|
||||
test('linux overlay shortcut: CommandOrControl+Shift+O dispatches runtime options locally', async () => {
|
||||
const { ctx, handlers, testGlobals } = createKeyboardHandlerHarness();
|
||||
|
||||
try {
|
||||
ctx.platform.isLinuxPlatform = true;
|
||||
await handlers.setupMpvInputForwarding();
|
||||
|
||||
testGlobals.dispatchKeydown({ key: 'O', code: 'KeyO', ctrlKey: true, shiftKey: true });
|
||||
|
||||
assert.deepEqual(testGlobals.mpvCommands, [['__runtime-options-open']]);
|
||||
} finally {
|
||||
testGlobals.restore();
|
||||
}
|
||||
});
|
||||
|
||||
test('keyboard mode: h moves left when popup is closed', async () => {
|
||||
const { ctx, handlers, testGlobals } = createKeyboardHandlerHarness();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Keybinding } from '../../types';
|
||||
import { SPECIAL_COMMANDS } from '../../config/definitions';
|
||||
import type { Keybinding, ShortcutsConfig } from '../../types';
|
||||
import type { RendererContext } from '../context';
|
||||
import {
|
||||
YOMITAN_POPUP_HIDDEN_EVENT,
|
||||
@@ -35,6 +36,7 @@ export function createKeyboardHandlers(
|
||||
// Timeout for the modal chord capture window (e.g. Y followed by H/K).
|
||||
const CHORD_TIMEOUT_MS = 1000;
|
||||
const KEYBOARD_SELECTED_WORD_CLASS = 'keyboard-selected';
|
||||
const linuxOverlayShortcutCommands = new Map<string, (string | number)[]>();
|
||||
let pendingSelectionAnchorAfterSubtitleSeek: 'start' | 'end' | null = null;
|
||||
let pendingLookupRefreshAfterSubtitleSeek = false;
|
||||
let resetSelectionToStartOnNextSubtitleSync = false;
|
||||
@@ -74,6 +76,117 @@ export function createKeyboardHandlers(
|
||||
return parts.join('+');
|
||||
}
|
||||
|
||||
function acceleratorToKeyToken(token: string): string | null {
|
||||
const normalized = token.trim();
|
||||
if (!normalized) return null;
|
||||
if (/^[a-z]$/i.test(normalized)) {
|
||||
return `Key${normalized.toUpperCase()}`;
|
||||
}
|
||||
if (/^[0-9]$/.test(normalized)) {
|
||||
return `Digit${normalized}`;
|
||||
}
|
||||
const exactMap: Record<string, string> = {
|
||||
space: 'Space',
|
||||
tab: 'Tab',
|
||||
enter: 'Enter',
|
||||
return: 'Enter',
|
||||
esc: 'Escape',
|
||||
escape: 'Escape',
|
||||
up: 'ArrowUp',
|
||||
down: 'ArrowDown',
|
||||
left: 'ArrowLeft',
|
||||
right: 'ArrowRight',
|
||||
backspace: 'Backspace',
|
||||
delete: 'Delete',
|
||||
slash: 'Slash',
|
||||
backslash: 'Backslash',
|
||||
minus: 'Minus',
|
||||
plus: 'Equal',
|
||||
equal: 'Equal',
|
||||
comma: 'Comma',
|
||||
period: 'Period',
|
||||
quote: 'Quote',
|
||||
semicolon: 'Semicolon',
|
||||
bracketleft: 'BracketLeft',
|
||||
bracketright: 'BracketRight',
|
||||
backquote: 'Backquote',
|
||||
};
|
||||
const lower = normalized.toLowerCase();
|
||||
if (exactMap[lower]) return exactMap[lower];
|
||||
if (/^key[a-z]$/i.test(normalized) || /^digit[0-9]$/i.test(normalized)) {
|
||||
return normalized[0]!.toUpperCase() + normalized.slice(1);
|
||||
}
|
||||
if (/^arrow(?:up|down|left|right)$/i.test(normalized)) {
|
||||
return normalized[0]!.toUpperCase() + normalized.slice(1);
|
||||
}
|
||||
if (/^f\d{1,2}$/i.test(normalized)) {
|
||||
return normalized.toUpperCase();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function acceleratorToKeyString(accelerator: string): string | null {
|
||||
const normalized = accelerator
|
||||
.replace(/\s+/g, '')
|
||||
.replace(/cmdorctrl/gi, 'CommandOrControl');
|
||||
if (!normalized) return null;
|
||||
const parts = normalized.split('+').filter(Boolean);
|
||||
const keyToken = parts.pop();
|
||||
if (!keyToken) return null;
|
||||
|
||||
const eventParts: string[] = [];
|
||||
for (const modifier of parts) {
|
||||
const lower = modifier.toLowerCase();
|
||||
if (lower === 'ctrl' || lower === 'control') {
|
||||
eventParts.push('Ctrl');
|
||||
continue;
|
||||
}
|
||||
if (lower === 'alt' || lower === 'option') {
|
||||
eventParts.push('Alt');
|
||||
continue;
|
||||
}
|
||||
if (lower === 'shift') {
|
||||
eventParts.push('Shift');
|
||||
continue;
|
||||
}
|
||||
if (lower === 'meta' || lower === 'super' || lower === 'command' || lower === 'cmd') {
|
||||
eventParts.push('Meta');
|
||||
continue;
|
||||
}
|
||||
if (lower === 'commandorcontrol') {
|
||||
eventParts.push(ctx.platform.isMacOSPlatform ? 'Meta' : 'Ctrl');
|
||||
continue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalizedKey = acceleratorToKeyToken(keyToken);
|
||||
if (!normalizedKey) return null;
|
||||
eventParts.push(normalizedKey);
|
||||
return eventParts.join('+');
|
||||
}
|
||||
|
||||
function updateConfiguredShortcuts(shortcuts: Required<ShortcutsConfig>): void {
|
||||
linuxOverlayShortcutCommands.clear();
|
||||
const bindings: Array<[string | null, (string | number)[]]> = [
|
||||
[shortcuts.triggerSubsync, [SPECIAL_COMMANDS.SUBSYNC_TRIGGER]],
|
||||
[shortcuts.openRuntimeOptions, [SPECIAL_COMMANDS.RUNTIME_OPTIONS_OPEN]],
|
||||
[shortcuts.openJimaku, [SPECIAL_COMMANDS.JIMAKU_OPEN]],
|
||||
];
|
||||
|
||||
for (const [accelerator, command] of bindings) {
|
||||
if (!accelerator) continue;
|
||||
const keyString = acceleratorToKeyString(accelerator);
|
||||
if (keyString) {
|
||||
linuxOverlayShortcutCommands.set(keyString, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshConfiguredShortcuts(): Promise<void> {
|
||||
updateConfiguredShortcuts(await window.electronAPI.getConfiguredShortcuts());
|
||||
}
|
||||
|
||||
function dispatchYomitanPopupKeydown(
|
||||
key: string,
|
||||
code: string,
|
||||
@@ -779,12 +892,14 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
|
||||
async function setupMpvInputForwarding(): Promise<void> {
|
||||
const [keybindings, statsToggleKey, markWatchedKey] = await Promise.all([
|
||||
const [keybindings, shortcuts, statsToggleKey, markWatchedKey] = await Promise.all([
|
||||
window.electronAPI.getKeybindings(),
|
||||
window.electronAPI.getConfiguredShortcuts(),
|
||||
window.electronAPI.getStatsToggleKey(),
|
||||
window.electronAPI.getMarkWatchedKey(),
|
||||
]);
|
||||
updateKeybindings(keybindings);
|
||||
updateConfiguredShortcuts(shortcuts);
|
||||
ctx.state.statsToggleKey = statsToggleKey;
|
||||
ctx.state.markWatchedKey = markWatchedKey;
|
||||
syncKeyboardTokenSelection();
|
||||
@@ -982,6 +1097,14 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
|
||||
const keyString = keyEventToString(e);
|
||||
const linuxOverlayCommand = ctx.platform.isLinuxPlatform
|
||||
? linuxOverlayShortcutCommands.get(keyString)
|
||||
: undefined;
|
||||
if (linuxOverlayCommand) {
|
||||
e.preventDefault();
|
||||
dispatchConfiguredMpvCommand(linuxOverlayCommand);
|
||||
return;
|
||||
}
|
||||
const command = ctx.state.keybindingsMap.get(keyString);
|
||||
|
||||
if (command) {
|
||||
@@ -1015,6 +1138,7 @@ export function createKeyboardHandlers(
|
||||
|
||||
return {
|
||||
setupMpvInputForwarding,
|
||||
refreshConfiguredShortcuts,
|
||||
updateKeybindings,
|
||||
syncKeyboardTokenSelection,
|
||||
handleSubtitleContentUpdated,
|
||||
|
||||
@@ -130,6 +130,7 @@ function describeCommand(command: (string | number)[]): string {
|
||||
}
|
||||
if (first === SPECIAL_COMMANDS.SUBSYNC_TRIGGER) return 'Open subtitle sync controls';
|
||||
if (first === SPECIAL_COMMANDS.RUNTIME_OPTIONS_OPEN) return 'Open runtime options';
|
||||
if (first === SPECIAL_COMMANDS.JIMAKU_OPEN) return 'Open jimaku';
|
||||
if (first === SPECIAL_COMMANDS.PLAYLIST_BROWSER_OPEN) return 'Open playlist browser';
|
||||
if (first === SPECIAL_COMMANDS.REPLAY_SUBTITLE) return 'Replay current subtitle';
|
||||
if (first === SPECIAL_COMMANDS.PLAY_NEXT_SUBTITLE) return 'Play next subtitle';
|
||||
@@ -165,6 +166,7 @@ function sectionForCommand(command: (string | number)[]): string {
|
||||
|
||||
if (
|
||||
first === SPECIAL_COMMANDS.RUNTIME_OPTIONS_OPEN ||
|
||||
first === SPECIAL_COMMANDS.JIMAKU_OPEN ||
|
||||
first === SPECIAL_COMMANDS.PLAYLIST_BROWSER_OPEN ||
|
||||
first.startsWith(SPECIAL_COMMANDS.RUNTIME_OPTION_CYCLE_PREFIX)
|
||||
) {
|
||||
|
||||
@@ -621,6 +621,7 @@ async function init(): Promise<void> {
|
||||
window.electronAPI.onConfigHotReload((payload: ConfigHotReloadPayload) => {
|
||||
runGuarded('config:hot-reload', () => {
|
||||
keyboardHandlers.updateKeybindings(payload.keybindings);
|
||||
void keyboardHandlers.refreshConfiguredShortcuts();
|
||||
subtitleRenderer.applySubtitleStyle(payload.subtitleStyle);
|
||||
subtitleRenderer.updateSecondarySubMode(payload.secondarySubMode);
|
||||
ctx.state.subtitleSidebarConfig = payload.subtitleSidebar;
|
||||
|
||||
Reference in New Issue
Block a user