다른 앱 타이핑 시에도 AX Copilot가 과하게 개입하던 글로벌 키보드 훅의 핫패스를 줄였다. InputListener는 모든 키마다 파일 대화상자 억제 창 검사를 하지 않고 실제 핫키·캡처·키필터 후보 키에서만 검사하도록 최적화했다. SnippetExpander는 추적 중이 아닐 때 ';' 시작 키 외에는 즉시 반환하게 바꿔 일반 타이핑 중 반복적인 modifier 상태 확인과 버퍼 처리를 제거했다. README와 DEVELOPMENT 문서를 2026-04-06 18:34 (KST) 기준으로 갱신했고, Release 빌드 검증에서 경고 0 / 오류 0을 확인했다.
This commit is contained in:
@@ -177,12 +177,17 @@ public class InputListener : IDisposable
|
||||
if (wParam != WM_KEYDOWN && wParam != WM_SYSKEYDOWN)
|
||||
return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
|
||||
|
||||
var isHotkeyMainKey = vkCode == _hotkey.VkCode;
|
||||
var isCaptureMainKey = _captureHotkeyEnabled && vkCode == _captureHotkey.VkCode;
|
||||
var shouldRunKeyFilter = KeyFilter != null;
|
||||
var needsSuppressedWindowCheck = isHotkeyMainKey || isCaptureMainKey || shouldRunKeyFilter;
|
||||
|
||||
// ─── 시스템 파일 대화상자에서는 핫키·스니펫 전부 비활성 ──────────────
|
||||
if (IsSuppressedForegroundWindow())
|
||||
if (needsSuppressedWindowCheck && IsSuppressedForegroundWindow())
|
||||
return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
|
||||
|
||||
// ─── 핫키 감지 ──────────────────────────────────────────────────────
|
||||
if (!SuspendHotkey && vkCode == _hotkey.VkCode)
|
||||
if (!SuspendHotkey && isHotkeyMainKey)
|
||||
{
|
||||
bool ctrlOk = !_hotkey.Ctrl || (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;
|
||||
bool altOk = !_hotkey.Alt || (GetAsyncKeyState(VK_MENU) & 0x8000) != 0;
|
||||
@@ -202,7 +207,7 @@ public class InputListener : IDisposable
|
||||
}
|
||||
|
||||
// ─── 글로벌 캡처 단축키 감지 ─────────────────────────────────────────
|
||||
if (!SuspendHotkey && _captureHotkeyEnabled && vkCode == _captureHotkey.VkCode)
|
||||
if (!SuspendHotkey && isCaptureMainKey)
|
||||
{
|
||||
bool ctrlOk = !_captureHotkey.Ctrl || (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;
|
||||
bool altOk = !_captureHotkey.Alt || (GetAsyncKeyState(VK_MENU) & 0x8000) != 0;
|
||||
@@ -221,7 +226,7 @@ public class InputListener : IDisposable
|
||||
}
|
||||
|
||||
// ─── 스니펫 키 필터 ─────────────────────────────────────────────────
|
||||
if (KeyFilter?.Invoke(vkCode) == true)
|
||||
if (shouldRunKeyFilter && KeyFilter?.Invoke(vkCode) == true)
|
||||
return (IntPtr)1;
|
||||
|
||||
return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
|
||||
|
||||
@@ -49,20 +49,30 @@ public class SnippetExpander
|
||||
// 자동 확장 비활성화 시 즉시 통과
|
||||
if (!_settings.Settings.Launcher.SnippetAutoExpand) return false;
|
||||
|
||||
// Ctrl/Alt 조합은 무시 (단축키와 충돌 방지)
|
||||
if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) { _tracking = false; _buffer.Clear(); return false; }
|
||||
if ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0) { _tracking = false; _buffer.Clear(); return false; }
|
||||
|
||||
// ─── 트리거 시작: ';' 입력 ──────────────────────────────────────────
|
||||
if (vkCode == VK_OEM_1 && (GetAsyncKeyState(VK_SHIFT) & 0x8000) == 0)
|
||||
// 추적 중이 아닐 때는 ';' 시작 키만 검사해서 훅 경로 부담을 최소화합니다.
|
||||
if (!_tracking)
|
||||
{
|
||||
if (vkCode != VK_OEM_1)
|
||||
return false;
|
||||
|
||||
if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0)
|
||||
return false;
|
||||
|
||||
if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0)
|
||||
return false;
|
||||
|
||||
if ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0)
|
||||
return false;
|
||||
|
||||
_tracking = true;
|
||||
_buffer.Clear();
|
||||
_buffer.Append(';');
|
||||
return false; // ';'는 소비하지 않고 앱으로 전달
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_tracking) return false;
|
||||
// Ctrl/Alt 조합은 무시 (단축키와 충돌 방지)
|
||||
if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) { _tracking = false; _buffer.Clear(); return false; }
|
||||
if ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0) { _tracking = false; _buffer.Clear(); return false; }
|
||||
|
||||
// ─── 영문자/숫자 — 버퍼에 추가 ─────────────────────────────────────
|
||||
if ((vkCode >= 0x41 && vkCode <= 0x5A) || // A-Z
|
||||
|
||||
Reference in New Issue
Block a user