improvement(shortcut): Support more keyboard shortcuts

This commit is contained in:
icinggslits 2025-02-16 05:17:42 +08:00 committed by 亢奋猫
parent a869857fc1
commit 23a2a6b57c
2 changed files with 165 additions and 25 deletions

View File

@ -56,6 +56,59 @@ function handleZoom(delta: number) {
}
}
const convertShortcutRecordedByKeyboardEventKeyValueToElectronGlobalShortcutFormat = (
shortcut: string | string[]
): string => {
const accelerator = (() => {
if (Array.isArray(shortcut)) {
return shortcut
} else {
return shortcut.split('+').map((key) => key.trim())
}
})()
return accelerator
.map((key) => {
switch (key) {
case 'Control':
return 'CommandOrControl'
case 'Ctrl':
return 'CommandOrControl'
case 'ArrowUp':
return 'Up'
case 'ArrowDown':
return 'Down'
case 'ArrowLeft':
return 'Left'
case 'ArrowRight':
return 'Right'
case 'AltGraph':
return 'Alt'
case 'Slash':
return '/'
case 'Semicolon':
return ';'
case 'BracketLeft':
return '['
case 'BracketRight':
return ']'
case 'Backslash':
return '\\'
case 'Quote':
return "'"
case 'Comma':
return ','
case 'Minus':
return '-'
case 'Equal':
return '='
default:
return key
}
})
.join('+')
}
export function registerShortcuts(window: BrowserWindow) {
window.webContents.setZoomFactor(configManager.getZoomFactor())
@ -104,7 +157,10 @@ export function registerShortcuts(window: BrowserWindow) {
}
if (shortcut.enabled) {
globalShortcut.register(formatShortcutKey(shortcut.shortcut), () => handler(window))
const accelerator = convertShortcutRecordedByKeyboardEventKeyValueToElectronGlobalShortcutFormat(
shortcut.shortcut
)
globalShortcut.register(accelerator, () => handler(window))
}
} catch (error) {
Logger.error(`[ShortcutService] Failed to register shortcut ${shortcut.key}`)
@ -120,12 +176,16 @@ export function registerShortcuts(window: BrowserWindow) {
if (showAppAccelerator) {
const handler = getShortcutHandler({ key: 'show_app' } as Shortcut)
handler && globalShortcut.register(showAppAccelerator, () => handler(window))
const accelerator =
convertShortcutRecordedByKeyboardEventKeyValueToElectronGlobalShortcutFormat(showAppAccelerator)
handler && globalShortcut.register(accelerator, () => handler(window))
}
if (showMiniWindowAccelerator) {
const handler = getShortcutHandler({ key: 'mini_window' } as Shortcut)
handler && globalShortcut.register(showMiniWindowAccelerator, () => handler(window))
const accelerator =
convertShortcutRecordedByKeyboardEventKeyValueToElectronGlobalShortcutFormat(showMiniWindowAccelerator)
handler && globalShortcut.register(accelerator, () => handler(window))
}
} catch (error) {
Logger.error('[ShortcutService] Failed to unregister shortcuts')

View File

@ -8,7 +8,7 @@ import { initialState, resetShortcuts, toggleShortcut, updateShortcut } from '@r
import { Shortcut } from '@renderer/types'
import { Button, Input, InputRef, Switch, Table as AntTable, Tooltip } from 'antd'
import type { ColumnsType } from 'antd/es/table'
import { FC, useRef, useState } from 'react'
import React, { FC, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
@ -92,8 +92,32 @@ const ShortcutSettings: FC = () => {
return isMac ? '⇧' : 'Shift'
case 'CommandOrControl':
return isMac ? '⌘' : 'Ctrl'
case ' ':
return 'Space'
case 'ArrowUp':
return '↑'
case 'ArrowDown':
return '↓'
case 'ArrowLeft':
return '←'
case 'ArrowRight':
return '→'
case 'Slash':
return '/'
case 'Semicolon':
return ';'
case 'BracketLeft':
return '['
case 'BracketRight':
return ']'
case 'Backslash':
return '\\'
case 'Quote':
return "'"
case 'Comma':
return ','
case 'Minus':
return '-'
case 'Equal':
return '='
default:
return key.charAt(0).toUpperCase() + key.slice(1)
}
@ -101,13 +125,61 @@ const ShortcutSettings: FC = () => {
.join(' + ')
}
const usableEndKeys = (key: string): string | null => {
if (key.length === 1) {
return key.toUpperCase()
}
switch (key) {
const usableEndKeys = (event: React.KeyboardEvent): string | null => {
const { code } = event
// No lock keys
// Among the commonly used keys, not including: Escape, NumpadMultiply, NumpadDivide, NumpadSubtract, NumpadAdd, NumpadDecimal
// The react-hotkeys-hook library does not differentiate between `Digit` and `Numpad`
switch (code) {
case 'KeyA':
case 'KeyB':
case 'KeyC':
case 'KeyD':
case 'KeyE':
case 'KeyF':
case 'KeyG':
case 'KeyH':
case 'KeyI':
case 'KeyJ':
case 'KeyK':
case 'KeyL':
case 'KeyM':
case 'KeyN':
case 'KeyO':
case 'KeyP':
case 'KeyQ':
case 'KeyR':
case 'KeyS':
case 'KeyT':
case 'KeyU':
case 'KeyV':
case 'KeyW':
case 'KeyX':
case 'KeyY':
case 'KeyZ':
case 'Digit0':
case 'Digit1':
case 'Digit2':
case 'Digit3':
case 'Digit4':
case 'Digit5':
case 'Digit6':
case 'Digit7':
case 'Digit8':
case 'Digit9':
case 'Numpad0':
case 'Numpad1':
case 'Numpad2':
case 'Numpad3':
case 'Numpad4':
case 'Numpad5':
case 'Numpad6':
case 'Numpad7':
case 'Numpad8':
case 'Numpad9':
return code.slice(-1)
case 'Space':
case 'Enter':
case 'Escape':
case 'Backspace':
case 'Tab':
case 'Delete':
@ -139,10 +211,24 @@ const ShortcutSettings: FC = () => {
case 'F17':
case 'F18':
case 'F19':
case 'F20':
return key
case ' ':
return 'Space'
return code
case 'Backquote':
return '`'
case 'Period':
return '.'
case 'NumpadEnter':
return 'Enter'
// The react-hotkeys-hook library does not handle the symbol strings for the following keys
case 'Slash':
case 'Semicolon':
case 'BracketLeft':
case 'BracketRight':
case 'Backslash':
case 'Quote':
case 'Comma':
case 'Minus':
case 'Equal':
return code
default:
return null
}
@ -156,15 +242,9 @@ const ShortcutSettings: FC = () => {
if (e.metaKey) keys.push('Command')
if (e.altKey) keys.push('Alt')
if (e.shiftKey) keys.push('Shift')
const key = e.key
if (key.length === 1 && !['Control', 'Alt', 'Shift', 'Meta'].includes(key)) {
if (key === ' ') {
keys.push('Space')
} else {
keys.push(key.toUpperCase())
}
const endKey = usableEndKeys(e)
if (endKey) {
keys.push(endKey)
}
if (!isValidShortcut(keys)) {