diff --git a/src/main/bootstrap.ts b/src/main/bootstrap.ts index f1a7d17..c49a729 100644 --- a/src/main/bootstrap.ts +++ b/src/main/bootstrap.ts @@ -117,11 +117,49 @@ async function initPopupWindows(): Promise { globalShortcut.register('Ctrl+Shift+V', () => { if (isHistoryPopupVisible()) { hideHistoryPopup() + unregisterPopupNavKeys() } else { const entries = getHistoryService().list({ page: 0, pageSize: 10 }).entries showHistoryPopup(entries as unknown as Array>) + registerPopupNavKeys() } }) + +} + +// 히스토리 팝업 키 네비게이션 등록/해제 +const POPUP_NAV_KEYS: Array<{ accel: string; key: string }> = [ + { accel: 'Up', key: 'ArrowUp' }, + { accel: 'Down', key: 'ArrowDown' }, + { accel: 'Return', key: 'Enter' }, + { accel: 'Escape', key: 'Escape' }, + { accel: '1', key: '1' }, { accel: '2', key: '2' }, { accel: '3', key: '3' }, + { accel: '4', key: '4' }, { accel: '5', key: '5' }, { accel: '6', key: '6' }, + { accel: '7', key: '7' }, { accel: '8', key: '8' }, { accel: '9', key: '9' }, +] + +function registerPopupNavKeys(): void { + for (const { accel, key } of POPUP_NAV_KEYS) { + try { + globalShortcut.register(accel, () => { + if (isHistoryPopupVisible()) { + sendKeyToHistoryPopup(key) + } + }) + } catch { + // 일부 키는 globalShortcut으로 등록 불가할 수 있음 + } + } +} + +function unregisterPopupNavKeys(): void { + for (const { accel } of POPUP_NAV_KEYS) { + try { + globalShortcut.unregister(accel) + } catch { + // 이미 해제된 경우 무시 + } + } } async function initVoiceMode(): Promise { @@ -188,6 +226,7 @@ function setupHistoryPopupIPC(): void { // 아이템 선택 → 텍스트 삽입 ipcMainRef.on('history:itemSelected', (_event: Electron.IpcMainEvent, data: { text: string }) => { hideHistoryPopup() + unregisterPopupNavKeys() setTimeout(async () => { try { await getTextInsertService().insertText(data.text) @@ -200,5 +239,6 @@ function setupHistoryPopupIPC(): void { // 팝업 닫기 ipcMainRef.on('history:popupDismissed', () => { hideHistoryPopup() + unregisterPopupNavKeys() }) } diff --git a/src/main/windows/WindowManager.ts b/src/main/windows/WindowManager.ts index f7fc811..1f88d99 100644 --- a/src/main/windows/WindowManager.ts +++ b/src/main/windows/WindowManager.ts @@ -308,32 +308,30 @@ export function getHistoryPopupWindow(): BrowserWindow { export function showHistoryPopup(entries: Array>): void { const win = getHistoryPopupWindow() - win.webContents.send('history:showItems', { entries }) + // 커서 위치에 즉시 배치+표시 (2-phase 제거 — 숨겨진 윈도우 렌더러 비활성 문제 방지) + const cursorPos = screen.getCursorScreenPoint() + const display = screen.getDisplayNearestPoint(cursorPos) - const handler = (_event: Electron.IpcMainEvent, data: { width: number; height: number }) => { - ipcMain.removeListener('history:popupMeasured', handler) + const popupWidth = 380 + const popupHeight = Math.min(60 + entries.length * 44, 500) - const cursorPos = screen.getCursorScreenPoint() - const display = screen.getDisplayNearestPoint(cursorPos) + let x = cursorPos.x - Math.round(popupWidth / 2) + let y = cursorPos.y - popupHeight - 20 - let x = cursorPos.x - Math.round(data.width / 2) - let y = cursorPos.y - data.height - 20 - - x = Math.max(display.workArea.x, Math.min(x, display.workArea.x + display.workArea.width - data.width)) - if (y < display.workArea.y) { - y = cursorPos.y + 20 - } - - win.setBounds({ x, y, width: data.width, height: data.height }) - - if (!win.isVisible()) { - win.showInactive() - } - - win.webContents.send('history:show', {}) + x = Math.max(display.workArea.x, Math.min(x, display.workArea.x + display.workArea.width - popupWidth)) + if (y < display.workArea.y) { + y = cursorPos.y + 20 } - ipcMain.on('history:popupMeasured', handler) + win.setBounds({ x, y, width: popupWidth, height: popupHeight }) + + win.webContents.send('history:showItems', { entries }) + + if (!win.isVisible()) { + win.showInactive() + } + + win.webContents.send('history:show', {}) } export function hideHistoryPopup(): void {