Use the hotkey package to register system-level global hotkey shortcuts. A hotkey consists of a combination of Modifiers and a single Key. Once registered, you can listen for Keydown and Keyup events via channels.
Platform Specifics
- macOS: Hotkey events must be handled on the "main thread". For self-contained applications, use the
golang.design/x/hotkey/mainthread package to start the OS main event loop. If you are using GUI frameworks like Fyne, Ebiten, or Gio, this is unnecessary. - macOS Permissions: Hotkeys use
CGEventTap, which requires Accessibility (Input Monitoring) permissions. Grant this in System Settings → Privacy & Security → Accessibility. - Linux (X11):
- If
AutoRepeat is enabled in the X server, Keyup may be triggered automatically and continuously while Keydown is active. - Some keys map to multiple
Mod keys. You may need to use the specific underlying keycode combination (e.g., Ctrl+Mod2+Mod4+S instead of Ctrl+Alt+S).
- Custom Keycodes: If a specific key is not provided in the package, you can use
hotkey.Key(keycode) where keycode is a numeric value (e.g., hotkey.Key(0x15)).
package main
import (
"log"
"golang.design/x/hotkey"
"golang.design/x/hotkey/mainthread"
)
func main() {
// mainthread.Init is required on macOS for self-contained apps
mainthread.Init(fn)
}
func fn() {
// Create a hotkey: Ctrl + Shift + S
hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS)
// Register the hotkey with the system
err := hk.Register()
if err != nil {
log.Fatalf("hotkey: failed to register hotkey: %v", err)
}
log.Printf("hotkey: %v is registered\n", hk)
// Wait for key down event
<-hk.Keydown()
log.Printf("hotkey: %v is down\n", hk)
// Wait for key up event
<-hk.Keyup()
log.Printf("hotkey: %v is up\n", hk)
// Unregister the hotkey
hk.Unregister()
log.Printf("hotkey: %v is unregistered\n", hk)
}