namespace AxCopilot.Core; /// /// "Alt+Space", "Ctrl+Shift+K" 형식의 핫키 문자열 파싱/포맷 유틸리티. /// public static class HotkeyParser { private static readonly Dictionary _keyMap = new(StringComparer.OrdinalIgnoreCase) { // 특수키 ["Space"] = 0x20, ["Enter"] = 0x0D, ["Return"] = 0x0D, ["Tab"] = 0x09, ["Esc"] = 0x1B, ["Escape"] = 0x1B, ["Backspace"]= 0x08, ["Back"] = 0x08, ["Delete"] = 0x2E, ["Del"] = 0x2E, ["Insert"] = 0x2D, ["Ins"] = 0x2D, ["Home"] = 0x24, ["End"] = 0x23, ["PageUp"] = 0x21, ["PgUp"] = 0x21, ["PageDown"] = 0x22, ["PgDn"] = 0x22, ["PrintScreen"] = 0x2C, ["PrtSc"] = 0x2C, ["Snapshot"] = 0x2C, ["Pause"] = 0x13, ["Break"] = 0x13, ["ScrollLock"] = 0x91, // 방향키 ["Left"] = 0x25, ["Up"] = 0x26, ["Right"] = 0x27, ["Down"] = 0x28, // 기호 ["`"] = 0xC0, ["Grave"] = 0xC0, ["-"] = 0xBD, ["="] = 0xBB, ["["] = 0xDB, ["]"] = 0xDD, ["\\"] = 0xDC, [";"] = 0xBA, ["'"] = 0xDE, [","] = 0xBC, ["."] = 0xBE, ["/"] = 0xBF, }; static HotkeyParser() { // A–Z for (char c = 'A'; c <= 'Z'; c++) _keyMap[c.ToString()] = c; // 0–9 for (char c = '0'; c <= '9'; c++) _keyMap[c.ToString()] = c; // F1–F24 for (int i = 1; i <= 24; i++) _keyMap[$"F{i}"] = 0x6F + i; // Numpad 0–9 for (int i = 0; i <= 9; i++) _keyMap[$"Num{i}"] = 0x60 + i; } /// /// "Alt+Space" → . 실패 시 false 반환. /// public static bool TryParse(string hotkey, out HotkeyDefinition result) { result = default; if (string.IsNullOrWhiteSpace(hotkey)) return false; var parts = hotkey.Split('+', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); bool ctrl = false, alt = false, shift = false, win = false; int? vkCode = null; foreach (var p in parts) { if (p.Equals("Ctrl", StringComparison.OrdinalIgnoreCase) || p.Equals("Control", StringComparison.OrdinalIgnoreCase)) { ctrl = true; continue; } if (p.Equals("Alt", StringComparison.OrdinalIgnoreCase)) { alt = true; continue; } if (p.Equals("Shift", StringComparison.OrdinalIgnoreCase)) { shift = true; continue; } if (p.Equals("Win", StringComparison.OrdinalIgnoreCase) || p.Equals("Windows", StringComparison.OrdinalIgnoreCase)) { win = true; continue; } if (_keyMap.TryGetValue(p, out int vk)) vkCode = vk; else return false; // 알 수 없는 키 } if (vkCode == null) return false; result = new HotkeyDefinition(vkCode.Value, ctrl, alt, shift, win); return true; } /// /// → "Alt+Space" 형식 문자열. /// public static string Format(HotkeyDefinition def) { var parts = new List(5); if (def.Ctrl) parts.Add("Ctrl"); if (def.Alt) parts.Add("Alt"); if (def.Shift) parts.Add("Shift"); if (def.Win) parts.Add("Win"); parts.Add(VkToName(def.VkCode)); return string.Join("+", parts); } // VK 코드 → 읽기 좋은 이름 변환 private static string VkToName(int vk) { if (vk >= 0x41 && vk <= 0x5A) return ((char)vk).ToString(); // A–Z if (vk >= 0x30 && vk <= 0x39) return ((char)vk).ToString(); // 0–9 if (vk >= 0x70 && vk <= 0x87) return $"F{vk - 0x6F}"; // F1–F24 if (vk >= 0x60 && vk <= 0x69) return $"Num{vk - 0x60}"; // Numpad // 특수키 테이블에서 긴 이름 우선 검색 string? best = null; foreach (var (name, code) in _keyMap) { if (code == vk && (best == null || name.Length > best.Length)) best = name; } return best ?? $"0x{vk:X2}"; } } /// /// 파싱된 핫키 정의. VK 코드 + 요구 수정자 키. /// public record struct HotkeyDefinition(int VkCode, bool Ctrl, bool Alt, bool Shift, bool Win);