3대 근본 버그 수정 (RE 조사 기반)
1. HotkeyService: modifier 먼저 놓기 대응 - Alt+1에서 Alt를 먼저 놓아도 release 감지 - _handleKeyUp에서 pressed 핫키의 구성 키(main/modifier) 매칭 2. ResultPopup auto-close IPC 핸들러 추가 - window:hideResultPopup 핸들러가 없어서 팝업이 안 꺼지던 버그 - window-handlers.ts에 hideResultPopup/hideRecordingTip 핸들러 등록 3. bootstrap.ts 이중 팝업 제어 제거 - session-completed에서 무조건 showResultPopup 호출하던 코드 제거 - 팝업 제어는 VoiceModeService 내부에서만 처리 - bootstrap은 효과음만 담당
This commit is contained in:
parent
788600b66b
commit
c64ab3b58f
3 changed files with 49 additions and 29 deletions
|
|
@ -398,17 +398,36 @@ class HotkeyService extends EventEmitter {
|
|||
|
||||
/**
|
||||
* 키 업 이벤트를 처리한다.
|
||||
* Alt+1 같은 조합에서 Alt를 먼저 놓아도 release 감지해야 한다.
|
||||
* 전략: pressed 상태인 핫키 중 구성 키(main key 또는 modifier)가 놓아지면 release.
|
||||
*/
|
||||
private _handleKeyUp(e: UiohookKeyboardEvent): void {
|
||||
// 방법 1: 정확한 매칭 시도
|
||||
const matched = this._findMatchingHotkey(e)
|
||||
if (!matched) return
|
||||
|
||||
const { id } = matched
|
||||
|
||||
// 눌려있지 않은 키의 release는 무시
|
||||
if (!this._isKeyDown.get(id)) {
|
||||
if (matched && this._isKeyDown.get(matched.id)) {
|
||||
this._fireRelease(matched)
|
||||
return
|
||||
}
|
||||
|
||||
// 방법 2: 현재 pressed인 핫키 중 구성 키가 놓아진 경우 (modifier 먼저 놓기 대응)
|
||||
for (const config of this._registeredHotkeys.values()) {
|
||||
if (!this._isKeyDown.get(config.id)) continue
|
||||
|
||||
// 놓아진 키가 이 핫키의 main key인가?
|
||||
const isMainKey = e.keycode === config.keyCode
|
||||
// 놓아진 키가 이 핫키의 modifier 중 하나인가?
|
||||
const isModifier = this._isEventModifierOf(e, config)
|
||||
|
||||
if (isMainKey || isModifier) {
|
||||
this._fireRelease(config)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** pressed 핫키의 release 이벤트 발행 */
|
||||
private _fireRelease(config: HotkeyConfig): void {
|
||||
const { id } = config
|
||||
this._isKeyDown.set(id, false)
|
||||
|
||||
const now = Date.now()
|
||||
|
|
@ -418,12 +437,24 @@ class HotkeyService extends EventEmitter {
|
|||
|
||||
logger.debug(`Hotkey released: "${id}" (duration=${durationMs}ms)`)
|
||||
this.emit('hotkey-released', {
|
||||
config: matched,
|
||||
config,
|
||||
durationMs,
|
||||
timestamp: now
|
||||
})
|
||||
}
|
||||
|
||||
/** 키 이벤트가 핫키의 modifier 구성요소인지 확인 */
|
||||
private _isEventModifierOf(e: UiohookKeyboardEvent, config: HotkeyConfig): boolean {
|
||||
const modifiers = config.modifiers ?? []
|
||||
for (const mod of modifiers) {
|
||||
if (mod === 'ctrl' && (this._isCtrlKeyCode(e.keycode))) return true
|
||||
if (mod === 'alt' && (this._isAltKeyCode(e.keycode))) return true
|
||||
if (mod === 'shift' && (this._isShiftKeyCode(e.keycode))) return true
|
||||
if (mod === 'meta' && (this._isMetaKeyCode(e.keycode))) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* uiohook 키 이벤트와 등록된 핫키를 매칭한다.
|
||||
* 키코드와 수정자 키가 모두 일치해야 매칭 성공.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue