keyboard

package module
v1.0.12 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 23, 2025 License: Apache-2.0 Imports: 5 Imported by: 0

README

go-keyboard-capture

Keyboard Capture API

A simple and flexible Go API for capturing keyboard events in real-time, including special keys like arrows. Works on Linux and macOS (raw mode not supported on Windows).

Features

  • ✅ Capture individual key presses
  • ✅ Support for arrow keys and special keys
  • ✅ Context-based cancellation for clean shutdown
  • ✅ Non-blocking event-driven architecture
  • ✅ Easy integration into other projects

Installation

go get github.com/FireAnomaly/go-keyboard-capture

Or copy keyboard.go into your project.

Quick Start

package main

import (
    "context"
    "fmt"
    
    "github.com/FireAnomaly/keyboard-capture"
)

func main() {
    events := make(chan main.KeyEvent)
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    if err := main.CaptureKeyboard(ctx, events); err != nil {
        fmt.Println("Error:", err)
        return
    }

    for event := range events {
        if event.Key != 0 {
            fmt.Printf("Key: %c\n", event.Key)
        }
    }
}

API Reference

Types
KeyEvent

Represents a keyboard event.

type KeyEvent struct {
    Key  rune  // Character for printable keys (e.g., 'a', '1')
    Code int   // Code for special keys (0 for regular keys)
}

Special Key Codes:

  • 1 - Up arrow
  • 2 - Down arrow
  • 3 - Right arrow
  • 4 - Left arrow
  • 5 - Clear line (Ctrl+L)
Functions
CaptureKeyboard(ctx context.Context, events chan<- KeyEvent) error

Starts capturing keyboard input in a goroutine and sends events to the provided channel.

Parameters:

  • ctx - Context for cancellation control
  • events - Channel to receive keyboard events

Returns:

  • error - Returns error if raw mode cannot be enabled (e.g., on Windows)

Example:

events := make(chan KeyEvent)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

if err := CaptureKeyboard(ctx, events); err != nil {
    log.Fatal(err)
}

for event := range events {
    // Handle events
}

Complete Examples

Example 1: Basic Usage
package main

import (
    "context"
    "fmt"
)

func main() {
    events := make(chan KeyEvent)
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    CaptureKeyboard(ctx, events)

    for event := range events {
        if event.Key == 'q' {
            cancel()
            break
        }
        fmt.Printf("Pressed: %c\n", event.Key)
    }
}
Example 2: With Signal Handling
package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "syscall"
)

func main() {
    events := make(chan KeyEvent)
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    // Handle Ctrl+C
    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
    go func() {
        <-sigChan
        fmt.Println("\nShutting down...")
        cancel()
    }()

    if err := CaptureKeyboard(ctx, events); err != nil {
        fmt.Println("Error:", err)
        return
    }

    for event := range events {
        if event.Key != 0 {
            fmt.Printf("Key: %c\n", event.Key)
        } else {
            switch event.Code {
            case 1: fmt.Println("↑")
            case 2: fmt.Println("↓")
            case 3: fmt.Println("→")
            case 4: fmt.Println("←")
            case 5: fmt.Println("Clear Line")
            }
        }
    }
}
Example 3: Game-like Input Handler
package main

import (
    "context"
    "fmt"
    "time"
)

type Position struct {
    X, Y int
}

func main() {
    events := make(chan KeyEvent)
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    CaptureKeyboard(ctx, events)

    pos := Position{X: 5, Y: 5}
    
    ticker := time.NewTicker(100 * time.Millisecond)
    defer ticker.Stop()

    for {
        select {
        case event, ok := <-events:
            if !ok {
                return
            }
            switch event.Code {
            case 1: pos.Y-- // Up
            case 2: pos.Y++ // Down
            case 3: pos.X++ // Right
            case 4: pos.X-- // Left
            }
            if event.Key == 'q' {
                cancel()
                return
            }
        case <-ticker.C:
            fmt.Printf("\rPosition: (%d, %d) ", pos.X, pos.Y)
        }
    }
}

Platform Support

Platform Support Notes
Linux ✅ Yes Full support
macOS ✅ Yes Full support
Windows ❌ No Raw mode not available via stty

Best Practices

  1. Always use context for cancellation: Never rely on the deprecated Stop() function
  2. Handle signals: Implement SIGINT/SIGTERM handlers for clean shutdown
  3. Defer cancel(): Always defer the context cancel function
  4. Close channels: The API automatically closes the events channel when done
  5. Error handling: Check the error returned by CaptureKeyboard()

Troubleshooting

Terminal doesn't respond after program crash

If your program crashes without restoring terminal mode, run:

stty sane
Keys not being captured

Ensure your terminal supports raw mode and the program has proper stdin access.

License

MIT License - Feel free to use in your projects!

Contributing

Contributions are welcome! Please submit issues and pull requests.

Documentation

Index

Constants

View Source
const (
	KeyUpArrow    = 1
	KeyDownArrow  = 2
	KeyRightArrow = 3
	KeyLeftArrow  = 4
	KeyClearLine  = 5
)

Variables

This section is empty.

Functions

func CaptureKeyboard

func CaptureKeyboard(ctx context.Context, events chan<- KeyEvent) error

CaptureKeyboard starts capturing keyboard input and sends events to the provided channel. It runs in a goroutine and can be stopped via the context. Returns an error if raw mode fails.

Types

type KeyEvent

type KeyEvent struct {
	Key  rune
	Code int // For special keys like arrows
}

KeyEvent represents a keyboard event

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL