winput

package module
v1.2.4 Latest Latest
Warning

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

Go to latest
Published: Jan 30, 2026 License: MIT Imports: 9 Imported by: 0

README

winput

Ask DeepWiki

winput is a lightweight, high-performance Go library for Windows background input automation.

It provides a unified, window-centric API that abstracts the underlying input mechanism, allowing seamless switching between standard Window Messages (PostMessage) and kernel-level injection (Interception driver).

Features

  • Pure Go (No CGO): Uses dynamic DLL loading. No GCC required for compilation.
  • Window-Centric API: Operations are performed on Window objects, not raw HWNDs.
  • Background Input:
    • Message Backend: Sends inputs directly to window message queues. Works without window focus or mouse cursor movement.
    • HID Backend: Uses the Interception driver to simulate hardware input at the kernel level.
  • Coordinate Management:
    • Unified Client Coordinate system for all APIs.
    • Built-in ScreenToClient / ClientToScreen conversion.
    • DPI Awareness: Helpers for Per-Monitor DPI scaling.
  • Safety & Reliability:
    • Thread-Safe: Global input serialization ensures atomic operations (inputMutex).
    • Explicit error returns (no silent failures).
    • Type-safe Key definitions.
  • Keyboard Layout:
    • The KeyFromRune and Type functions currently assume a US QWERTY keyboard layout.

Vision Automation (Electron / Games)

Ideal for applications where window handles are unreliable.

import (
	"github.com/rpdg/winput"
	"github.com/rpdg/winput/screen"
)

func main() {
	winput.EnablePerMonitorDPI()

	// 1. Capture the entire virtual desktop (all monitors)
	img, err := screen.CaptureVirtualDesktop()
	// Or capture a specific region:
	// img, err := screen.CaptureRegion(0, 0, 1920, 1080)
	if err != nil {
		panic(err)
	}
	// img is a standard *image.RGBA, ready for OpenCV/GoCV

	// 2. Perform your CV matching here (pseudo-code)
	// matchX, matchY := yourCVLib.Match(img, template)

	// 3. Convert image coordinates to virtual desktop coordinates
	targetX, targetY := screen.ImageToVirtual(int32(matchX), int32(matchY))

	// 4. Move and Click
	winput.MoveMouseTo(targetX, targetY)
	winput.ClickMouseAt(targetX, targetY)
}

API Reference

Backend Limitations & Permissions

Message Backend
  • Mechanism: Uses PostMessageW.
  • Pros: No focus required, no mouse movement, works in background.
  • Cons:
    • Modifier Keys: PostMessage does not update global keyboard state. Apps checking GetKeyState (e.g. for Ctrl+C) might fail.
    • UIPI: Cannot send messages to apps running as Administrator if your app is not.
    • Coordinates: Limited to 16-bit signed integer range ([-32768, 32767]). Larger coordinates will be clipped.
    • Compatibility: Some games (DirectX/OpenGL/RawInput) and frameworks (Qt/WPF) ignore these messages.
HID Backend
  • Mechanism: Uses Interception driver (kernel-level).
  • Context: Uses a global driver context (singleton). Safe for automation scripts, but be aware if integrating into larger apps.
  • Pros: Works with almost everything (games, anti-cheat), undetectable as software input.
  • Cons:
    • Driver Required: Must install Interception driver.
    • Blocking: Move operations are synchronous and blocking (to simulate human speed).
    • Mouse Movement: Physically moves the cursor.
    • Focus: Usually requires the window to be active/foreground.

Installation

go get github.com/rpdg/winput
HID Support (Optional)

This library is Pure Go and does not require CGO. To use the HID backend:

  1. Install the Interception driver.
  2. Place interception.dll in your app directory, or specify its path:
    winput.SetHIDLibraryPath("libs/interception.dll")
    if err := winput.SetBackend(winput.BackendHID); err != nil {
        // Handle error (e.g. fallback to Message backend)
        panic(err)
    }
    

Usage Examples

1. Basic Message Backend (Standard Apps)

Ideal for standard windows (Notepad, etc.). Works in background. Tip: For some apps (like Notepad), you may need to find the child window (e.g., "Edit") to send text.

go run cmd/example/basic_message/main.go
2. Global Vision Automation (Electron / Games)

For apps where HWND is unreliable (VS Code, Discord, Games). Uses absolute screen coordinates. Tip: Use screen.ImageToVirtual(x, y) to convert OpenCV screenshot coordinates to winput coordinates.

go run cmd/example/global_vision/main.go
3. HID Backend (Hardware Simulation)

Simulates physical hardware input. Requires driver.

go run cmd/example/advanced_hid/main.go

Quick Start (Code Snippet)

package main

import (
	"log"
	"github.com/rpdg/winput"
)

func main() {
	// 1. Find target window
	w, err := winput.FindByTitle("Untitled - Notepad")
	if err != nil {
		log.Fatal(err)
	}

	// 2. Click (Left Button)
	if err := w.Click(100, 100); err != nil {
		log.Fatal(err)
	}

	// 3. Type text
	w.Type("Hello World")
	w.Press(winput.KeyEnter)

	// 4. Global Input (Target independent)
	winput.Type("Hello Electron!")
	winput.Press(winput.KeyEnter)

	// 5. Using winput/screen (Boundary query)
	// import "github.com/rpdg/winput/screen"
	bounds := screen.VirtualBounds()
	fmt.Printf("Virtual Desktop Bounds: %d, %d\n", bounds.Right, bounds.Bottom)
}

Error Handling

winput avoids silent failures. Common errors you should handle:

Error Variable Description Handling
ErrWindowNotFound Window not found by Title/Class/PID. Check if the app is running or use FindByClass as fallback.
ErrDriverNotInstalled Interception driver missing (HID mode only). Prompt user to install the driver or fallback to Message backend.
ErrDLLLoadFailed interception.dll not found or invalid. Check DLL path (SetHIDLibraryPath) or installation.
ErrUnsupportedKey Character cannot be mapped to a key. Check input string encoding or use raw KeyDown for special keys.
ErrPermissionDenied Operation blocked (e.g., UIPI). Run your application as Administrator.

Example of robust error handling:

// SetBackend now fails fast if the driver or DLL is missing.
if err := winput.SetBackend(winput.BackendHID); err != nil {
    log.Printf("HID backend not available: %v. Falling back to Message backend.", err)
    // No need to explicitly set BackendMessage, as it is the default.
}

// All subsequent calls will use the successfully set backend.
if err := w.Click(100, 100); err != nil {
    log.Fatal(err)
}

Advanced Usage

1. Handling High-DPI Monitors

Modern Windows scales applications. To ensure your (100, 100) click lands on the correct pixel:

// Call this at program start
if err := winput.EnablePerMonitorDPI(); err != nil {
    log.Printf("DPI Awareness failed: %v", err)
}

// Check window specific DPI (96 is standard 100%)
dpi, _ := w.DPI()
fmt.Printf("Target Window DPI: %d (Scale: %.2f%%)
", dpi, float64(dpi)/96.0*100)
2. HID Backend with Fallback

Use HID for games/anti-cheat, fallback to Message for standard apps.

// Try to enable HID backend
if err := winput.SetBackend(winput.BackendHID); err != nil {
    log.Println("HID init failed, using default Message backend:", err)
    // No action needed, default is already BackendMessage
}

w.Type("password") // Works with whatever backend is active
3. Key Mapping Details

winput maps runes to Scan Codes (Set 1).

  • Supported: A-Z, 0-9, Common Symbols (!, @, #...), Space, Enter, Tab.
  • Auto-Shift: Type("A") automatically sends Shift Down -> a Down -> a Up -> Shift Up.

Comparison

Feature winput (Go) C# Interceptor Wrappers Python winput (ctypes)
Backends Dual (HID + Message) HID (Interception) Only Message (User32) Only
API Style Object-Oriented (w.Click) Low-level (SendInput) Function-based
Dependency None (Default) / Driver (HID) Driver Required None
Safety Explicit Errors Exceptions / Silent Silent / Return Codes
DPI Aware ✅ Yes ❌ Manual calc needed ❌ Manual calc needed
  • vs Python winput: Python's version is great for simple automation but lacks the kernel-level injection capability required for games or stubborn applications.
  • vs C# Interceptor: Most C# wrappers expose the raw driver API. winput abstracts this into high-level actions (Click, Type) and adds coordinate translation logic.

Selection Guide: winput vs robotgo

Feature robotgo winput
Input Level OS Synthetic (SendInput / Events) Kernel Driver (Interception) + OS Message
Background Control ❌ Fails often Native Support (PostMessage)
Anti-Cheat / Protected Apps ❌ Blocked Bypasses most protections (HID level)
Coordinate System Implicit / Device-dependent Explicit Virtual Desktop (DPI-aware)
Visual Integration Basic Engineered for OpenCV/OCR (Capture -> Map -> Input)
Cross-Platform ✅ (Win/Mac/Linux) ❌ (Windows Optimized)
Use Case Quick scripts, simple GUI automation Engineering-grade automation, Games, Electron, Background tasks

Summary:

  • Use robotgo for quick, cross-platform scripts where reliability in edge cases (games, background) is not critical.
  • Use winput when you need determinism, driver-level control, or need to interact with background windows, games, or Electron apps that ignore standard input injection.

License

MIT

Documentation

Overview

Package winput provides a Windows input automation library focused on background operation. It abstracts input injection to support multiple backends while maintaining a consistent, object-centric API.

Key Features:

1. Pure Go & No CGO: This library uses dynamic DLL loading (syscall.LoadLibrary) and does not require a CGO compiler environment (GCC) for building.

2. Dual Input Backends:

  • BackendMessage (Default): Uses PostMessage for background input. It does not require focus and is ideal for non-intrusive automation.
  • BackendHID: Uses the Interception driver for kernel-level simulation (requires driver installation). This mode simulates hardware-level input, complete with human-like mouse movement trajectories and jitter. Supports custom DLL path via SetHIDLibraryPath.

3. Coordinate System & Screen Management:

  • Window-Centric: Operations on *Window use client coordinates.
  • Global Input: MoveMouseTo/ClickMouseAt/Type for absolute virtual desktop coordinates (useful for Electron/Games).
  • Child Windows: FindChildByClass for targeting specific controls (e.g. "Edit" in Notepad).
  • Screen Package: winput/screen helpers for querying monitor bounds and virtual desktop geometry.
  • DPI Awareness: Per-Monitor v2 support for accurate mapping.

4. Intelligent Keyboard Input:

  • Type(string) automatically handles Shift modifiers for uppercase letters and symbols.
  • Uses Scan Codes (Set 1) for maximum compatibility with low-level hooks and games.

5. Robust Error Handling: Defines standard errors like ErrWindowNotFound, ErrDriverNotInstalled, ErrPostMessageFailed. It follows an "explicit failure" principle, where backend initialization errors are reported on the first attempted action.

6. Thread Safety: All public input methods are thread-safe and serialized using an internal mutex. This prevents state pollution (e.g., mixing Shift states from concurrent operations) and race conditions when switching backends.

Example:

 // For complete examples, see cmd/example/
 // - basic_message: Background automation for standard apps
 // - global_vision: Electron/Game automation using screen coordinates
 // - advanced_hid: Hardware level simulation

	// 1. Find the window
	w, err := winput.FindByTitle("Untitled - Notepad")
	if err != nil {
	    log.Fatal(winput.ErrWindowNotFound)
	}

	// 2. Setup DPI awareness (optional but recommended)
	winput.EnablePerMonitorDPI()

	// 3. Perform actions (using default Message backend)
	w.Click(100, 100)       // Left click
	w.ClickRight(100, 100)  // Right click
	w.Scroll(100, 100, 120) // Vertical scroll

	w.Type("Hello World!")  // Automatically handles Shift for 'H', 'W', and '!'
	w.Press(winput.KeyEnter)

	// 4. Global Input (Visual Automation / Electron)
	// winput.MoveMouseTo(1920, 500)
	// winput.ClickMouseAt(1920, 500)

	// 5. Switch to HID backend for hardware-level simulation
	// winput.SetHIDLibraryPath("libs/interception.dll")
	// winput.SetBackend(winput.BackendHID)

Index

Constants

View Source
const (
	KeyEsc       = keyboard.KeyEsc
	Key1         = keyboard.Key1
	Key2         = keyboard.Key2
	Key3         = keyboard.Key3
	Key4         = keyboard.Key4
	Key5         = keyboard.Key5
	Key6         = keyboard.Key6
	Key7         = keyboard.Key7
	Key8         = keyboard.Key8
	Key9         = keyboard.Key9
	Key0         = keyboard.Key0
	KeyMinus     = keyboard.KeyMinus
	KeyEqual     = keyboard.KeyEqual
	KeyBkSp      = keyboard.KeyBkSp
	KeyTab       = keyboard.KeyTab
	KeyQ         = keyboard.KeyQ
	KeyW         = keyboard.KeyW
	KeyE         = keyboard.KeyE
	KeyR         = keyboard.KeyR
	KeyT         = keyboard.KeyT
	KeyY         = keyboard.KeyY
	KeyU         = keyboard.KeyU
	KeyI         = keyboard.KeyI
	KeyO         = keyboard.KeyO
	KeyP         = keyboard.KeyP
	KeyLBr       = keyboard.KeyLBr
	KeyRBr       = keyboard.KeyRBr
	KeyEnter     = keyboard.KeyEnter
	KeyCtrl      = keyboard.KeyCtrl
	KeyA         = keyboard.KeyA
	KeyS         = keyboard.KeyS
	KeyD         = keyboard.KeyD
	KeyF         = keyboard.KeyF
	KeyG         = keyboard.KeyG
	KeyH         = keyboard.KeyH
	KeyJ         = keyboard.KeyJ
	KeyK         = keyboard.KeyK
	KeyL         = keyboard.KeyL
	KeySemi      = keyboard.KeySemi
	KeyQuot      = keyboard.KeyQuot
	KeyTick      = keyboard.KeyTick
	KeyShift     = keyboard.KeyShift
	KeyBackslash = keyboard.KeyBackslash
	KeyZ         = keyboard.KeyZ
	KeyX         = keyboard.KeyX
	KeyC         = keyboard.KeyC
	KeyV         = keyboard.KeyV
	KeyB         = keyboard.KeyB
	KeyN         = keyboard.KeyN
	KeyM         = keyboard.KeyM
	KeyComma     = keyboard.KeyComma
	KeyDot       = keyboard.KeyDot
	KeySlash     = keyboard.KeySlash
	KeyAlt       = keyboard.KeyAlt
	KeySpace     = keyboard.KeySpace
	KeyCaps      = keyboard.KeyCaps
	KeyF1        = keyboard.KeyF1
	KeyF2        = keyboard.KeyF2
	KeyF3        = keyboard.KeyF3
	KeyF4        = keyboard.KeyF4
	KeyF5        = keyboard.KeyF5
	KeyF6        = keyboard.KeyF6
	KeyF7        = keyboard.KeyF7
	KeyF8        = keyboard.KeyF8
	KeyF9        = keyboard.KeyF9
	KeyF10       = keyboard.KeyF10
	KeyF11       = keyboard.KeyF11
	KeyF12       = keyboard.KeyF12
	KeyNumLock   = keyboard.KeyNumLock
	KeyScroll    = keyboard.KeyScroll

	KeyHome      = keyboard.KeyHome
	KeyArrowUp   = keyboard.KeyArrowUp
	KeyPageUp    = keyboard.KeyPageUp
	KeyLeft      = keyboard.KeyLeft
	KeyRight     = keyboard.KeyRight
	KeyEnd       = keyboard.KeyEnd
	KeyArrowDown = keyboard.KeyArrowDown
	KeyPageDown  = keyboard.KeyPageDown
	KeyInsert    = keyboard.KeyInsert
	KeyDelete    = keyboard.KeyDelete
)
View Source
const (
	INPUT_KEYBOARD    = 1
	KEYEVENTF_UNICODE = 0x0004
	KEYEVENTF_KEYUP   = 0x0002
)

Variables

View Source
var (
	// ErrWindowNotFound implies the target window could not be located by Title, Class, or PID.
	ErrWindowNotFound = errors.New("window not found")

	// ErrWindowGone implies the window handle is no longer valid.
	ErrWindowGone = errors.New("window is gone or invalid")

	// ErrWindowNotVisible implies the window is hidden or minimized.
	ErrWindowNotVisible = errors.New("window is not visible")

	// ErrUnsupportedKey implies the character cannot be mapped to a key.
	ErrUnsupportedKey = errors.New("unsupported key or character")

	// ErrBackendUnavailable implies the selected backend (e.g. HID) failed to initialize.
	ErrBackendUnavailable = errors.New("input backend unavailable")

	// ErrDriverNotInstalled specific to BackendHID, implies the Interception driver is missing or not accessible.
	ErrDriverNotInstalled = errors.New("interception driver not installed or accessible")

	// ErrDLLLoadFailed implies interception.dll could not be loaded.
	ErrDLLLoadFailed = errors.New("failed to load interception library")

	// ErrPermissionDenied implies the operation failed due to system privilege restrictions (e.g. UIPI).
	ErrPermissionDenied = errors.New("permission denied")

	// ErrPostMessageFailed implies the PostMessageW call returned 0.
	ErrPostMessageFailed = window.ErrPostMessageFailed
)

Functions

func ClickMiddleMouseAt

func ClickMiddleMouseAt(x, y int32) error

ClickMiddleMouseAt moves to the specified screen coordinates and performs a middle click.

func ClickMouseAt

func ClickMouseAt(x, y int32) error

ClickMouseAt moves to the specified screen coordinates and performs a left click.

func ClickRightMouseAt

func ClickRightMouseAt(x, y int32) error

ClickRightMouseAt moves to the specified screen coordinates and performs a right click.

func DoubleClickMouseAt

func DoubleClickMouseAt(x, y int32) error

DoubleClickMouseAt moves to the specified screen coordinates and performs a left double-click.

func EnablePerMonitorDPI

func EnablePerMonitorDPI() error

EnablePerMonitorDPI sets the process to be Per-Monitor DPI aware.

func GetCursorPos

func GetCursorPos() (int32, int32, error)

GetCursorPos returns the current cursor position in screen coordinates.

func KeyDown

func KeyDown(k Key) error

KeyDown simulates a global key down event.

func KeyUp

func KeyUp(k Key) error

KeyUp simulates a global key up event.

func MoveMouseTo

func MoveMouseTo(x, y int32) error

MoveMouseTo moves the mouse cursor to the specified absolute screen coordinates (Virtual Desktop).

func Press

func Press(k Key) error

Press simulates a global key press (down then up).

func PressHotkey

func PressHotkey(keys ...Key) error

PressHotkey simulates a global combination of keys.

func SetBackend

func SetBackend(b Backend) error

SetBackend sets the input simulation backend. If BackendHID is selected, it attempts to initialize the Interception driver immediately. Returns an error if the driver or DLL cannot be loaded.

func SetHIDLibraryPath

func SetHIDLibraryPath(path string)

SetHIDLibraryPath sets the path to the interception.dll library.

func Type

func Type(text string) error

Type simulates typing text globally.

Types

type Backend

type Backend int

Backend represents the input simulation backend.

const (
	// BackendMessage uses Windows messages (PostMessage) for input simulation.
	BackendMessage Backend = iota
	// BackendHID uses the Interception driver for hardware-level input simulation.
	BackendHID
)

type Key

type Key = keyboard.Key

func KeyFromRune

func KeyFromRune(r rune) (Key, bool)

KeyFromRune attempts to map a unicode character to a Key.

type Window

type Window struct {
	HWND uintptr
}

Window represents a handle to a window.

func FindByClass

func FindByClass(class string) (*Window, error)

FindByClass searches for a top-level window matching the specified class name.

func FindByPID

func FindByPID(pid uint32) ([]*Window, error)

FindByPID returns all top-level windows belonging to the specified Process ID.

func FindByProcessName

func FindByProcessName(name string) ([]*Window, error)

FindByProcessName searches for all top-level windows belonging to a process with the given executable name.

func FindByTitle

func FindByTitle(title string) (*Window, error)

FindByTitle searches for a top-level window matching the exact title.

func (*Window) Click

func (w *Window) Click(x, y int32) error

Click simulates a left mouse button click at the specified client coordinates.

func (*Window) ClickMiddle

func (w *Window) ClickMiddle(x, y int32) error

ClickMiddle simulates a middle mouse button click at the specified client coordinates.

func (*Window) ClickRight

func (w *Window) ClickRight(x, y int32) error

ClickRight simulates a right mouse button click at the specified client coordinates.

func (*Window) ClientRect

func (w *Window) ClientRect() (width, height int32, err error)

ClientRect returns the client area dimensions of the window.

func (*Window) ClientToScreen

func (w *Window) ClientToScreen(x, y int32) (sx, sy int32, err error)

ClientToScreen converts client coordinates to screen coordinates.

func (*Window) DPI

func (w *Window) DPI() (uint32, uint32, error)

DPI returns the DPI of the window.

func (*Window) DoubleClick

func (w *Window) DoubleClick(x, y int32) error

DoubleClick simulates a left mouse button double-click at the specified client coordinates.

func (*Window) FindChildByClass

func (w *Window) FindChildByClass(class string) (*Window, error)

FindChildByClass searches for a child window with the specified class name.

func (*Window) IsValid

func (w *Window) IsValid() bool

IsValid checks if the window handle is valid.

func (*Window) IsVisible

func (w *Window) IsVisible() bool

IsVisible checks if the window is visible and not minimized.

func (*Window) KeyDown

func (w *Window) KeyDown(key Key) error

KeyDown sends a key down event to the window.

func (*Window) KeyUp

func (w *Window) KeyUp(key Key) error

KeyUp sends a key up event to the window.

func (*Window) Move

func (w *Window) Move(x, y int32) error

Move simulates mouse movement to the specified client coordinates.

func (*Window) MoveRel

func (w *Window) MoveRel(dx, dy int32) error

MoveRel simulates relative mouse movement from the current cursor position.

func (*Window) Press

func (w *Window) Press(key Key) error

Press simulates a key press (down then up).

func (*Window) PressHotkey

func (w *Window) PressHotkey(keys ...Key) error

PressHotkey presses a combination of keys (e.g., Ctrl+A).

func (*Window) ScreenToClient

func (w *Window) ScreenToClient(x, y int32) (cx, cy int32, err error)

ScreenToClient converts screen coordinates to client coordinates.

func (*Window) Scroll

func (w *Window) Scroll(x, y int32, delta int32) error

Scroll simulates a vertical mouse wheel scroll.

func (*Window) Type

func (w *Window) Type(text string) error

Type simulates typing text.

Directories

Path Synopsis
cmd
hid

Jump to

Keyboard shortcuts

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