ai-chat-ui/src/composables/useKeyboard.ts

128 lines
3.7 KiB
TypeScript

import { onMounted, onUnmounted, ref } from 'vue'
export interface KeyboardShortcut {
key: string
ctrl?: boolean
shift?: boolean
alt?: boolean
meta?: boolean
description: string
action: () => void
}
// 快捷键管理组合式函数
export function useKeyboard(shortcuts: KeyboardShortcut[]) {
const activeKeys = ref<Set<string>>(new Set())
const handleKeyDown = (event: KeyboardEvent) => {
activeKeys.value.add(event.key.toLowerCase())
for (const shortcut of shortcuts) {
const keyMatch = event.key.toLowerCase() === shortcut.key.toLowerCase()
const ctrlMatch = !!shortcut.ctrl === (event.ctrlKey || event.metaKey)
const shiftMatch = !!shortcut.shift === event.shiftKey
const altMatch = !!shortcut.alt === event.altKey
if (keyMatch && ctrlMatch && shiftMatch && altMatch) {
// 排除在输入框中的部分快捷键
const target = event.target as HTMLElement
const isInput = target.tagName === 'INPUT' ||
target.tagName === 'TEXTAREA' ||
target.isContentEditable
// 这些快捷键在输入框中也生效
const globalShortcuts = ['Escape', 'Enter']
const needsModifier = shortcut.ctrl || shortcut.alt || shortcut.meta
if (isInput && !globalShortcuts.includes(shortcut.key) && !needsModifier) {
continue
}
event.preventDefault()
shortcut.action()
break
}
}
}
const handleKeyUp = (event: KeyboardEvent) => {
activeKeys.value.delete(event.key.toLowerCase())
}
onMounted(() => {
window.addEventListener('keydown', handleKeyDown)
window.addEventListener('keyup', handleKeyUp)
})
onUnmounted(() => {
window.removeEventListener('keydown', handleKeyDown)
window.removeEventListener('keyup', handleKeyUp)
})
return {
activeKeys,
}
}
// 预定义的快捷键配置
export function getDefaultShortcuts(actions: {
newChat: () => void
toggleSidebar: () => void
focusInput: () => void
sendMessage: () => void
cancelStream: () => void
toggleTheme: () => void
showShortcuts: () => void
searchConversations: () => void
}): KeyboardShortcut[] {
return [
{
key: 'n',
ctrl: true,
description: '新建对话',
action: actions.newChat,
},
{
key: 'b',
ctrl: true,
description: '切换侧边栏',
action: actions.toggleSidebar,
},
{
key: '/',
ctrl: true,
description: '聚焦输入框',
action: actions.focusInput,
},
{
key: 'Enter',
ctrl: true,
description: '发送消息',
action: actions.sendMessage,
},
{
key: 'Escape',
description: '取消生成',
action: actions.cancelStream,
},
{
key: 'd',
ctrl: true,
shift: true,
description: '切换主题',
action: actions.toggleTheme,
},
{
key: '?',
ctrl: true,
description: '显示快捷键',
action: actions.showShortcuts,
},
{
key: 'k',
ctrl: true,
description: '搜索对话',
action: actions.searchConversations,
},
]
}