### Ebiten Game Engine Integration Example Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/DOCUMENTATION.txt Shows how to integrate hotkey handling into an Ebiten game loop. This example assumes basic Ebiten setup and focuses on hotkey event processing. ```go package main import ( "fmt" "log" "github.com/hajimehoshi/ebiten/v2" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) // Game struct for Ebiten. type Game struct { hotkeyChan <-chan hotkey.Event } func (g *Game) Update() error { select { case event := <-g.hotkeyChan: fmt.Printf("Hotkey event received: %s\n", event) default: // No hotkey event, continue game loop. } return nil } func (g *Game) Draw(screen *ebiten.Image) { // Drawing logic here... } func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { return ebiten.DefaultLogicalSize } func main() { // Initialize main thread for hotkey library. err := mainthread.Init() if err != nil { log.Fatalf("Failed to initialize main thread: %v", err) } // Define and register a hotkey. hk := hotkey.Hotkey{ Modifiers: hotkey.ModShift, Key: hotkey.KeySpace, } err = hk.Register() if err != nil { log.Fatalf("Failed to register hotkey: %v", err) } defer hk.Unregister() game := &Game{ hotkeyChan: hk.Keydown(), } ebiten.SetWindowSize(640, 480) ebiten.SetWindowTitle("Hotkey Ebiten Example") if err := ebiten.RunGame(game); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Minimal Hotkey Example Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/reference-index.md A basic example demonstrating how to create, register, and wait for a hotkey event. Requires initialization of the main thread. ```go package main import ( "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { mainthread.Init(fn) } func fn() { hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) hk.Register() <-hk.Keydown() log.Println("Hotkey pressed") } ``` -------------------------------- ### Setup Xvfb for Headless Servers Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/platform-requirements.md Installs Xvfb and starts a virtual X11 display server, setting the DISPLAY environment variable. This is necessary for running X11 applications on headless servers. ```bash # Install Xvfb apt install -y xvfb # Start a virtual X11 display Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & # Set the display variable export DISPLAY=:99.0 ``` -------------------------------- ### Install libx11 on ArchLinux Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/platform-requirements.md Installs the X11 client library on Arch Linux. ```bash pacman -S libx11 ``` -------------------------------- ### Install libx11-devel on Fedora/RHEL Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/platform-requirements.md Installs the X11 client library development package on Fedora or RHEL-based systems. ```bash dnf install -y libx11-devel ``` -------------------------------- ### Custom Key Code Example Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/api-reference/keys-and-modifiers.md Demonstrates how to use a custom keycode for a key not defined as a constant. The keycode values are platform-dependent. ```go // Use a custom keycode for a key not in the constants customKey := hotkey.Key(0x15) hk := hotkey.New([]hotkey.Modifier{}, customKey) ``` -------------------------------- ### Fyne GUI Integration Example Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/DOCUMENTATION.txt Demonstrates how to integrate hotkey functionality within a Fyne GUI application. This requires proper initialization of the main thread for GUI operations. ```go package main import ( "fmt" "log" "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/widget" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { // Initialize Fyne application. a := app.New() w := a.NewWindow("Hotkey Fyne Example") // Initialize main thread for hotkey library. err := mainthread.Init() if err != nil { log.Fatalf("Failed to initialize main thread: %v", err) } // Define and register a hotkey. hk := hotkey.Hotkey{ Modifiers: hotkey.ModCtrl, Key: hotkey.KeyF, } err = hk.Register() if err != nil { log.Fatalf("Failed to register hotkey: %v", err) } defer hk.Unregister() label := widget.NewLabel("Press Ctrl+F to trigger hotkey.") w.SetContent(fyne.NewContainer(label)) // Listen for hotkey events in a separate goroutine. go func() { for { select { case event := <-hk.Keydown(): fmt.Printf("Hotkey Ctrl+F pressed: %s\n", event) // Update UI on the main thread. w.Canvas().QueueMainThread(func() { label.SetText("Ctrl+F was pressed!") }) } } }() w.ShowAndRun() } ``` -------------------------------- ### Install libx11-dev on Debian/Ubuntu Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/platform-requirements.md Installs the X11 client library development package on Debian-based systems. ```bash apt install -y libx11-dev ``` -------------------------------- ### Get Hotkey String Representation Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/api-reference/hotkey.md This example shows how to get a human-readable string representation of a hotkey, including its key and modifiers. The String() method is useful for debugging or display purposes. ```go package main import ( "log" "golang.design/x/hotkey" ) func main() { hk := hotkey.New( []hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS, ) log.Println(hk.String()) // Outputs: "S+Ctrl+Shift" or similar } ``` -------------------------------- ### Go Module Definition Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Example of a go.mod file specifying the module path and its dependencies. ```go module golang.design/x/hotkey go 1.24 require golang.design/x/mainthread v0.3.0 ``` -------------------------------- ### Unit Testing Hotkey Functionality Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/DOCUMENTATION.txt Provides an example of how to unit test hotkey registration and event handling. This often involves mocking or simulating hotkey events. ```go package hotkey_test import ( "testing" "time" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func TestHotkeyRegistration(t *testing.T) { // Ensure main thread initialization for testing. err := mainthread.Init() if err != nil { t log.Fatalf("Failed to initialize main thread for test: %v", err) } hk := hotkey.Hotkey{Modifiers: hotkey.ModCtrl, Key: hotkey.KeyT} // Test registration. err = hk.Register() if err != nil { t.Errorf("Hotkey registration failed: %v", err) } defer hk.Unregister() // Ensure unregistration. // Test if it's registered (this might require platform-specific checks or mocking). // For simplicity, we assume registration success implies it's active. // Test unregistration. err = hk.Unregister() if err != nil { t.Errorf("Hotkey unregistration failed: %v", err) } // Test registering again after unregistering. err = hk.Register() if err != nil { t.Errorf("Hotkey registration failed after unregister: %v", err) } } // Note: Testing event triggering typically requires more advanced mocking or // platform-specific simulation tools, which are beyond a simple example. // The following is a conceptual placeholder. func TestHotkeyEventTriggering(t *testing.T) { // Mock or simulate a hotkey event being sent to the library. // This is highly platform-dependent and often requires external tools or libraries. // Example: If you had a way to simulate an event: // hk := hotkey.Hotkey{...} // hk.Register() // simulateEvent(hk) // select { // case <-hk.Keydown(): // // Event received, test passed. // case <-time.After(100 * time.Millisecond): // tt.Error("Hotkey event not received within timeout") // } t.Skip("Event triggering simulation not implemented in this example.") } ``` -------------------------------- ### Register Hotkey on Windows Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/errors.md Example of registering a hotkey on Windows. Handles potential registration failures, such as the hotkey already being in use. ```go hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS) err := hk.Register() if err != nil { log.Fatalf("Failed to register: %v", err) // Output: Failed to register: hotkey: failed to register, the combination // might already be taken by another application: [Windows error details] } ``` -------------------------------- ### Receive Hotkey Events Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/types.md Examples of receiving keydown and keyup events from a hotkey. These operations block until an event occurs. ```go // Receive keydown event <-hk.Keydown() // Blocks until keydown, returns empty Event{} // Receive keyup event <-hk.Keyup() // Blocks until keyup, returns empty Event{} ``` -------------------------------- ### Create Hotkey with Custom Key Code Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/types.md Use a raw Key value for keys not defined as constants. This example uses keycode 0x15, which is platform-specific. ```go // Use keycode 0x15 (platform-specific) customKey := hotkey.Key(0x15) hk := hotkey.New([]hotkey.Modifier{}, customKey) ``` -------------------------------- ### Create Hotkey with No Modifiers Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/types.md Example of creating a new hotkey with no modifiers, using only a bare key (F12). ```go // No modifiers (bare key) hk := hotkey.New([]hotkey.Modifier{}, hotkey.KeyF12) ``` -------------------------------- ### Example of Non-Standard Modifier Mapping in Go Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/platform-requirements.md Illustrates how to define a hotkey with alternative modifier masks (Mod2, Mod4) when standard mappings do not apply due to keyboard layout issues on Linux/X11. ```go hk := hotkey.New( []hotkey.Modifier{hotkey.ModCtrl, hotkey.Mod2, hotkey.Mod4}, hotkey.KeyS, ) ``` -------------------------------- ### Create Hotkey with Single Modifier Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/types.md Example of creating a new hotkey with a single modifier (Ctrl) and a specific key (D). ```go // Single modifier hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) ``` -------------------------------- ### Create Hotkey with Multiple Modifiers Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/types.md Example of creating a new hotkey with multiple modifiers (Ctrl and Shift) and a specific key (S). ```go // Multiple modifiers hk := hotkey.New( []hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS, ) ``` -------------------------------- ### Check for Specific Hotkey Errors Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/errors.md Example of checking for specific hotkey registration errors using `errors.Is` and direct error message comparison. ```go package main import ( "errors" "log" "golang.design/x/hotkey" ) func main() { hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) err := hk.Register() if err != nil { // Check for already-registered error if errors.Is(err, /* need to import */ errAlreadyRegistered) { log.Println("Hotkey already registered") return } // Check for other errors by message if err.Error() == "hotkey: not registered" { log.Println("Hotkey not registered") return } log.Fatalf("Registration failed: %v", err) } } ``` -------------------------------- ### Media Key Handling Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/DOCUMENTATION.txt Demonstrates how to register and handle media keys (e.g., Play/Pause, Volume Up/Down). Platform-specific key constants should be used. ```go package main import ( "fmt" "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { err := mainthread.Init() if err != nil { log.Fatalf("Failed to initialize main thread: %v", err) } // Example: Registering the Play/Pause media key. mediaKey := hotkey.Hotkey{ Key: hotkey.KeyMediaPlayPause, } err = mediaKey.Register() if err != nil { log.Fatalf("Failed to register media key: %v", err) } defer mediaKey.Unregister() fmt.Println("Media Play/Pause key registered. Press it to trigger.") for { select { case event := <-mediaKey.Keydown(): fmt.Printf("Media Play/Pause pressed: %s\n", event) } } } ``` -------------------------------- ### Handle Media Keys in Go Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/integration-examples.md Demonstrates how to register and handle media keys like Play/Pause. Includes platform-specific fallback logic for keys not available on all operating systems. ```go package main import ( "log" "runtime" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { mainthread.Init(fn) } func fn() { // Choose media keys based on platform var playPauseKey hotkey.Key = hotkey.KeyMediaPlayPause hk := hotkey.New([]hotkey.Modifier{}, playPauseKey) err := hk.Register() if err != nil { // KeyMediaStop not available on macOS if runtime.GOOS == "darwin" && playPauseKey == hotkey.KeyMediaStop { log.Println("Media stop not supported on macOS, using play/pause") hk = hotkey.New([]hotkey.Modifier{}, hotkey.KeyMediaPlayPause) err = hk.Register() } if err != nil { log.Fatalf("Failed to register media key: %v", err) } } log.Printf("Media hotkey registered: %v", hk) // Handle media key go func() { for { <-hk.Keydown() log.Println("Media key pressed") <-hk.Keyup() log.Println("Media key released") } }() } ``` -------------------------------- ### Go Main Thread Initialization Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/platform-requirements.md Shows how to initialize the hotkey package to process events on the main thread using the `mainthread` package. GUI frameworks may handle this automatically. ```go func main() { mainthread.Init(fn) } func fn() { // All hotkey code here } ``` -------------------------------- ### Create Hotkeys Using Constants and Custom Keycodes Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/types.md Demonstrates creating hotkeys using predefined constants for modifiers and keys, as well as using a custom keycode. ```go // Using constants hk1 := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) hk2 := hotkey.New([]hotkey.Modifier{}, hotkey.KeyF1) // Using custom keycode hk3 := hotkey.New([]hotkey.Modifier{}, hotkey.Key(0x15)) ``` -------------------------------- ### Basic Hotkey Registration and Event Handling Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Demonstrates how to create, register, and handle keydown/keyup events for a global hotkey. Requires mainthread initialization for macOS. ```go package main import ( "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { mainthread.Init(fn) } func fn() { // Create hotkey: Ctrl+Shift+S hk := hotkey.New( []hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS, ) // Register with OS if err := hk.Register(); err != nil { log.Fatalf("Failed to register: %v", err) } // Wait for keydown event <-hk.Keydown() log.Println("Hotkey pressed!") // Wait for keyup event <-hk.Keyup() log.Println("Hotkey released!") // Cleanup hk.Unregister() } ``` -------------------------------- ### Initialize mainthread and schedule functions Source: https://github.com/golang-design/hotkey/blob/main/vendor/golang.design/x/mainthread/README.md Initialize the mainthread package by calling mainthread.Init from the main function. Use mainthread.Call for blocking calls and mainthread.Go for non-blocking calls. ```go package main import "golang.design/x/mainthread" func main() { mainthread.Init(fn) } // fn is the actual main function func fn() { // ... do stuff ... // mainthread.Call returns when f1 returns. Note that if f1 blocks // it will also block the execution of any subsequent calls on the // main thread. mainthread.Call(f1) // ... do stuff ... // mainthread.Go returns immediately and f2 is scheduled to be // executed in the future. mainthread.Go(f2) // ... do stuff ... } func f1() { ... } func f2() { ... } ``` -------------------------------- ### Basic Hotkey Registration and Usage Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/DOCUMENTATION.txt Demonstrates the fundamental steps of creating, registering, and listening for hotkey events. Ensure the hotkey is unregistered when no longer needed. ```go package main import ( "fmt" "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { // Ensure main thread initialization for GUI frameworks. err := mainthread.Init() if err != nil { log.Fatalf("Failed to initialize main thread: %v", err) } // Define the hotkey combination (e.g., Ctrl+Shift+A). hk := hotkey.Hotkey{ Modifiers: hotkey.ModCtrl | hotkey.ModShift, Key: hotkey.KeyA, } // Register the hotkey. err = hk.Register() if err != nil { log.Fatalf("Failed to register hotkey: %v", err) } // Unregister the hotkey when done. defer hk.Unregister() fmt.Println("Hotkey registered. Press Ctrl+Shift+A to trigger.") // Listen for hotkey events. for { select { case event := <-hk.Keydown(): fmt.Printf("Hotkey pressed: %s\n", event) case event := <-hk.Keyup(): fmt.Printf("Hotkey released: %s\n", event) } } } ``` -------------------------------- ### Import Paths for Hotkey Package Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Shows the necessary import paths for using the hotkey and mainthread packages. ```go import "golang.design/x/hotkey" import "golang.design/x/hotkey/mainthread" ``` -------------------------------- ### Import Hotkey Package Source: https://github.com/golang-design/hotkey/blob/main/README.md Import the hotkey package to begin using its functionalities. ```go import "golang.design/x/hotkey" ``` -------------------------------- ### Golang Hotkey Package Directory Structure Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/reference-index.md Illustrates the file organization for the golang.design/x/hotkey package and its related documentation. ```text /workspace/home/output/ ├── reference-index.md ← Start here ├── api-reference/ │ ├── hotkey.md ← Core API │ ├── keys-and-modifiers.md ← Constants │ └── mainthread.md ← Main thread functions ├── types.md ← Type definitions ├── errors.md ← Error handling ├── platform-requirements.md ← OS-specific └── integration-examples.md ← Code patterns ``` -------------------------------- ### macOS Build Commands for CGO Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/platform-requirements.md Demonstrates how to build the Go application on macOS with CGO enabled (default and required) and disabled (which will cause a runtime panic). ```bash # CGO enabled (default, required) go build main.go # CGO disabled (will panic at runtime) CGO_ENABLED=0 go build main.go ``` -------------------------------- ### Go init() function calling XInitThreads Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/platform-requirements.md Demonstrates the automatic call to C.XInitThreads() within the Go init() function to ensure thread-safe X11 access from multiple hotkey event loops. ```go func init() { C.XInitThreads() // ... } ``` -------------------------------- ### Initialize Main Thread Event Handling (macOS/Windows/Linux) Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/api-reference/mainthread.md Initializes main thread event handling and runs the provided function on the main thread. On macOS, this is required and blocks indefinitely. On other platforms, it's optional but recommended. ```go package main import ( "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { mainthread.Init(fn) } func fn() { log.Println("Main thread initialized") hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) err := hk.Register() if err != nil { log.Fatalf("Failed to register hotkey: %v", err) } log.Println("Waiting for hotkey...") <-hk.Keydown() log.Println("Hotkey pressed!") } ``` -------------------------------- ### Create and Register a Hotkey Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/00-START-HERE.txt This snippet demonstrates how to create a new hotkey with specific modifiers and a key, register it, and then wait for its keydown and keyup events. It also shows how to unregister the hotkey. Ensure the mainthread.Init function is called before executing hotkey operations. ```Go package main import ( "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { mainthread.Init(fn) } func fn() { hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) hk.Register() <-hk.Keydown() // Wait for press <-hk.Keyup() // Wait for release hk.Unregister() } ``` -------------------------------- ### Register a Single Hotkey Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Shows how to create and register a single hotkey combination (Ctrl+D). It then waits for the hotkey to be pressed and logs a message. ```go hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) if err := hk.Register(); err != nil { log.Fatalf("Failed: %v", err) } <-hk.Keydown() log.Println("Pressed") ``` -------------------------------- ### Error Handling and Recovery Patterns Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/DOCUMENTATION.txt Illustrates how to handle potential errors during hotkey registration and provides strategies for recovery. It's crucial to check for errors after registration and unregistration. ```go package main import ( "fmt" "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { err := mainthread.Init() if err != nil { log.Fatalf("Failed to initialize main thread: %v", err) } hk := hotkey.Hotkey{Modifiers: hotkey.ModCtrl, Key: hotkey.KeyE} // Attempt to register the hotkey and handle potential errors. err = hk.Register() if err != nil { s// Handle specific errors, e.g., already registered. if err == hotkey.ErrAlreadyRegistered { fmt.Println("Hotkey is already registered. Attempting to unregister and re-register.") // Attempt to unregister first, then re-register. _ = hk.Unregister() // Ignore error during unregister if it fails. err = hk.Register() if err != nil { log.Fatalf("Failed to re-register hotkey after unregister: %v", err) } } else { log.Fatalf("Failed to register hotkey: %v", err) } } defer func() { // Ensure unregistration, handling potential errors. err := hk.Unregister() if err != nil && err != hotkey.ErrNotRegistered { fmt.Printf("Warning: Failed to unregister hotkey: %v\n", err) } }() fmt.Println("Hotkey Ctrl+E registered successfully.") // Example of listening for events, assuming successful registration. for { select { case event := <-hk.Keydown(): fmt.Printf("Hotkey Ctrl+E pressed: %s\n", event) } } } ``` -------------------------------- ### Build with CGO Disabled Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/errors.md Illustrates the command to build a Go program with CGO disabled, which will cause the hotkey library to panic on registration. ```bash # This will panic when Register() is called CGO_ENABLED=0 go run main.go ``` -------------------------------- ### Error-Handling Hotkey Pattern Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/reference-index.md Demonstrates how to register a hotkey, handle potential registration errors, and unregister it using defer. It also shows how to listen for keydown and keyup events in a separate goroutine. ```go hk := hotkey.New(mods, key) if err := hk.Register(); err != nil { log.Fatalf("Registration failed: %v", err) } defer hk.Unregister() go func() { for { <-hk.Keydown() // Handle keydown <-hk.Keyup() // Handle keyup } }() ``` -------------------------------- ### Hotkey Type Usage Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Illustrates the creation, registration, event handling, and unregistration of a hotkey using its methods. ```go // Create a hotkey hk := hotkey.New( []hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, // Modifiers hotkey.KeyS, // Key ) // Register with operating system err := hk.Register() // Receive keydown and keyup events <-hk.Keydown() // Blocks until hotkey pressed <-hk.Keyup() // Blocks until hotkey released // Unregister when done hk.Unregister() ``` -------------------------------- ### Hotkey Registration and Event Handling Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Demonstrates how to create, register, and listen for keydown events for a single hotkey. This is a fundamental operation for using the hotkey package. ```APIDOC ## Register a Single Hotkey ### Description Creates a new hotkey with specified modifiers and key, registers it with the operating system, and waits for a keydown event. ### Method `Register()` ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) if err := hk.Register(); err != nil { log.Fatalf("Failed: %v", err) } <-hk.Keydown() log.Println("Pressed") ``` ### Response #### Success Response - `<-hk.Keydown()`: Returns a channel that receives an `Event` when the hotkey is pressed. #### Response Example ```go // Upon successful registration and key press, the program will log "Pressed" ``` ### Error Handling - `hk.Register()` can return errors such as `errAlreadyRegistered` or `errRegisterFailed`. ``` -------------------------------- ### Enable CGO for Linux/X11 Builds Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/platform-requirements.md When building for Linux/X11, CGO must be enabled. This command ensures CGO is active during the build process. ```bash # CGO enabled (required) CGO_ENABLED=1 go build main.go ``` -------------------------------- ### Registering Multiple Hotkeys Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/DOCUMENTATION.txt Shows how to register and manage multiple hotkeys concurrently. Each hotkey should be unregistered when no longer needed. ```go package main import ( "fmt" "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { err := mainthread.Init() if err != nil { log.Fatalf("Failed to initialize main thread: %v", err) } // Define multiple hotkeys. hotkeys := []*hotkey.Hotkey{ { Modifiers: hotkey.ModCtrl, Key: hotkey.KeyS, }, { Modifiers: hotkey.ModAlt, Key: hotkey.KeyX, }, } // Register all hotkeys. for _, hk := range hotkeys { err = hk.Register() if err != nil { log.Fatalf("Failed to register hotkey %s: %v", hk, err) } // Ensure unregistration. defer hk.Unregister() } fmt.Println("Multiple hotkeys registered. Press Ctrl+S or Alt+X.") // Listen for events from all hotkeys. for { select { case event := <-hotkeys[0].Keydown(): fmt.Printf("Hotkey Ctrl+S pressed: %s\n", event) case event := <-hotkeys[1].Keydown(): fmt.Printf("Hotkey Alt+X pressed: %s\n", event) } } } ``` -------------------------------- ### Main Thread Initialization for macOS Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Shows how to initialize the main thread for hotkey event processing on macOS. This function must be called within main(). ```go func main() { mainthread.Init(fn) } // Must be in main() func fn() { // All hotkey code runs here on the main thread } ``` -------------------------------- ### X11 Hotkey Registration Workaround Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/errors.md Demonstrates how to adjust modifier keys for hotkey registration on X11 systems where default mappings might differ. ```go // Incorrect on some systems hk := hotkey.New([]hotkey.Modifier{hotkey.Mod1}, hotkey.KeyS) // Might need to use Mod2 or Mod4 depending on keyboard layout hk := hotkey.New([]hotkey.Modifier{hotkey.Mod2}, hotkey.KeyS) ``` -------------------------------- ### Register Hotkey with OS Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/api-reference/hotkey.md Registers the created Hotkey with the operating system to enable global event listening. Handles potential errors like already registered hotkeys or permission issues. ```go func (hk *Hotkey) Register() error ``` ```go package main import ( "log" "golang.design/x/hotkey" ) func main() { hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) err := hk.Register() if err != nil { log.Fatalf("Failed to register hotkey: %v", err) } // Hotkey is now active log.Println("Hotkey registered successfully") } ``` -------------------------------- ### Error Handling and Recovery for Hotkey Registration Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/integration-examples.md Demonstrates robust error handling for hotkey registration, including fallback options and specific error checks. Ensures graceful failure and resource cleanup. ```go package main import ( "errors" "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { mainthread.Init(fn) } func fn() { // Attempt to register a hotkey with fallback if !tryRegisterHotkey(hotkey.ModCtrl, hotkey.KeyD) { log.Println("Primary hotkey failed, trying fallback...") if !tryRegisterHotkey(hotkey.ModCtrl, hotkey.KeyK) { log.Println("All hotkey options failed, exiting") return } } } func tryRegisterHotkey(mod hotkey.Modifier, key hotkey.Key) bool { hk := hotkey.New([]hotkey.Modifier{mod}, key) err := hk.Register() if err != nil { // Check for specific errors if errors.Is(err, /* errAlreadyRegistered */ errors.New("hotkey: already registered")) { log.Printf("Hotkey already in use: %v", err) return false } // Check for permission errors if errors.Is(err, errors.New("hotkey: failed to register")) { log.Printf("Hotkey registration failed: %v", err) return false } log.Printf("Unexpected error: %v", err) return false } log.Printf("Successfully registered hotkey: %v", hk) // Background listener go func() { <-hk.Keydown() log.Printf("Hotkey %v was pressed", hk) <-hk.Keyup() // Re-register if needed hk.Unregister() }() return true } ``` -------------------------------- ### Handling Multiple Hotkeys Concurrently Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Shows how to manage multiple hotkeys simultaneously by launching a goroutine for each hotkey to handle its events independently. ```APIDOC ## Handle Multiple Hotkeys ### Description Iterates through a list of hotkey specifications, creating and registering a hotkey for each. Each hotkey is managed in its own goroutine to concurrently listen for and handle keydown events. ### Method `Register()`, `Keydown()` ### Endpoint N/A (SDK Method) ### Parameters None explicitly defined for this pattern, relies on `hotkey.New` parameters. ### Request Example ```go // Assuming hotkeySpecs is a slice of structs containing hotkey definitions for _, spec := range hotkeySpecs { go func(s spec) { hk := hotkey.New(s.Mods, s.Key) hk.Register() for { <-hk.Keydown() // Handle keydown event for this specific hotkey } }(spec) } ``` ### Response - `<-hk.Keydown()`: Each goroutine receives events for its respective hotkey. ### Error Handling - `hk.Register()` errors should be handled within each goroutine, potentially logging the issue and continuing with other hotkeys. ``` -------------------------------- ### New Hotkey Constructor Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/api-reference/hotkey.md Creates a new Hotkey instance with specified modifiers and key. The hotkey is not yet registered with the system. ```go func New(mods []Modifier, key Key) *Hotkey ``` ```go package main import ( "golang.design/x/hotkey" ) func main() { // Create a hotkey for Ctrl+Shift+S hk := hotkey.New( []hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS, ) _ = hk // Use the hotkey } ``` -------------------------------- ### Linux/X11 Media Keys Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/api-reference/keys-and-modifiers.md Defines constants for media playback and volume control keys on Linux/X11 systems. ```go const ( KeyMediaPlayPause Key = 0x1008FF14 // XF86AudioPlay KeyMediaNext Key = 0x1008FF17 // XF86AudioNext KeyMediaPrev Key = 0x1008FF16 // XF86AudioPrev KeyMediaStop Key = 0x1008FF15 // XF86AudioStop KeyVolumeUp Key = 0x1008FF13 // XF86AudioRaiseVolume KeyVolumeDown Key = 0x1008FF11 // XF86AudioLowerVolume KeyVolumeMute Key = 0x1008FF12 // XF86AudioMute ) ``` -------------------------------- ### mainthread.Init Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/api-reference/mainthread.md Initializes main thread event handling and runs the provided function on the main thread. This function blocks indefinitely on most platforms until the provided function completes or calls os.Exit(). On macOS, it sets up the NSApplication main event loop. ```APIDOC ## Function: Init Initializes main thread event handling and runs the provided function on the main thread. ### Signature: ```go func Init(main func()) ``` ### Parameters: #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters: | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | main | `func()` | Yes | — | A function to execute on the main thread. This function becomes the main entry point for hotkey handling. | ### Return Type: - None (void). Init blocks indefinitely until the provided function completes (on most platforms) or calls `os.Exit()` (on macOS). ### Behavior: **On macOS (darwin with cgo):** - Locks the OS thread (via `runtime.LockOSThread()` in `init()`) - Launches the provided function in a goroutine - Blocks by calling C Objective-C `os_main()`, which sets up and runs the NSApplication main event loop - When the function completes, it calls `os.Exit(0)` to terminate the program - The function can use `mainthread.Call()` to dispatch additional work to the main thread **On Windows, Linux/OpenBSD:** - Delegates to the underlying `golang.design/x/mainthread.Init()` - Starts the main thread event loop - Runs the provided function ### Platform-Specific Usage: On macOS, hotkey events must be processed on the main thread. The Init function must be called in `main()` before any hotkey operations: ```go func main() { mainthread.Init(fn) } func fn() { // All hotkey code goes here } ``` On Windows and Linux, Init is optional but recommended if you want centralized main-thread handling. ### Example: ```go package main import ( "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { mainthread.Init(fn) } func fn() { log.Println("Main thread initialized") hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) err := hk.Register() if err != nil { log.Fatalf("Failed to register hotkey: %v", err) } log.Println("Waiting for hotkey...") <-hk.Keydown() log.Println("Hotkey pressed!") } ``` ``` -------------------------------- ### Integrating Hotkeys with Fyne GUI Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Illustrates how to integrate hotkey functionality into a Fyne application, ensuring hotkey events are processed correctly within the Fyne main thread. ```APIDOC ## Use with Fyne ### Description Registers a hotkey and starts a goroutine to listen for its keydown events. This setup is designed to work alongside the Fyne application's main loop, which typically handles thread management. ### Method `Register()`, `Keydown()` ### Endpoint N/A (SDK Method) ### Parameters None explicitly defined for this pattern, relies on `hotkey.New` parameters. ### Request Example ```go hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyK) hk.Register() go func() { for { <-hk.Keydown() // Handle keydown event within the Fyne app context } }() myApp.ShowAndRun() // Fyne's main loop manages the application thread ``` ### Response - `<-hk.Keydown()`: Receives events that can be processed by the Fyne application. ### Error Handling - Ensure `hk.Register()` errors are handled appropriately before proceeding. ``` -------------------------------- ### Handle Common Hotkey Errors Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Demonstrates how to check for and handle specific hotkey registration errors like already registered, not registered, or registration failure. Includes platform-specific error checks for macOS Accessibility and Linux/X11 display issues. ```go // Already registered if err == errAlreadyRegistered { log.Println("Hotkey already registered") } // Not registered if err == errNotRegistered { log.Println("Hotkey not registered") } // Registration failed (unavailable) if err == errRegisterFailed { log.Println("Hotkey combination unavailable") } // macOS: Permission missing if strings.Contains(err.Error(), "Accessibility") { log.Println("Grant Accessibility permission in System Settings") } // Linux/X11: Display unavailable if strings.Contains(err.Error(), "X11") { log.Println("X11 display not available") } ``` -------------------------------- ### Polling Event Channels with Select Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/DOCUMENTATION.txt Illustrates how to efficiently poll multiple hotkey event channels using a `select` statement. This pattern is useful for handling events from various sources simultaneously. ```go package main import ( "fmt" "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { err := mainthread.Init() if err != nil { log.Fatalf("Failed to initialize main thread: %v", err) } hk1 := hotkey.Hotkey{Modifiers: hotkey.ModCtrl, Key: hotkey.Key1} hk2 := hotkey.Hotkey{Modifiers: hotkey.ModCtrl, Key: hotkey.Key2} err = hk1.Register() if err != nil { log.Fatalf("Failed to register hotkey %s: %v", hk1, err) } defer hk1.Unregister() err = hk2.Register() if err != nil { log.Fatalf("Failed to register hotkey %s: %v", hk2, err) } defer hk2.Unregister() fmt.Println("Listening for Ctrl+1 and Ctrl+2...") for { select { case event := <-hk1.Keydown(): fmt.Printf("Ctrl+1 pressed: %s\n", event) case event := <-hk2.Keydown(): fmt.Printf("Ctrl+2 pressed: %s\n", event) } } } ``` -------------------------------- ### Multiple Concurrent Hotkeys Pattern Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/reference-index.md Shows how to register multiple hotkeys concurrently using goroutines and a WaitGroup. Each hotkey is registered in its own goroutine. ```go wg := sync.WaitGroup{} for _, keySpec := range keySpecs { wg.Add(1) go func(spec KeySpec) { defer wg.Done() hk := hotkey.New(spec.Mods, spec.Key) hk.Register() // Handle events }(keySpec) } wg.Wait() ``` -------------------------------- ### Receive Hotkey Release Event Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/api-reference/hotkey.md Use this snippet to wait for and log a hotkey release event. It requires the hotkey to be registered first. The channel returned by Keyup() blocks until the hotkey is released. ```go package main import ( "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) func main() { mainthread.Init(fn) } func fn() { hk := hotkey.New([]hotkey.Modifier{hotkey.ModCtrl}, hotkey.KeyD) hk.Register() <-hk.Keydown() log.Println("Key held down") <-hk.Keyup() log.Println("Key released") } ``` -------------------------------- ### Callback-based Hotkey Patterns Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/DOCUMENTATION.txt Shows an alternative pattern for handling hotkey events using callbacks. This can be useful for integrating with systems that expect function calls upon event triggers. ```go package main import ( "fmt" "log" "golang.design/x/hotkey" "golang.design/x/hotkey/mainthread" ) // Callback function to handle hotkey events. func handleHotkey(event hotkey.Event) { fmt.Printf("Callback triggered for hotkey: %s\n", event) } func main() { err := mainthread.Init() if err != nil { log.Fatalf("Failed to initialize main thread: %v", err) } hk := hotkey.Hotkey{Modifiers: hotkey.ModAlt, Key: hotkey.KeyC} err = hk.Register() if err != nil { log.Fatalf("Failed to register hotkey: %v", err) } defer hk.Unregister() fmt.Println("Hotkey Alt+C registered. Press it to trigger callback.") // Use a separate goroutine to listen and call the handler. go func() { for { select { case event := <-hk.Keydown(): handleHotkey(event) } } }() // Keep the main goroutine alive. select {} } ``` -------------------------------- ### Handle Multiple Hotkeys Concurrently Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/README.md Demonstrates registering and handling multiple hotkeys concurrently using goroutines. Each hotkey is registered in its own goroutine, allowing for independent handling of keydown events. ```go for _, spec := range hotkeySpecs { go func(s spec) { hk := hotkey.New(s.Mods, s.Key) hk.Register() for { <-hk.Keydown() // Handle keydown } }(spec) } ``` -------------------------------- ### New Hotkey Constructor Source: https://github.com/golang-design/hotkey/blob/main/_autodocs/api-reference/hotkey.md Creates a new hotkey with the specified modifiers and key. The returned hotkey is not yet registered with the system. ```APIDOC ## New Creates a new hotkey with the specified modifiers and key. ### Signature: ```go func New(mods []Modifier, key Key) *Hotkey ``` ### Parameters: #### Path Parameters - **mods** (`[]Modifier`) - Required - Slice of modifiers (e.g., ModCtrl, ModShift). Order is insignificant. Empty slice is valid for unmodified keys. - **key** (`Key`) - Required - The key code as a Key constant or raw uint32 value. ### Return Type: - `*Hotkey`: A pointer to a newly created Hotkey. The returned hotkey is not yet registered with the system. ### Example: ```go package main import ( "golang.design/x/hotkey" ) func main() { // Create a hotkey for Ctrl+Shift+S hk := hotkey.New( []hotkey.Modifier{hotkey.ModCtrl, hotkey.ModShift}, hotkey.KeyS, ) _ = hk // Use the hotkey } ``` ```