[Phase L5-1] 항목별 전용 핫키 기능 구현

HotkeyAssignment 모델 추가 (AppSettings.Models.cs):
- Hotkey, Target, Label, Type 필드 (app/url/folder/command)
- AppSettings.CustomHotkeys (List<HotkeyAssignment>) 추가

InputListener.cs 확장 (Core/):
- _customHotkeys 목록 (스레드 안전 lock)
- UpdateCustomHotkeys() 메서드 — 설정 저장 후 즉시 갱신
- CustomHotkeyTriggered 이벤트 (CustomHotkeyEventArgs: Target, Type)
- WH_KEYBOARD_LL 콜백에 전용 핫키 감지 분기 추가

HotkeyHandler.cs 신규 생성 (Handlers/, 140줄):
- prefix="hotkey" — 등록 목록 표시 / 설정 열기
- ExecuteHotkeyTarget() — app/url/folder/command 타입별 실행

App.xaml.cs + App.Settings.cs:
- HotkeyHandler 등록 (Phase L5 주석)
- OnCustomHotkeyTriggered 이벤트 핸들러 연결
- 설정 저장 시 UpdateCustomHotkeys() 호출

SettingsViewModel 3파일 업데이트:
- HotkeyRowModel (Properties.cs): Hotkey/Target/Label/Type + TypeSymbol
- CustomHotkeys ObservableCollection + New* 필드 (Properties.cs)
- AddCustomHotkey() / RemoveCustomHotkey() 메서드 (Methods.cs)
  - HotkeyParser 형식 검증, 중복 핫키 방지
- Load/Save에 CustomHotkeys 매핑 (SettingsViewModel.cs, Methods.cs)

SettingsWindow.xaml + .xaml.cs:
- "전용 핫키" 탭 신규 추가 (배치 명령 탭 다음)
  - 안내 배너, 입력 폼 (핫키 레코더 + 표시이름 + 타입 + 대상)
  - 핫키 목록 (배지 + 타입아이콘 + 이름/경로 + 삭제 버튼)
- HotkeyRecord_Click: 클릭 후 키 입력 → 자동 핫키 감지 (PreviewKeyDown)
- AddHotkey_Click, RemoveHotkey_Click, BrowseHotkeyTarget_Click 핸들러

docs/LAUNCHER_ROADMAP.md:
- L5-1  완료 표시, 구현 내용 업데이트

빌드: 경고 0, 오류 0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 12:12:32 +09:00
parent e103a3a65a
commit c12e863e3a
13 changed files with 635 additions and 1 deletions

View File

@@ -177,6 +177,10 @@ public partial class App : System.Windows.Application
// Phase L4-1: 인라인 파일 탐색기 (Prefix=null, 경로 패턴 감지)
commandResolver.RegisterHandler(new FileBrowserHandler());
// ─── Phase L5 핸들러 ──────────────────────────────────────────────────
// Phase L5-1: 전용 핫키 목록 관리 (prefix=hotkey)
commandResolver.RegisterHandler(new HotkeyHandler(settings));
// ─── 플러그인 로드 ────────────────────────────────────────────────────
var pluginHost = new PluginHost(settings, commandResolver);
pluginHost.LoadAll();
@@ -207,6 +211,7 @@ public partial class App : System.Windows.Application
_inputListener = new InputListener();
_inputListener.HotkeyTriggered += OnHotkeyTriggered;
_inputListener.CaptureHotkeyTriggered += OnCaptureHotkeyTriggered;
_inputListener.CustomHotkeyTriggered += OnCustomHotkeyTriggered;
_inputListener.HookFailed += OnHookFailed;
// 설정에 저장된 핫키로 초기화 (기본: Alt+Space)
@@ -217,6 +222,9 @@ public partial class App : System.Windows.Application
settings.Settings.ScreenCapture.GlobalHotkey,
settings.Settings.ScreenCapture.GlobalHotkeyEnabled);
// 항목별 전용 핫키 초기화
_inputListener.UpdateCustomHotkeys(settings.Settings.CustomHotkeys);
var snippetExpander = new SnippetExpander(settings);
_inputListener.KeyFilter = snippetExpander.HandleKey;
@@ -450,6 +458,12 @@ public partial class App : System.Windows.Application
});
}
private void OnCustomHotkeyTriggered(object? sender, Core.CustomHotkeyEventArgs e)
{
// 전용 핫키 발동: 런처를 열지 않고 대상을 직접 실행
Handlers.HotkeyHandler.ExecuteHotkeyTarget(e.Target, e.Type);
}
private void OnHookFailed(object? sender, EventArgs e)
{
Dispatcher.Invoke(() =>