Files
OpenTerminal/src/main/globalShortcuts.ts
T

68 lines
2.5 KiB
TypeScript

import { BrowserWindow, globalShortcut } from 'electron'
/**
* Chords the app owns outright: Ctrl+L is the panic lock, captured in the main
* window's before-input-event. The settings recorder (SettingsTabs.tsx,
* RESERVED_EXACT_ACCELERATORS) refuses to save it, but that guard only covers
* values entered after it existed — a shortcut persisted by an older build
* still arrives here, and a global registration intercepts the key at the OS
* level even while the window is focused, silently killing the lock shortcut.
* Normalized (modifier aliases + case folded) so every spelling is caught.
*/
const RESERVED_ACCELERATORS = new Set(['control+l', 'commandorcontrol+l'])
function normalizeAccelerator(accelerator: string): string {
return accelerator
.split('+')
.map((part) => {
const p = part.trim().toLowerCase()
if (p === 'ctrl') return 'control'
if (p === 'cmdorctrl' || p === 'commandorctrl') return 'commandorcontrol'
return p
})
.join('+')
}
/**
* Register the global show/hide toggle for the main window.
*
* - accelerator '' / undefined => disabled (no global key bound).
* - A reserved chord (Ctrl+L) is skipped: see RESERVED_ACCELERATORS.
* - Passing an invalid accelerator string makes Electron's register() throw;
* we swallow that here so a bad user-supplied value never crashes the app.
* - register() returning false means the accelerator is already taken by
* another application; we only log a warning and keep running.
*/
export function applyGlobalShortcut(accelerator: string | undefined): void {
// No other global shortcuts are registered anywhere in this app, so a full
// unregister is safe and guarantees a clean re-register on every change.
globalShortcut.unregisterAll()
if (!accelerator) return
if (RESERVED_ACCELERATORS.has(normalizeAccelerator(accelerator))) {
console.warn(
`[global-shortcut] "${accelerator}" is reserved for the Ctrl+L lock shortcut; not registering`
)
return
}
const handler = (): void => {
const win = BrowserWindow.getAllWindows()[0]
if (!win || win.isDestroyed()) return
if (win.isVisible() && win.isFocused()) {
win.hide()
} else {
win.show()
win.focus()
}
}
try {
const ok = globalShortcut.register(accelerator, handler)
if (!ok) {
console.warn(`[global-shortcut] register "${accelerator}" failed (conflict with another app)`)
}
} catch (err) {
console.warn(`[global-shortcut] register "${accelerator}" threw`, err)
}
}