fix(keybinding): stop stealing chords on Windows, release mouse holds, keep cleared actions
This commit is contained in:
parent
115e8488ac
commit
1a4c39cb94
8 changed files with 927 additions and 148 deletions
|
|
@ -1248,7 +1248,13 @@ export function parseBindingList(value: unknown): KeyBinding[] {
|
|||
return out
|
||||
}
|
||||
|
||||
/** 저장된 전체 맵을 복원한다. 누락·손상 액션은 기본값으로 채운다. */
|
||||
/**
|
||||
* 저장된 전체 맵을 복원한다 (옛 의미). 누락·손상 액션 **과 명시적 빈 목록** 을 기본값으로 채운다.
|
||||
*
|
||||
* @deprecated 저장소를 읽는 경로는 `decodeKeyBindingMap` 을 쓴다. 이 함수는 사용자가 지운
|
||||
* 액션(`[]`)을 기본값으로 되살리므로, 저장값을 읽고 다시 쓰는 곳에서 쓰면 지운 단축키가
|
||||
* 되돌아온다. 옛 호출부 호환을 위해서만 남긴다.
|
||||
*/
|
||||
export function parseBindingMap(value: unknown): KeyBindingMap {
|
||||
const defaults = createDefaultBindingMap()
|
||||
if (!isRecord(value)) return defaults
|
||||
|
|
@ -1260,3 +1266,85 @@ export function parseBindingMap(value: unknown): KeyBindingMap {
|
|||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 저장 코덱 — 저장된 keyBindings 를 읽는 단일 정본
|
||||
// ============================================================
|
||||
|
||||
/** 액션 하나의 저장값을 해석한 결과 */
|
||||
type StoredListState =
|
||||
/** 저장값 그대로 쓸 수 있다 */
|
||||
| 'intact'
|
||||
/** 유효 항목은 있지만 손상·중복 항목을 버렸거나 정규화로 모양이 바뀌었다 */
|
||||
| 'normalized'
|
||||
/** 누락·배열 아님·전부 손상 — 기본값으로 복구했다 */
|
||||
| 'repaired'
|
||||
|
||||
function sameStoredShape(stored: KeyBinding, decoded: KeyBinding): boolean {
|
||||
return (
|
||||
stored.device === decoded.device &&
|
||||
stored.code === decoded.code &&
|
||||
stored.ctrl === decoded.ctrl &&
|
||||
stored.alt === decoded.alt &&
|
||||
stored.shift === decoded.shift &&
|
||||
stored.meta === decoded.meta
|
||||
)
|
||||
}
|
||||
|
||||
function decodeBindingList(
|
||||
value: unknown,
|
||||
fallback: readonly KeyBinding[]
|
||||
): { bindings: KeyBinding[]; state: StoredListState } {
|
||||
const repaired = (): { bindings: KeyBinding[]; state: StoredListState } => ({
|
||||
bindings: fallback.map((b) => ({ ...b })),
|
||||
state: 'repaired'
|
||||
})
|
||||
if (!Array.isArray(value)) return repaired()
|
||||
// 명시적 빈 목록 = 사용자가 이 액션의 단축키를 모두 지웠다. 기본값으로 되살리지 않는다.
|
||||
if (value.length === 0) return { bindings: [], state: 'intact' }
|
||||
|
||||
const bindings = parseBindingList(value)
|
||||
// 비어 있지 않았는데 쓸 만한 항목이 하나도 없다 = 손상. 기본값으로 복구한다.
|
||||
if (bindings.length === 0) return repaired()
|
||||
|
||||
const intact =
|
||||
bindings.length === value.length &&
|
||||
bindings.every((binding, index) => {
|
||||
const stored: unknown = value[index]
|
||||
return isKeyBinding(stored) && sameStoredShape(stored, binding)
|
||||
})
|
||||
return { bindings, state: intact ? 'intact' : 'normalized' }
|
||||
}
|
||||
|
||||
/** `decodeKeyBindingMap` 결과 */
|
||||
export interface DecodedKeyBindingMap {
|
||||
/** 모든 액션 키를 가진 정규화된 맵. 명시적 빈 목록은 빈 목록 그대로다. */
|
||||
map: KeyBindingMap
|
||||
/** 저장값이 없거나(새 액션 포함) 손상되어 기본값으로 채운 액션 */
|
||||
repairedActions: KeyBindingActionId[]
|
||||
/** 결과가 저장된 모양과 달라 다시 써야 하는지 (복구 · 손상 항목 제거 · 정규화) */
|
||||
needsRewrite: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* 저장된 keyBindings 를 엄격하게 해석한다 — 저장소를 읽는 모든 경로(설정 로딩 · IPC ·
|
||||
* 마이그레이션 · 후킹 서비스)의 단일 정본.
|
||||
*
|
||||
* - 명시적 빈 목록(`[]`)은 "이 액션은 단축키 없음" 으로 보존한다.
|
||||
* - 누락 · 배열 아님 · 비어 있지 않은데 유효 항목이 없는 액션만 기본값으로 복구한다.
|
||||
* - 유효 항목은 정규화하고 중복을 없앤다. 알 수 없는 액션 키는 버린다.
|
||||
*/
|
||||
export function decodeKeyBindingMap(value: unknown): DecodedKeyBindingMap {
|
||||
const record = isRecord(value) && !Array.isArray(value) ? value : null
|
||||
const map = {} as KeyBindingMap
|
||||
const repairedActions: KeyBindingActionId[] = []
|
||||
let needsRewrite = record === null
|
||||
|
||||
for (const action of KEYBINDING_ACTIONS) {
|
||||
const decoded = decodeBindingList(record?.[action.id], action.defaultBindings)
|
||||
map[action.id] = decoded.bindings
|
||||
if (decoded.state === 'repaired') repairedActions.push(action.id)
|
||||
if (decoded.state !== 'intact') needsRewrite = true
|
||||
}
|
||||
return { map, repairedActions, needsRewrite }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue