mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
refactor: extract shortcut fallback matching helpers
This commit is contained in:
89
src/core/services/shortcut-fallback-service.ts
Normal file
89
src/core/services/shortcut-fallback-service.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { globalShortcut } from "electron";
|
||||
|
||||
export function isGlobalShortcutRegisteredSafe(accelerator: string): boolean {
|
||||
try {
|
||||
return globalShortcut.isRegistered(accelerator);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function shortcutMatchesInputForLocalFallback(
|
||||
input: Electron.Input,
|
||||
accelerator: string,
|
||||
allowWhenRegistered = false,
|
||||
): boolean {
|
||||
if (input.type !== "keyDown" || input.isAutoRepeat) return false;
|
||||
if (!accelerator) return false;
|
||||
if (!allowWhenRegistered && isGlobalShortcutRegisteredSafe(accelerator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const normalized = accelerator
|
||||
.replace(/\s+/g, "")
|
||||
.replace(/cmdorctrl/gi, "CommandOrControl")
|
||||
.toLowerCase();
|
||||
const parts = normalized.split("+").filter(Boolean);
|
||||
if (parts.length === 0) return false;
|
||||
|
||||
const keyToken = parts[parts.length - 1];
|
||||
const modifierTokens = new Set(parts.slice(0, -1));
|
||||
const allowedModifiers = new Set([
|
||||
"shift",
|
||||
"alt",
|
||||
"meta",
|
||||
"control",
|
||||
"commandorcontrol",
|
||||
]);
|
||||
for (const token of modifierTokens) {
|
||||
if (!allowedModifiers.has(token)) return false;
|
||||
}
|
||||
|
||||
const inputKey = (input.key || "").toLowerCase();
|
||||
if (keyToken.length === 1) {
|
||||
if (inputKey !== keyToken) return false;
|
||||
} else if (keyToken.startsWith("key") && keyToken.length === 4) {
|
||||
if (inputKey !== keyToken.slice(3)) return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
const expectedShift = modifierTokens.has("shift");
|
||||
const expectedAlt = modifierTokens.has("alt");
|
||||
const expectedMeta = modifierTokens.has("meta");
|
||||
const expectedControl = modifierTokens.has("control");
|
||||
const expectedCommandOrControl = modifierTokens.has("commandorcontrol");
|
||||
|
||||
if (Boolean(input.shift) !== expectedShift) return false;
|
||||
if (Boolean(input.alt) !== expectedAlt) return false;
|
||||
|
||||
if (expectedCommandOrControl) {
|
||||
const hasCmdOrCtrl =
|
||||
process.platform === "darwin"
|
||||
? Boolean(input.meta || input.control)
|
||||
: Boolean(input.control);
|
||||
if (!hasCmdOrCtrl) return false;
|
||||
} else {
|
||||
if (process.platform === "darwin") {
|
||||
if (input.meta || input.control) return false;
|
||||
} else if (input.control) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (expectedMeta && !input.meta) return false;
|
||||
if (!expectedMeta && modifierTokens.has("meta") === false && input.meta) {
|
||||
if (!expectedCommandOrControl) return false;
|
||||
}
|
||||
|
||||
if (expectedControl && !input.control) return false;
|
||||
if (
|
||||
!expectedControl &&
|
||||
modifierTokens.has("control") === false &&
|
||||
input.control
|
||||
) {
|
||||
if (!expectedCommandOrControl) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
140
src/main.ts
140
src/main.ts
@@ -131,6 +131,10 @@ import {
|
||||
} from "./core/services/subtitle-ws-service";
|
||||
import { registerGlobalShortcutsService } from "./core/services/shortcut-service";
|
||||
import { registerIpcHandlersService } from "./core/services/ipc-service";
|
||||
import {
|
||||
isGlobalShortcutRegisteredSafe,
|
||||
shortcutMatchesInputForLocalFallback,
|
||||
} from "./core/services/shortcut-fallback-service";
|
||||
import {
|
||||
ConfigService,
|
||||
DEFAULT_CONFIG,
|
||||
@@ -2405,142 +2409,6 @@ function getConfiguredShortcuts() {
|
||||
};
|
||||
}
|
||||
|
||||
function shouldUseMarkAudioCardLocalFallback(input: Electron.Input): boolean {
|
||||
const shortcuts = getConfiguredShortcuts();
|
||||
if (!shortcuts.markAudioCard) return false;
|
||||
if (globalShortcut.isRegistered(shortcuts.markAudioCard)) return false;
|
||||
|
||||
const normalized = shortcuts.markAudioCard.replace(/\s+/g, "").toLowerCase();
|
||||
const supportsFallback =
|
||||
normalized === "commandorcontrol+shift+a" ||
|
||||
normalized === "cmdorctrl+shift+a" ||
|
||||
normalized === "control+shift+a" ||
|
||||
normalized === "ctrl+shift+a";
|
||||
if (!supportsFallback) return false;
|
||||
|
||||
if (input.type !== "keyDown" || input.isAutoRepeat) return false;
|
||||
if ((input.key || "").toLowerCase() !== "a") return false;
|
||||
if (!input.shift || input.alt) return false;
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
return Boolean(input.meta || input.control);
|
||||
}
|
||||
return Boolean(input.control);
|
||||
}
|
||||
|
||||
function shouldUseRuntimeOptionsLocalFallback(input: Electron.Input): boolean {
|
||||
const shortcuts = getConfiguredShortcuts();
|
||||
if (!shortcuts.openRuntimeOptions) return false;
|
||||
if (globalShortcut.isRegistered(shortcuts.openRuntimeOptions)) return false;
|
||||
|
||||
const normalized = shortcuts.openRuntimeOptions
|
||||
.replace(/\s+/g, "")
|
||||
.toLowerCase();
|
||||
const supportsFallback =
|
||||
normalized === "commandorcontrol+shift+o" ||
|
||||
normalized === "cmdorctrl+shift+o" ||
|
||||
normalized === "control+shift+o" ||
|
||||
normalized === "ctrl+shift+o";
|
||||
if (!supportsFallback) return false;
|
||||
|
||||
if (input.type !== "keyDown" || input.isAutoRepeat) return false;
|
||||
if ((input.key || "").toLowerCase() !== "o") return false;
|
||||
if (!input.shift || input.alt) return false;
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
return Boolean(input.meta || input.control);
|
||||
}
|
||||
return Boolean(input.control);
|
||||
}
|
||||
|
||||
function isGlobalShortcutRegisteredSafe(accelerator: string): boolean {
|
||||
try {
|
||||
return globalShortcut.isRegistered(accelerator);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function shortcutMatchesInputForLocalFallback(
|
||||
input: Electron.Input,
|
||||
accelerator: string,
|
||||
allowWhenRegistered = false,
|
||||
): boolean {
|
||||
if (input.type !== "keyDown" || input.isAutoRepeat) return false;
|
||||
if (!accelerator) return false;
|
||||
if (!allowWhenRegistered && isGlobalShortcutRegisteredSafe(accelerator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const normalized = accelerator
|
||||
.replace(/\s+/g, "")
|
||||
.replace(/cmdorctrl/gi, "CommandOrControl")
|
||||
.toLowerCase();
|
||||
const parts = normalized.split("+").filter(Boolean);
|
||||
if (parts.length === 0) return false;
|
||||
|
||||
const keyToken = parts[parts.length - 1];
|
||||
const modifierTokens = new Set(parts.slice(0, -1));
|
||||
const allowedModifiers = new Set([
|
||||
"shift",
|
||||
"alt",
|
||||
"meta",
|
||||
"control",
|
||||
"commandorcontrol",
|
||||
]);
|
||||
for (const token of modifierTokens) {
|
||||
if (!allowedModifiers.has(token)) return false;
|
||||
}
|
||||
|
||||
const inputKey = (input.key || "").toLowerCase();
|
||||
if (keyToken.length === 1) {
|
||||
if (inputKey !== keyToken) return false;
|
||||
} else if (keyToken.startsWith("key") && keyToken.length === 4) {
|
||||
if (inputKey !== keyToken.slice(3)) return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
const expectedShift = modifierTokens.has("shift");
|
||||
const expectedAlt = modifierTokens.has("alt");
|
||||
const expectedMeta = modifierTokens.has("meta");
|
||||
const expectedControl = modifierTokens.has("control");
|
||||
const expectedCommandOrControl = modifierTokens.has("commandorcontrol");
|
||||
|
||||
if (Boolean(input.shift) !== expectedShift) return false;
|
||||
if (Boolean(input.alt) !== expectedAlt) return false;
|
||||
|
||||
if (expectedCommandOrControl) {
|
||||
const hasCmdOrCtrl =
|
||||
process.platform === "darwin"
|
||||
? Boolean(input.meta || input.control)
|
||||
: Boolean(input.control);
|
||||
if (!hasCmdOrCtrl) return false;
|
||||
} else {
|
||||
if (process.platform === "darwin") {
|
||||
if (input.meta || input.control) return false;
|
||||
} else if (input.control) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (expectedMeta && !input.meta) return false;
|
||||
if (!expectedMeta && modifierTokens.has("meta") === false && input.meta) {
|
||||
if (!expectedCommandOrControl) return false;
|
||||
}
|
||||
|
||||
if (expectedControl && !input.control) return false;
|
||||
if (
|
||||
!expectedControl &&
|
||||
modifierTokens.has("control") === false &&
|
||||
input.control
|
||||
) {
|
||||
if (!expectedCommandOrControl) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function tryHandleOverlayShortcutLocalFallback(input: Electron.Input): boolean {
|
||||
const shortcuts = getConfiguredShortcuts();
|
||||
const handlers: Array<{
|
||||
|
||||
Reference in New Issue
Block a user