134 lines
3.2 KiB
TypeScript
134 lines
3.2 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,
|
|
},
|
|
];
|
|
}
|