namespace MeetingAssistant.Hotkeys; [Flags] public enum HotkeyModifiers : uint { None = 0, Alt = 0x0001, Control = 0x0002, Shift = 0x0004, Windows = 0x0008 } public sealed record HotkeyDefinition(HotkeyModifiers Modifiers, uint VirtualKey) { public static HotkeyDefinition Parse(string value) { if (string.IsNullOrWhiteSpace(value)) { throw new ArgumentException("Hotkey cannot be empty.", nameof(value)); } var modifiers = HotkeyModifiers.None; uint? virtualKey = null; foreach (var rawPart in value.Split('+', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) { var part = rawPart.ToUpperInvariant(); modifiers |= part switch { "CTRL" or "CONTROL" => HotkeyModifiers.Control, "ALT" => HotkeyModifiers.Alt, "SHIFT" => HotkeyModifiers.Shift, "WIN" or "WINDOWS" => HotkeyModifiers.Windows, _ => HotkeyModifiers.None }; if (modifiers.HasFlagForToken(part)) { continue; } virtualKey = ParseVirtualKey(part); } return virtualKey is null ? throw new FormatException($"Hotkey '{value}' does not contain a key.") : new HotkeyDefinition(modifiers, virtualKey.Value); } private static uint ParseVirtualKey(string part) { if (part.Length == 1 && char.IsLetterOrDigit(part[0])) { return part[0]; } if (part.Length is 2 or 3 && part[0] == 'F' && int.TryParse(part[1..], out var functionKey) && functionKey is >= 1 and <= 24) { return (uint)(0x70 + functionKey - 1); } throw new FormatException($"Unsupported hotkey key '{part}'."); } } file static class HotkeyModifierExtensions { public static bool HasFlagForToken(this HotkeyModifiers _, string token) { return token is "CTRL" or "CONTROL" or "ALT" or "SHIFT" or "WIN" or "WINDOWS"; } }