Files
AX-Copilot/src/AxCopilot/Core/HotkeyParser.cs

128 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace AxCopilot.Core;
/// <summary>
/// "Alt+Space", "Ctrl+Shift+K" 형식의 핫키 문자열 파싱/포맷 유틸리티.
/// </summary>
public static class HotkeyParser
{
private static readonly Dictionary<string, int> _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()
{
// AZ
for (char c = 'A'; c <= 'Z'; c++)
_keyMap[c.ToString()] = c;
// 09
for (char c = '0'; c <= '9'; c++)
_keyMap[c.ToString()] = c;
// F1F24
for (int i = 1; i <= 24; i++)
_keyMap[$"F{i}"] = 0x6F + i;
// Numpad 09
for (int i = 0; i <= 9; i++)
_keyMap[$"Num{i}"] = 0x60 + i;
}
/// <summary>
/// "Alt+Space" → <see cref="HotkeyDefinition"/>. 실패 시 false 반환.
/// </summary>
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;
}
/// <summary>
/// <see cref="HotkeyDefinition"/> → "Alt+Space" 형식 문자열.
/// </summary>
public static string Format(HotkeyDefinition def)
{
var parts = new List<string>(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(); // AZ
if (vk >= 0x30 && vk <= 0x39) return ((char)vk).ToString(); // 09
if (vk >= 0x70 && vk <= 0x87) return $"F{vk - 0x6F}"; // F1F24
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}";
}
}
/// <summary>
/// 파싱된 핫키 정의. VK 코드 + 요구 수정자 키.
/// </summary>
public record struct HotkeyDefinition(int VkCode, bool Ctrl, bool Alt, bool Shift, bool Win);