M0-M11 狩夜人笔记初始实现:11里程碑+86测试

This commit is contained in:
hunter-dev
2026-08-24 20:35:22 +08:00
commit 3ebd33536b
106 changed files with 10490 additions and 0 deletions
@@ -0,0 +1,33 @@
// KeymapService — 快捷键绑定管理 + 冲突检测(FR-K3/K4/K5)
export type Scope = 'global' | 'app' | 'editor';
export interface Binding { id: string; scope: Scope; combo: string; defaultCombo: string; }
export class KeymapService {
private bindings = new Map<string, Binding>();
register(b: Binding) { this.bindings.set(b.id, b); }
setCombo(id: string, combo: string) {
const b = this.bindings.get(id); if (b) this.bindings.set(id, { ...b, combo });
}
resetAll() { for (const [id, b] of this.bindings) this.bindings.set(id, { ...b, combo: b.defaultCombo }); }
getAll(): Binding[] { return [...this.bindings.values()]; }
// 冲突检测:同一 combo 绑定到多个 action(不同 id)即冲突
conflicts(): Record<string, string[]> {
const byCombo = new Map<string, string[]>();
for (const b of this.bindings.values()) {
const arr = byCombo.get(b.combo) ?? []; arr.push(b.id); byCombo.set(b.combo, arr);
}
const out: Record<string, string[]> = {};
for (const [combo, ids] of byCombo) if (ids.length > 1) out[combo] = ids;
return out;
}
conflictCount(): number { return Object.keys(this.conflicts()).length; }
// 作用域裁决:给定当前是否编辑器聚焦,返回某 combo 应触发哪个 binding(编辑器聚焦时 global 让位规则按需)
resolve(combo: string, editorFocused: boolean): Binding | null {
const matches = [...this.bindings.values()].filter(b => b.combo === combo);
if (matches.length === 0) return null;
// 优先 editor(编辑器聚焦时),再 app,再 global
if (editorFocused) { const e = matches.find(m => m.scope === 'editor'); if (e) return e; }
return matches.find(m => m.scope === 'global') ?? matches[0];
}
}