diff --git a/internal/infrastructure/hotkey/hotkey.go b/internal/infrastructure/hotkey/hotkey.go index 1224011..a09f017 100644 --- a/internal/infrastructure/hotkey/hotkey.go +++ b/internal/infrastructure/hotkey/hotkey.go @@ -104,7 +104,7 @@ func parseSpec(spec string) ([]hk.Modifier, hk.Key, error) { case "option", "alt": mods = append(mods, modOption()) case "shift": - mods = append(mods, hk.ModShift) + mods = append(mods, modShift()) default: k, ok := lookupKey(p) if !ok { diff --git a/internal/infrastructure/hotkey/hotkey_darwin.go b/internal/infrastructure/hotkey/hotkey_darwin.go index 1d21c22..afeb662 100644 --- a/internal/infrastructure/hotkey/hotkey_darwin.go +++ b/internal/infrastructure/hotkey/hotkey_darwin.go @@ -1,10 +1,15 @@ -//go:build darwin +//go:build darwin && cgo package hotkey import hk "golang.design/x/hotkey" // macOS uses ⌘ as the primary modifier; Option corresponds to Alt. +// +// This file is gated on cgo because golang.design/x/hotkey only exposes the +// Mod* constants from its cgo-backed darwin implementation; with CGO_ENABLED=0 +// the package falls back to a stub that defines no constants. func modCmd() hk.Modifier { return hk.ModCmd } func modCtrl() hk.Modifier { return hk.ModCtrl } func modOption() hk.Modifier { return hk.ModOption } +func modShift() hk.Modifier { return hk.ModShift } diff --git a/internal/infrastructure/hotkey/hotkey_linux.go b/internal/infrastructure/hotkey/hotkey_linux.go new file mode 100644 index 0000000..2e7b0d8 --- /dev/null +++ b/internal/infrastructure/hotkey/hotkey_linux.go @@ -0,0 +1,18 @@ +//go:build linux && cgo + +package hotkey + +import hk "golang.design/x/hotkey" + +// On Linux we map "cmd" to Ctrl so the same config string ("cmd+shift+a") +// stays meaningful across platforms. +// +// The X11 backend exposes modifiers as Mod1..Mod5 rather than named Alt/Option +// constants; Mod1 is the conventional Alt mask under X11, so "option"/"alt" +// resolve to hk.Mod1. This file is gated on cgo because the constants only +// exist in the cgo-backed linux implementation (CGO_ENABLED=0 falls back to a +// stub with no constants). +func modCmd() hk.Modifier { return hk.ModCtrl } +func modCtrl() hk.Modifier { return hk.ModCtrl } +func modOption() hk.Modifier { return hk.Mod1 } +func modShift() hk.Modifier { return hk.ModShift } diff --git a/internal/infrastructure/hotkey/hotkey_other.go b/internal/infrastructure/hotkey/hotkey_other.go deleted file mode 100644 index 3fb5b7d..0000000 --- a/internal/infrastructure/hotkey/hotkey_other.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build !darwin - -package hotkey - -import hk "golang.design/x/hotkey" - -// On Windows / Linux we map "cmd" to Ctrl so the same config string works -// across platforms; "option" is treated as Alt. -func modCmd() hk.Modifier { return hk.ModCtrl } -func modCtrl() hk.Modifier { return hk.ModCtrl } -func modOption() hk.Modifier { return hk.ModAlt } diff --git a/internal/infrastructure/hotkey/hotkey_unsupported.go b/internal/infrastructure/hotkey/hotkey_unsupported.go new file mode 100644 index 0000000..2be7d60 --- /dev/null +++ b/internal/infrastructure/hotkey/hotkey_unsupported.go @@ -0,0 +1,25 @@ +//go:build !windows && !cgo + +package hotkey + +import hk "golang.design/x/hotkey" + +// This file covers the configuration where golang.design/x/hotkey compiles its +// cgo-less stub (any non-Windows platform built with CGO_ENABLED=0). In that +// stub the package defines the Modifier/Key types but no Mod*/Key* constants, +// and Register panics at runtime. We still provide the package-internal +// helpers so that snapgo keeps cross-compiling (e.g. `go vet`, editor analysis, +// or CI cross-builds) without pulling in a C toolchain. +// +// The returned values are inert zero modifiers and lookupKey always reports +// "unsupported": callers on this build cannot register a real global hotkey, +// so surfacing an "unsupported token" parse error is preferable to reaching +// the upstream panic. +func modCmd() hk.Modifier { return 0 } +func modCtrl() hk.Modifier { return 0 } +func modOption() hk.Modifier { return 0 } +func modShift() hk.Modifier { return 0 } + +// lookupKey has no key constants to map against in the cgo-less stub, so it +// always reports the token as unsupported. +func lookupKey(string) (hk.Key, bool) { return 0, false } diff --git a/internal/infrastructure/hotkey/hotkey_windows.go b/internal/infrastructure/hotkey/hotkey_windows.go new file mode 100644 index 0000000..4ac7482 --- /dev/null +++ b/internal/infrastructure/hotkey/hotkey_windows.go @@ -0,0 +1,13 @@ +//go:build windows + +package hotkey + +import hk "golang.design/x/hotkey" + +// On Windows we map "cmd" to Ctrl so the same config string ("cmd+shift+a") +// stays meaningful across platforms; "option" is treated as Alt. The Windows +// backend does not require cgo, hence the single-tag guard. +func modCmd() hk.Modifier { return hk.ModCtrl } +func modCtrl() hk.Modifier { return hk.ModCtrl } +func modOption() hk.Modifier { return hk.ModAlt } +func modShift() hk.Modifier { return hk.ModShift } diff --git a/internal/infrastructure/hotkey/keys.go b/internal/infrastructure/hotkey/keys.go index e895313..299ba49 100644 --- a/internal/infrastructure/hotkey/keys.go +++ b/internal/infrastructure/hotkey/keys.go @@ -1,9 +1,15 @@ +//go:build windows || cgo + package hotkey import hk "golang.design/x/hotkey" // lookupKey maps a token from the user-supplied hotkey spec to a hk.Key. // +// The Key* constants only exist in the platform backends that ship them +// (windows, or the cgo-backed darwin/linux implementations); the cgo-less stub +// in hotkey_unsupported.go provides a fallback lookupKey for the complement. +// // The map is intentionally exhaustive over the alphanumeric set so we never // rely on an assumption that hk.KeyA..hk.KeyZ are contiguous values — the // upstream package gives no such guarantee.