{"record":{"id":"51bf5b8ae5489c91","repo":"wtfutil/wtf","slug":"key-is-already-mapped-to-a-keyboard-command-s","errorCode":null,"errorMessage":"Key is already mapped to a keyboard command: %s\n","messagePattern":"Key is already mapped to a keyboard command: (.+?)\n","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"view/keyboard_widget.go","lineNumber":141,"sourceCode":"\t\tpath = widget.settings.Type\n\t}\n\n\turl := \"https://wtfutil.com/modules/\" + path\n\tutils.OpenFile(url)\n}\n\n// SetKeyboardChar sets a character/function combination that responds to key presses\n// Example:\n//\n//\twidget.SetKeyboardChar(\"d\", widget.deleteSelectedItem)\nfunc (widget *KeyboardWidget) SetKeyboardChar(char string, fn func(), helpText string) {\n\tif char == \"\" {\n\t\treturn\n\t}\n\n\t// Check to ensure that the key trying to be used isn't already being used for something\n\tif _, ok := widget.charMap[char]; ok {\n\t\tpanic(fmt.Sprintf(\"Key is already mapped to a keyboard command: %s\\n\", char))\n\t}\n\n\twidget.charMap[char] = fn\n\twidget.charHelp = append(widget.charHelp, helpItem{char, helpText})\n}\n\n// SetKeyboardKey sets a tcell.Key/function combination that responds to key presses\n// Example:\n//\n//\twidget.SetKeyboardKey(tcell.KeyCtrlD, widget.deleteSelectedItem)\nfunc (widget *KeyboardWidget) SetKeyboardKey(key tcell.Key, fn func(), helpText string) {\n\twidget.keyMap[key] = fn\n\twidget.keyHelp = append(widget.keyHelp, helpItem{tcell.KeyNames[key], helpText})\n\n\tif len(tcell.KeyNames[key]) > widget.maxKey {\n\t\twidget.maxKey = len(tcell.KeyNames[key])\n\t}\n}","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/wtfutil/wtf/blob/bb838c1ccb0f0f3223690df44afdec663d622881/view/keyboard_widget.go#L123-L159","documentation":"SetKeyboardChar registers a single-character keyboard shortcut on a keyboard-enabled widget. It panics if the requested char already exists in the widget's charMap, because one key can only map to one command. This is a deliberate programming-error guard: duplicate keybindings for the same widget are treated as a setup bug rather than silently overwritten.","triggerScenarios":"Calling SetKeyboardChar twice with the same char on the same widget instance — typically in a widget's InitializeHelpTextKeyboardControl, InitializeRefreshKeyboardControl, or initializeCommonKeyboardControls chain where the same key (e.g. \"h\", \"r\", or the anonymous function registrations) is bound more than once.","commonSituations":"A widget author copies initialization code and accidentally re-binds a key already bound by initializeCommonKeyboardControls (e.g. re-binding \"r\" that refresh already uses); user config maps a key that collides with a built-in binding registered earlier in the chain; tests (Test_HelpText) re-initializing controls on the same widget object.","solutions":["Find the second registration of the duplicate char in the widget's keyboard initialization and remove it or pick a different char","Check that initializeCommonKeyboardControls is not re-registering keys already bound by InitializeHelpTextKeyboardControl / InitializeRefreshKeyboardControls","Ensure widget keyboard controls are initialized only once per widget instance (no double init on reload)","If collisions should be allowed, change code to overwrite instead of panic (widget.charMap[char] = fn after removing the existence check)"],"exampleFix":"// before\nwidget.InitializeHelpTextKeyboardControl(\"h\", \"help\")\nwidget.initializeCommonKeyboardControls()\n// after (initializeCommonKeyboardControls also binds \"h\")\nif _, taken := widget.charMap[\"h\"]; !taken {\n    widget.InitializeHelpTextKeyboardControl(\"h\", \"help\")\n}\nwidget.initializeCommonKeyboardControls()","handlingStrategy":"validation","validationCode":"func safeSetKey(w *view.KeyboardWidget, char string, fn func(), help string) {\n    if char == \"\" {\n        return\n    }\n    if _, taken := w.CharMap()[char]; taken {\n        log.Printf(\"key %q already mapped, skipping\", char)\n        return\n    }\n    w.SetKeyboardChar(char, fn, help)\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        if s, ok := r.(string); ok && strings.Contains(s, \"already mapped\") {\n            log.Printf(\"duplicate keybinding skipped: %s\", s)\n            return\n        }\n        panic(r)\n    }\n}()\nwidget.SetKeyboardChar(\"h\", fn, \"help\")","preventionTips":["Keep a single place (initializeCommonKeyboardControls) where all default keybindings are registered","Before adding a new shortcut, grep the widget's init chain for the chosen char","Only call the keyboard initialization functions once per widget instance lifecycle","In tests, create a fresh widget instead of re-initializing controls on a shared instance"],"tags":["go","panic","keyboard-shortcuts","configuration"],"backgroundTag":"duplicate-key-binding","analyzedSha":"bb838c1ccb0f0f3223690df44afdec663d622881","analyzedAt":"2026-09-03T17:02:45.030Z","contentChangedAt":"2026-09-03T17:02:45.030Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}