Skip to content

floatpane/go-keybind

go-keybind

Key-binding config for Go TUI apps. Parse and normalize key strings, load/save JSON keybind files with merge-with-defaults semantics, validate for intra-area conflicts.

Go Version Go Reference GitHub release (latest by date) CI License: MIT

go-keybind provides two focused utilities for Go TUI applications:

  1. A Key type — parse and normalize keyboard shortcut strings. Catches typos ("crtl+c"), canonicalizes aliases ("escape""esc", "return""enter", "meta""alt"), fixes modifier order, and produces a comparable value you can switch on.

  2. A generic JSON config loaderLoad[T], Save[T], and Validate work with any app-defined struct. Fields the user didn't touch keep their compiled-in defaults, the file is written on first run, and Validate catches intra-area conflicts without false-positives for intentional cross-area duplicates.

Extracted from matcha's config package. Zero external dependencies.

Install

go get github.com/floatpane/go-keybind

Requires Go 1.26+.

Usage

Parse and compare key strings

k, err := keybind.Parse("ctrl+shift+a")
// k.Ctrl = true, k.Shift = true, k.Base = "a"
// k.String() = "ctrl+shift+a"

// Aliases normalize to the same Key:
a, _ := keybind.Parse("escape")
b, _ := keybind.Parse("esc")
fmt.Println(a == b) // true

// Modifier order doesn't matter in input:
c, _ := keybind.Parse("shift+ctrl+a")
d, _ := keybind.Parse("ctrl+shift+a")
fmt.Println(c == d) // true

Load a keybind config from disk

type MyKeys struct {
    Quit   string `json:"quit"`
    Reload string `json:"reload"`
    NavUp  string `json:"nav_up"`
}

cfg, err := keybind.Load(cfgDir, "keybinds.json", MyKeys{
    Quit:   "ctrl+c",
    Reload: "r",
    NavUp:  "k",
})
// If keybinds.json didn't exist it was created with the defaults.
// Fields absent from an existing file keep their default values.

Validate for conflicts

conflicts := keybind.Validate(map[string]map[string]string{
    "global": {"quit": cfg.Quit, "reload": cfg.Reload},
    "nav":    {"up": cfg.NavUp, "down": cfg.NavDown},
})
// Cross-area duplicates ("d" for delete in two different views) are fine.
// Only intra-area conflicts (two actions bound to the same key) are reported.

Use in a TUI event loop

quitKey := keybind.MustParse(cfg.Quit) // panics on bad config value

// In your event handler:
if event.String() == quitKey.String() {
    return tea.Quit
}

Supported keys

Modifiers: ctrl, alt (= meta = opt), shift

Special keys:

Canonical Aliases
enter return
esc escape
tab
backspace bs
space
up, down, left, right
delete del
insert
home, end
pgup pageup
pgdown pagedown, pgdn
f1f12

Any single printable character is also accepted (a, A, 1, /, […).

Documentation

Full API reference: pkg.go.dev/github.com/floatpane/go-keybind

Guides: see docs/.

Sister projects

Project Role
floatpane/matcha Reference consumer — inbox, email, composer, folder keybinds.

Contributing

PRs welcome. See CONTRIBUTING.md.

Security

Report vulnerabilities privately via SECURITY.md.

License

MIT. See LICENSE.

About

Zero-dependency keybind Go library

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors

Languages