package hotkeys import ( "sort" "strings" ) // Category constants for hotkey organization const ( CategoryPlayback = "Playback" CategorySeeking = "Seeking" CategoryAudio = "Audio & Volume" CategorySubtitles = "Subtitles" CategoryVideo = "Video & Display" CategoryPlaylist = "Playlist" CategoryScreenshot = "Screenshots" CategoryAdvanced = "Advanced" CategoryMenu = "Menu Navigation" CategoryMultimedia = "Multimedia Keys" ) // Hotkey represents a single keyboard shortcut type Hotkey struct { ID string // Unique identifier Keys string // Key combination display (e.g., "SPACE / p") Description string // What the shortcut does Category string // Category for filtering Priority int // Higher = shown first within category Aliases []string // Search aliases } // Hotkeys contains all MPV keyboard shortcuts var Hotkeys = []Hotkey{ // Playback (highest priority - most common) {ID: "pause", Keys: "SPACE / p", Description: "Pause/Resume playback", Category: CategoryPlayback, Priority: 100, Aliases: []string{"play", "resume", "stop"}}, {ID: "quit", Keys: "q", Description: "Stop playing and quit", Category: CategoryPlayback, Priority: 100, Aliases: []string{"exit", "close"}}, {ID: "quit-save", Keys: "Q", Description: "Quit and save playback position (resume later)", Category: CategoryPlayback, Priority: 95, Aliases: []string{"exit", "save", "resume"}}, {ID: "mute", Keys: "m", Description: "Mute/unmute sound", Category: CategoryPlayback, Priority: 90, Aliases: []string{"sound", "volume"}}, {ID: "frame-forward", Keys: ".", Description: "Step forward one frame (pauses)", Category: CategoryPlayback, Priority: 70, Aliases: []string{"frame", "step", "next"}}, {ID: "frame-backward", Keys: ",", Description: "Step backward one frame (pauses)", Category: CategoryPlayback, Priority: 70, Aliases: []string{"frame", "step", "prev"}}, {ID: "ab-loop", Keys: "l", Description: "Set/clear A-B loop points", Category: CategoryPlayback, Priority: 60, Aliases: []string{"loop", "repeat", "ab"}}, {ID: "infinite-loop", Keys: "L", Description: "Toggle infinite looping", Category: CategoryPlayback, Priority: 60, Aliases: []string{"loop", "repeat"}}, // Seeking (very common) {ID: "seek-right", Keys: "→", Description: "Seek forward 5 seconds", Category: CategorySeeking, Priority: 100, Aliases: []string{"forward", "skip", "right"}}, {ID: "seek-left", Keys: "←", Description: "Seek backward 5 seconds", Category: CategorySeeking, Priority: 100, Aliases: []string{"backward", "back", "left"}}, {ID: "seek-right-exact", Keys: "Shift + →", Description: "Exact seek forward 1 second", Category: CategorySeeking, Priority: 90, Aliases: []string{"forward", "exact"}}, {ID: "seek-left-exact", Keys: "Shift + ←", Description: "Exact seek backward 1 second", Category: CategorySeeking, Priority: 90, Aliases: []string{"backward", "exact"}}, {ID: "seek-up", Keys: "↑", Description: "Seek forward 1 minute", Category: CategorySeeking, Priority: 85, Aliases: []string{"forward", "skip", "up"}}, {ID: "seek-down", Keys: "↓", Description: "Seek backward 1 minute", Category: CategorySeeking, Priority: 85, Aliases: []string{"backward", "down"}}, {ID: "seek-up-exact", Keys: "Shift + ↑", Description: "Exact seek forward 5 seconds", Category: CategorySeeking, Priority: 80, Aliases: []string{"forward", "exact"}}, {ID: "seek-down-exact", Keys: "Shift + ↓", Description: "Exact seek backward 5 seconds", Category: CategorySeeking, Priority: 80, Aliases: []string{"backward", "exact"}}, {ID: "seek-sub-next", Keys: "Ctrl + →", Description: "Seek to next subtitle", Category: CategorySeeking, Priority: 70, Aliases: []string{"subtitle", "next"}}, {ID: "seek-sub-prev", Keys: "Ctrl + ←", Description: "Seek to previous subtitle", Category: CategorySeeking, Priority: 70, Aliases: []string{"subtitle", "prev"}}, {ID: "sub-delay-next", Keys: "Ctrl + Shift + →", Description: "Adjust subtitle delay (next subtitle now)", Category: CategorySeeking, Priority: 60, Aliases: []string{"subtitle", "delay", "sync"}}, {ID: "sub-delay-prev", Keys: "Ctrl + Shift + ←", Description: "Adjust subtitle delay (previous subtitle now)", Category: CategorySeeking, Priority: 60, Aliases: []string{"subtitle", "delay", "sync"}}, {ID: "seek-home", Keys: "HOME", Description: "Seek to beginning of file", Category: CategorySeeking, Priority: 75, Aliases: []string{"start", "beginning"}}, {ID: "seek-chapter-prev", Keys: "PAGE UP", Description: "Seek to previous chapter", Category: CategorySeeking, Priority: 65, Aliases: []string{"chapter", "prev"}}, {ID: "seek-chapter-next", Keys: "PAGE DOWN", Description: "Seek to next chapter", Category: CategorySeeking, Priority: 65, Aliases: []string{"chapter", "next"}}, {ID: "seek-10min-back", Keys: "Shift + PAGE UP", Description: "Seek backward 10 minutes", Category: CategorySeeking, Priority: 55, Aliases: []string{"back", "skip"}}, {ID: "seek-10min-forward", Keys: "Shift + PAGE DOWN", Description: "Seek forward 10 minutes", Category: CategorySeeking, Priority: 55, Aliases: []string{"forward", "skip"}}, {ID: "undo-seek", Keys: "BACKSPACE", Description: "Undo last seek", Category: CategorySeeking, Priority: 50, Aliases: []string{"undo", "back"}}, {ID: "mark-position", Keys: "Shift + Ctrl + BACKSPACE", Description: "Mark current position for revert", Category: CategorySeeking, Priority: 45, Aliases: []string{"mark", "position"}}, {ID: "revert-seek", Keys: "Shift + BACKSPACE", Description: "Revert to marked position", Category: CategorySeeking, Priority: 45, Aliases: []string{"revert", "mark"}}, // Audio & Volume {ID: "volume-up", Keys: "9 / /", Description: "Decrease volume", Category: CategoryAudio, Priority: 90, Aliases: []string{"volume", "down", "quieter"}}, {ID: "volume-down", Keys: "0 / *", Description: "Increase volume", Category: CategoryAudio, Priority: 90, Aliases: []string{"volume", "up", "louder"}}, {ID: "audio-next", Keys: "#", Description: "Cycle through audio tracks", Category: CategoryAudio, Priority: 80, Aliases: []string{"audio", "track", "language"}}, {ID: "audio-delay-up", Keys: "Ctrl + +", Description: "Increase audio delay (A/V sync)", Category: CategoryAudio, Priority: 60, Aliases: []string{"audio", "delay", "sync"}}, {ID: "audio-delay-down", Keys: "Ctrl + -", Description: "Decrease audio delay (A/V sync)", Category: CategoryAudio, Priority: 60, Aliases: []string{"audio", "delay", "sync"}}, {ID: "speed-up", Keys: "]", Description: "Increase playback speed 10%", Category: CategoryAudio, Priority: 70, Aliases: []string{"speed", "faster"}}, {ID: "speed-down", Keys: "[", Description: "Decrease playback speed 10%", Category: CategoryAudio, Priority: 70, Aliases: []string{"speed", "slower"}}, {ID: "speed-double", Keys: "}", Description: "Double playback speed", Category: CategoryAudio, Priority: 65, Aliases: []string{"speed", "faster"}}, {ID: "speed-half", Keys: "{", Description: "Halve playback speed", Category: CategoryAudio, Priority: 65, Aliases: []string{"speed", "slower"}}, {ID: "speed-reset", Keys: "BACKSPACE", Description: "Reset playback speed to normal", Category: CategoryAudio, Priority: 75, Aliases: []string{"speed", "reset", "normal"}}, // Subtitles {ID: "subtitle-toggle", Keys: "v", Description: "Toggle subtitle visibility", Category: CategorySubtitles, Priority: 95, Aliases: []string{"subtitle", "hide", "show"}}, {ID: "subtitle-secondary-toggle", Keys: "Alt + v", Description: "Toggle secondary subtitle visibility", Category: CategorySubtitles, Priority: 80, Aliases: []string{"subtitle", "secondary"}}, {ID: "subtitle-next", Keys: "j / J", Description: "Cycle through subtitle tracks", Category: CategorySubtitles, Priority: 90, Aliases: []string{"subtitle", "track", "language"}}, {ID: "subtitle-delay-down", Keys: "z", Description: "Decrease subtitle delay 0.1s", Category: CategorySubtitles, Priority: 70, Aliases: []string{"subtitle", "delay", "sync"}}, {ID: "subtitle-delay-up", Keys: "Z", Description: "Increase subtitle delay 0.1s", Category: CategorySubtitles, Priority: 70, Aliases: []string{"subtitle", "delay", "sync"}}, {ID: "subtitle-size-up", Keys: "F", Description: "Increase subtitle font size 10%", Category: CategorySubtitles, Priority: 60, Aliases: []string{"subtitle", "font", "size", "bigger"}}, {ID: "subtitle-size-down", Keys: "G", Description: "Decrease subtitle font size 10%", Category: CategorySubtitles, Priority: 60, Aliases: []string{"subtitle", "font", "size", "smaller"}}, {ID: "subtitle-move-up", Keys: "r", Description: "Move subtitles up", Category: CategorySubtitles, Priority: 55, Aliases: []string{"subtitle", "position", "up"}}, {ID: "subtitle-move-down", Keys: "R", Description: "Move subtitles down", Category: CategorySubtitles, Priority: 55, Aliases: []string{"subtitle", "position", "down"}}, {ID: "subtitle-ass-override", Keys: "u", Description: "Toggle SSA/ASS subtitle style override", Category: CategorySubtitles, Priority: 50, Aliases: []string{"subtitle", "ass", "style"}}, {ID: "subtitle-ass-video", Keys: "V", Description: "Cycle video data used for ASS rendering", Category: CategorySubtitles, Priority: 45, Aliases: []string{"subtitle", "ass", "video"}}, // Video & Display {ID: "fullscreen", Keys: "f", Description: "Toggle fullscreen", Category: CategoryVideo, Priority: 100, Aliases: []string{"fullscreen", "window", "maximize"}}, {ID: "exit-fullscreen", Keys: "ESC", Description: "Exit fullscreen mode", Category: CategoryVideo, Priority: 95, Aliases: []string{"fullscreen", "exit", "escape"}}, {ID: "ontop", Keys: "T", Description: "Toggle stay-on-top", Category: CategoryVideo, Priority: 80, Aliases: []string{"window", "top", "always"}}, {ID: "panscan-up", Keys: "w", Description: "Decrease pan-and-scan range", Category: CategoryVideo, Priority: 50, Aliases: []string{"pan", "scan", "zoom"}}, {ID: "panscan-down", Keys: "W", Description: "Increase pan-and-scan range", Category: CategoryVideo, Priority: 50, Aliases: []string{"pan", "scan", "zoom"}}, {ID: "osd-progress", Keys: "o / P", Description: "Show progress bar and time on OSD", Category: CategoryVideo, Priority: 85, Aliases: []string{"osd", "progress", "time"}}, {ID: "osd-toggle", Keys: "O", Description: "Toggle OSD states (normal/time/duration)", Category: CategoryVideo, Priority: 80, Aliases: []string{"osd", "toggle"}}, {ID: "aspect-ratio", Keys: "A", Description: "Cycle aspect ratio override", Category: CategoryVideo, Priority: 60, Aliases: []string{"aspect", "ratio", "stretch"}}, {ID: "deband", Keys: "b", Description: "Toggle debanding", Category: CategoryVideo, Priority: 55, Aliases: []string{"deband", "filter", "quality"}}, {ID: "deinterlace", Keys: "d", Description: "Cycle deinterlacing filter", Category: CategoryVideo, Priority: 55, Aliases: []string{"deinterlace", "interlace", "filter"}}, {ID: "hwdec-toggle", Keys: "Ctrl + h", Description: "Toggle hardware video decoding", Category: CategoryVideo, Priority: 70, Aliases: []string{"hardware", "decoding", "gpu"}}, {ID: "video-track", Keys: "_", Description: "Cycle through video tracks", Category: CategoryVideo, Priority: 75, Aliases: []string{"video", "track"}}, {ID: "video-track-edition", Keys: "E", Description: "Cycle through available editions", Category: CategoryVideo, Priority: 65, Aliases: []string{"edition", "version"}}, {ID: "pan-left", Keys: "Alt + ←", Description: "Move video left (panning)", Category: CategoryVideo, Priority: 45, Aliases: []string{"pan", "move", "left"}}, {ID: "pan-right", Keys: "Alt + →", Description: "Move video right (panning)", Category: CategoryVideo, Priority: 45, Aliases: []string{"pan", "move", "right"}}, {ID: "pan-up", Keys: "Alt + ↑", Description: "Move video up (panning)", Category: CategoryVideo, Priority: 45, Aliases: []string{"pan", "move", "up"}}, {ID: "pan-down", Keys: "Alt + ↓", Description: "Move video down (panning)", Category: CategoryVideo, Priority: 45, Aliases: []string{"pan", "move", "down"}}, {ID: "zoom-in", Keys: "Alt + +", Description: "Zoom video in", Category: CategoryVideo, Priority: 50, Aliases: []string{"zoom", "in", "bigger"}}, {ID: "zoom-out", Keys: "Alt + -", Description: "Zoom video out", Category: CategoryVideo, Priority: 50, Aliases: []string{"zoom", "out", "smaller"}}, {ID: "zoom-reset", Keys: "Alt + BACKSPACE", Description: "Reset pan/zoom settings", Category: CategoryVideo, Priority: 50, Aliases: []string{"zoom", "reset", "pan"}}, {ID: "contrast-up", Keys: "1", Description: "Decrease contrast", Category: CategoryVideo, Priority: 40, Aliases: []string{"contrast", "adjust"}}, {ID: "contrast-down", Keys: "2", Description: "Increase contrast", Category: CategoryVideo, Priority: 40, Aliases: []string{"contrast", "adjust"}}, {ID: "brightness-up", Keys: "3", Description: "Decrease brightness", Category: CategoryVideo, Priority: 40, Aliases: []string{"brightness", "adjust"}}, {ID: "brightness-down", Keys: "4", Description: "Increase brightness", Category: CategoryVideo, Priority: 40, Aliases: []string{"brightness", "adjust"}}, {ID: "gamma-up", Keys: "5", Description: "Decrease gamma", Category: CategoryVideo, Priority: 40, Aliases: []string{"gamma", "adjust"}}, {ID: "gamma-down", Keys: "6", Description: "Increase gamma", Category: CategoryVideo, Priority: 40, Aliases: []string{"gamma", "adjust"}}, {ID: "saturation-up", Keys: "7", Description: "Decrease saturation", Category: CategoryVideo, Priority: 40, Aliases: []string{"saturation", "color", "adjust"}}, {ID: "saturation-down", Keys: "8", Description: "Increase saturation", Category: CategoryVideo, Priority: 40, Aliases: []string{"saturation", "color", "adjust"}}, {ID: "window-half", Keys: "Alt + 0", Description: "Resize window to half size", Category: CategoryVideo, Priority: 60, Aliases: []string{"window", "resize", "size"}}, {ID: "window-normal", Keys: "Alt + 1", Description: "Resize window to original size", Category: CategoryVideo, Priority: 60, Aliases: []string{"window", "resize", "size"}}, {ID: "window-double", Keys: "Alt + 2", Description: "Resize window to double size", Category: CategoryVideo, Priority: 60, Aliases: []string{"window", "resize", "size"}}, // Playlist {ID: "playlist-next", Keys: "> / ENTER", Description: "Go to next playlist entry", Category: CategoryPlaylist, Priority: 90, Aliases: []string{"next", "playlist", "skip"}}, {ID: "playlist-prev", Keys: "<", Description: "Go to previous playlist entry", Category: CategoryPlaylist, Priority: 90, Aliases: []string{"prev", "playlist", "back"}}, {ID: "playlist-first", Keys: "Shift + HOME", Description: "Go to first playlist entry", Category: CategoryPlaylist, Priority: 70, Aliases: []string{"playlist", "first", "start"}}, {ID: "playlist-last", Keys: "Shift + END", Description: "Go to last playlist entry", Category: CategoryPlaylist, Priority: 70, Aliases: []string{"playlist", "last", "end"}}, {ID: "playlist-show", Keys: "F8", Description: "Show playlist and current position", Category: CategoryPlaylist, Priority: 65, Aliases: []string{"playlist", "show", "list"}}, // Screenshots {ID: "screenshot", Keys: "s", Description: "Take a screenshot (with subtitles)", Category: CategoryScreenshot, Priority: 90, Aliases: []string{"screenshot", "capture", "image"}}, {ID: "screenshot-video", Keys: "S", Description: "Take a screenshot (without subtitles)", Category: CategoryScreenshot, Priority: 85, Aliases: []string{"screenshot", "capture", "video"}}, {ID: "screenshot-window", Keys: "Ctrl + s", Description: "Take a screenshot (as window shows it)", Category: CategoryScreenshot, Priority: 80, Aliases: []string{"screenshot", "capture", "window", "osd"}}, // Advanced {ID: "stats-toggle", Keys: "i / I", Description: "Show/toggle statistics overlay", Category: CategoryAdvanced, Priority: 80, Aliases: []string{"stats", "info", "debug"}}, {ID: "keybinds-show", Keys: "?", Description: "Show active key bindings overlay", Category: CategoryAdvanced, Priority: 75, Aliases: []string{"keybinds", "help", "shortcuts"}}, {ID: "console", Keys: "`", Description: "Show the console (ESC to close)", Category: CategoryAdvanced, Priority: 70, Aliases: []string{"console", "command", "terminal"}}, {ID: "osc-visibility", Keys: "DEL", Description: "Cycle OSC visibility (never/auto/always)", Category: CategoryAdvanced, Priority: 65, Aliases: []string{"osc", "visibility", "show", "hide"}}, {ID: "streams-show", Keys: "F9", Description: "Show audio and subtitle streams list", Category: CategoryAdvanced, Priority: 60, Aliases: []string{"streams", "tracks", "list"}}, {ID: "clipboard-paste", Keys: "Ctrl + v", Description: "Append clipboard file/URL to playlist", Category: CategoryAdvanced, Priority: 55, Aliases: []string{"clipboard", "paste", "url"}}, {ID: "context-menu", Keys: "MENU / Shift + F10", Description: "Show context menu", Category: CategoryAdvanced, Priority: 50, Aliases: []string{"menu", "context", "right-click"}}, // Menu Navigation (g- keybindings) {ID: "menu-playlist", Keys: "g + p", Description: "Select playlist entry (menu)", Category: CategoryMenu, Priority: 70, Aliases: []string{"playlist", "menu", "select"}}, {ID: "menu-subtitle", Keys: "g + s", Description: "Select subtitle track (menu)", Category: CategoryMenu, Priority: 70, Aliases: []string{"subtitle", "menu", "select"}}, {ID: "menu-subtitle-secondary", Keys: "g + S", Description: "Select secondary subtitle (menu)", Category: CategoryMenu, Priority: 65, Aliases: []string{"subtitle", "secondary", "menu"}}, {ID: "menu-audio", Keys: "g + a", Description: "Select audio track (menu)", Category: CategoryMenu, Priority: 70, Aliases: []string{"audio", "menu", "select"}}, {ID: "menu-video", Keys: "g + v", Description: "Select video track (menu)", Category: CategoryMenu, Priority: 65, Aliases: []string{"video", "menu", "select"}}, {ID: "menu-track-any", Keys: "g + t", Description: "Select track of any type (menu)", Category: CategoryMenu, Priority: 60, Aliases: []string{"track", "menu", "select"}}, {ID: "menu-chapter", Keys: "g + c", Description: "Select chapter (menu)", Category: CategoryMenu, Priority: 65, Aliases: []string{"chapter", "menu", "select"}}, {ID: "menu-edition", Keys: "g + e", Description: "Select MKV edition/DVD title (menu)", Category: CategoryMenu, Priority: 55, Aliases: []string{"edition", "menu", "select"}}, {ID: "menu-subtitle-line", Keys: "g + l", Description: "Select subtitle line to seek to", Category: CategoryMenu, Priority: 50, Aliases: []string{"subtitle", "line", "seek", "menu"}}, {ID: "menu-audio-device", Keys: "g + d", Description: "Select audio device (menu)", Category: CategoryMenu, Priority: 55, Aliases: []string{"audio", "device", "menu"}}, {ID: "menu-history", Keys: "g + h", Description: "Select from watch history (menu)", Category: CategoryMenu, Priority: 50, Aliases: []string{"history", "menu", "recent"}}, {ID: "menu-resume", Keys: "g + w", Description: "Select file to resume (menu)", Category: CategoryMenu, Priority: 50, Aliases: []string{"resume", "watch later", "menu"}}, {ID: "menu-bindings", Keys: "g + b", Description: "Select defined input binding (menu)", Category: CategoryMenu, Priority: 45, Aliases: []string{"binding", "keybind", "menu"}}, {ID: "menu-properties", Keys: "g + r", Description: "Show all property values", Category: CategoryMenu, Priority: 45, Aliases: []string{"properties", "debug", "menu"}}, {ID: "menu-misc", Keys: "g + m / Ctrl + p", Description: "Show miscellaneous menu entries", Category: CategoryMenu, Priority: 50, Aliases: []string{"misc", "menu"}}, // Multimedia Keys {ID: "mm-pause", Keys: "PAUSE", Description: "Pause playback (multimedia key)", Category: CategoryMultimedia, Priority: 70, Aliases: []string{"pause", "play", "multimedia"}}, {ID: "mm-stop", Keys: "STOP", Description: "Stop playing and quit (multimedia key)", Category: CategoryMultimedia, Priority: 70, Aliases: []string{"stop", "quit", "multimedia"}}, {ID: "mm-prev", Keys: "PREVIOUS", Description: "Seek backward 1 minute (multimedia key)", Category: CategoryMultimedia, Priority: 65, Aliases: []string{"seek", "back", "multimedia"}}, {ID: "mm-next", Keys: "NEXT", Description: "Seek forward 1 minute (multimedia key)", Category: CategoryMultimedia, Priority: 65, Aliases: []string{"seek", "forward", "multimedia"}}, {ID: "mm-zoom-in", Keys: "ZOOM IN", Description: "Zoom video in (multimedia key)", Category: CategoryMultimedia, Priority: 55, Aliases: []string{"zoom", "multimedia"}}, {ID: "mm-zoom-out", Keys: "ZOOM OUT", Description: "Zoom video out (multimedia key)", Category: CategoryMultimedia, Priority: 55, Aliases: []string{"zoom", "multimedia"}}, // macOS specific {ID: "mac-fullscreen", Keys: "⌘ + f", Description: "Toggle fullscreen (macOS only)", Category: CategoryVideo, Priority: 95, Aliases: []string{"fullscreen", "macos", "command"}}, {ID: "mac-half", Keys: "⌘ + 0", Description: "Resize window to half size (macOS only)", Category: CategoryVideo, Priority: 55, Aliases: []string{"window", "macos", "resize"}}, {ID: "mac-normal", Keys: "⌘ + 1", Description: "Resize window to normal size (macOS only)", Category: CategoryVideo, Priority: 55, Aliases: []string{"window", "macos", "resize"}}, {ID: "mac-double", Keys: "⌘ + 2", Description: "Resize window to double size (macOS only)", Category: CategoryVideo, Priority: 55, Aliases: []string{"window", "macos", "resize"}}, } // Categories returns all unique categories in display order var Categories = []string{ CategoryPlayback, CategorySeeking, CategoryAudio, CategorySubtitles, CategoryVideo, CategoryPlaylist, CategoryScreenshot, CategoryAdvanced, CategoryMenu, CategoryMultimedia, } // GetHotkeysByCategory returns hotkeys filtered by category, sorted by priority func GetHotkeysByCategory(category string) []Hotkey { var result []Hotkey for _, h := range Hotkeys { if h.Category == category { result = append(result, h) } } sort.Slice(result, func(i, j int) bool { return result[i].Priority > result[j].Priority }) return result } // SearchHotkeys returns hotkeys matching the search query func SearchHotkeys(query string) []Hotkey { if query == "" { return GetSortedHotkeys() } query = strings.ToLower(query) var result []Hotkey for _, h := range Hotkeys { // Search in keys, description, category, and aliases if strings.Contains(strings.ToLower(h.Keys), query) || strings.Contains(strings.ToLower(h.Description), query) || strings.Contains(strings.ToLower(h.Category), query) || matchAliases(h.Aliases, query) { result = append(result, h) } } // Sort by priority sort.Slice(result, func(i, j int) bool { return result[i].Priority > result[j].Priority }) return result } // matchAliases checks if any alias contains the query func matchAliases(aliases []string, query string) bool { for _, alias := range aliases { if strings.Contains(strings.ToLower(alias), query) { return true } } return false } // GetSortedHotkeys returns all hotkeys sorted by category order then priority func GetSortedHotkeys() []Hotkey { result := make([]Hotkey, len(Hotkeys)) copy(result, Hotkeys) // Sort by category order first, then by priority within category sort.Slice(result, func(i, j int) bool { // Get category order catOrderI := getCategoryOrder(result[i].Category) catOrderJ := getCategoryOrder(result[j].Category) if catOrderI != catOrderJ { return catOrderI < catOrderJ } // Within same category, sort by priority (higher first) return result[i].Priority > result[j].Priority }) return result } // getCategoryOrder returns the display order for a category func getCategoryOrder(category string) int { for i, c := range Categories { if c == category { return i } } return 999 } // GetHotkeysCount returns the total number of hotkeys func GetHotkeysCount() int { return len(Hotkeys) } // GetHotkeysCountByCategory returns the count of hotkeys in each category func GetHotkeysCountByCategory() map[string]int { counts := make(map[string]int) for _, h := range Hotkeys { counts[h.Category]++ } return counts }