14 phase updated
This commit is contained in:
parent
023714442d
commit
dd68fc9ccd
3 changed files with 1003 additions and 25 deletions
|
|
@ -85,6 +85,10 @@ export function HotkeyRecordModal({
|
|||
const [captured, setCaptured] = useState<Array<{ keyCode: number; name: string }> | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const pressedRef = useRef<Map<number, string>>(new Map())
|
||||
// modifier-only 확정을 위한 타이머 (Alt만 눌렀을 때 바로 확정하지 않고 잠시 대기)
|
||||
const modifierTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
// 가장 최근 pressedKeys 스냅샷 (타이머 콜백에서 stale closure 방지)
|
||||
const lastPressedRef = useRef<Array<{ keyCode: number; name: string }>>([])
|
||||
|
||||
// Modal 열릴 때 리셋
|
||||
useEffect(() => {
|
||||
|
|
@ -93,6 +97,11 @@ export function HotkeyRecordModal({
|
|||
setCaptured(null)
|
||||
setError(null)
|
||||
pressedRef.current.clear()
|
||||
lastPressedRef.current = []
|
||||
if (modifierTimerRef.current) {
|
||||
clearTimeout(modifierTimerRef.current)
|
||||
modifierTimerRef.current = null
|
||||
}
|
||||
}
|
||||
}, [open])
|
||||
|
||||
|
|
@ -101,6 +110,12 @@ export function HotkeyRecordModal({
|
|||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
// 새 키가 눌렸으므로 modifier-only 타이머 취소
|
||||
if (modifierTimerRef.current) {
|
||||
clearTimeout(modifierTimerRef.current)
|
||||
modifierTimerRef.current = null
|
||||
}
|
||||
|
||||
const keyCode = e.keyCode || e.which
|
||||
if (pressedRef.current.has(keyCode)) return
|
||||
|
||||
|
|
@ -109,8 +124,9 @@ export function HotkeyRecordModal({
|
|||
|
||||
const keys = Array.from(pressedRef.current.entries()).map(([kc, n]) => ({ keyCode: kc, name: n }))
|
||||
setPressedKeys(keys)
|
||||
lastPressedRef.current = keys
|
||||
|
||||
// modifier가 아닌 키가 눌리면 → 조합 확정
|
||||
// modifier가 아닌 키가 눌리면 → 조합 즉시 확정 (Alt+1, Ctrl+F5 등)
|
||||
if (!isModifier(keyCode)) {
|
||||
setCaptured(keys)
|
||||
}
|
||||
|
|
@ -122,14 +138,20 @@ export function HotkeyRecordModal({
|
|||
const keyCode = e.keyCode || e.which
|
||||
pressedRef.current.delete(keyCode)
|
||||
|
||||
// 모든 키를 놓았고 modifier만 눌렀었다면 → 단일 modifier 확정
|
||||
if (pressedRef.current.size === 0 && pressedKeys.length > 0 && pressedKeys.every(k => isModifier(k.keyCode))) {
|
||||
setCaptured(pressedKeys)
|
||||
// 모든 키를 놓았고 modifier만 눌렀었다면 → 500ms 대기 후 확정
|
||||
// 이 대기 시간 동안 추가 키를 누르면 타이머가 취소되어 조합키로 확장 가능
|
||||
if (pressedRef.current.size === 0 && lastPressedRef.current.length > 0 && lastPressedRef.current.every(k => isModifier(k.keyCode))) {
|
||||
if (modifierTimerRef.current) clearTimeout(modifierTimerRef.current)
|
||||
modifierTimerRef.current = setTimeout(() => {
|
||||
// 타이머 만료: 여전히 confirmed 안됐고 추가 키 입력 없으면 단일 modifier로 확정
|
||||
setCaptured(lastPressedRef.current)
|
||||
modifierTimerRef.current = null
|
||||
}, 500)
|
||||
}
|
||||
|
||||
const keys = Array.from(pressedRef.current.entries()).map(([kc, n]) => ({ keyCode: kc, name: n }))
|
||||
setPressedKeys(keys)
|
||||
}, [captured, pressedKeys])
|
||||
}, [captured])
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
|
|
@ -159,15 +181,27 @@ export function HotkeyRecordModal({
|
|||
}
|
||||
|
||||
// HotkeyBinding 생성
|
||||
// 주 키(main key) = modifier가 아닌 키가 있으면 그것, 없으면 첫 번째 modifier
|
||||
const mainKey = captured.find(k => !isModifier(k.keyCode))
|
||||
const primaryKeyCode = mainKey?.keyCode ?? captured[0].keyCode
|
||||
|
||||
// modifier 플래그: 주 키 자체가 해당 modifier인 경우 false 유지
|
||||
// 예: Right Alt 단독 → keyCode=165, alt=false (주 키가 Alt 자체이므로)
|
||||
// 예: Ctrl+A → keyCode=A, ctrl=true (Ctrl은 modifier로 사용)
|
||||
const isCtrlKey = (kc: number) => kc === 17 || kc === 162 || kc === 163
|
||||
const isAltKey = (kc: number) => kc === 18 || kc === 164 || kc === 165
|
||||
const isShiftKey = (kc: number) => kc === 16 || kc === 160 || kc === 161
|
||||
const isMetaKey = (kc: number) => kc === 91 || kc === 92
|
||||
|
||||
// 주 키를 제외한 나머지 키들만 modifier로 취급
|
||||
const modifierKeys = captured.filter(k => k.keyCode !== primaryKeyCode)
|
||||
|
||||
const binding: HotkeyBinding = {
|
||||
keyCode: primaryKeyCode,
|
||||
ctrl: captured.some(k => k.keyCode === 17 || k.keyCode === 162 || k.keyCode === 163),
|
||||
alt: captured.some(k => k.keyCode === 18 || k.keyCode === 164 || k.keyCode === 165),
|
||||
shift: captured.some(k => k.keyCode === 16 || k.keyCode === 160 || k.keyCode === 161),
|
||||
meta: captured.some(k => k.keyCode === 91 || k.keyCode === 92),
|
||||
ctrl: modifierKeys.some(k => isCtrlKey(k.keyCode)),
|
||||
alt: modifierKeys.some(k => isAltKey(k.keyCode)),
|
||||
shift: modifierKeys.some(k => isShiftKey(k.keyCode)),
|
||||
meta: modifierKeys.some(k => isMetaKey(k.keyCode)),
|
||||
displayLabel: label,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue