Skip to content

roryl23/xpad-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

xpad-go

Go bindings for Xbox-compatible controllers.

On Linux, this package targets the kernel xpad driver (evdev, joystick, sysfs). On Windows, it uses XInput and exposes connected controllers as xinput://0 through xinput://3. On macOS, it uses IOKit HID and exposes connected controllers as iokit://... devices.

Support

  • Linux: wired Xbox 360 controller only (this is the only device tested/supported today).
  • Windows: XInput-compatible controllers, with discovery, input polling, and rumble.
  • macOS: IOKit HID game controllers, with discovery and input polling. Rumble is not supported.
  • PRs welcome for broader controller support and other features.

If you need something implemented, be the change you want to see in the world and open a PR!

Linux-only APIs: joystick devices, sysfs LED control, and kernel module parameters. Windows and macOS native controller paths do not have an underlying os.File or file descriptor, so File and FD return ErrNotImplemented. The macOS IOKit backend requires cgo; builds with cgo disabled return ErrNotImplemented for discovery/opening.

Install the xpad driver (Linux)

The xpad driver ships with the Linux kernel. In most distros it is already available as a loadable kernel module.

  1. Plug in the Xbox 360 controller (USB or wireless receiver).
  2. Load the module if it is not already loaded:
sudo modprobe xpad
  1. Verify the devices are present:
ls -l /dev/input/event*
ls -l /dev/input/js*
ls -l /sys/class/leds/xpad*

If you do not see the devices, confirm the kernel module is loaded:

lsmod | grep xpad

Permissions: reading /dev/input/* and writing to /sys/class/leds/* typically require elevated privileges or a udev rule that grants your user access.

Install the Go library

go get github.com/roryl23/xpad-go

Quick start

package xpad

func ExampleDevice_ReadEvent() {
	devices, err := FindXpadDevices()
	if err != nil {
		panic(err)
	}
	if len(devices) == 0 {
		panic(ErrNotFound)
	}

	dev, err := OpenDevice(devices[0])
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := dev.Close(); err != nil {
			panic(err)
		}
	}()

	event, err := dev.ReadEvent(-1)
	if err != nil {
		panic(err)
	}
	_ = event
}

On Windows, FindXpadDevices scans XInput slots and returns paths like xinput://0. On macOS, it scans IOKit HID game controllers and returns paths like iokit://.... ReadEvent polls platform state changes and maps them to the existing event constants.

LED control (Linux)

package xpad

func ExampleDeviceInfo_SetLED() {
	devices, err := FindXpadDevices()
	if err != nil {
		panic(err)
	}
	if len(devices) == 0 {
		panic(ErrNotFound)
	}

	info := devices[0]
	if err := info.SetLED(LEDPlayer1); err != nil {
		panic(err)
	}
}

LED command values:

  • 0: off
  • 1: all blink, then previous setting
  • 2-5: 1-4 blink, then on
  • 6-9: 1-4 on
  • 10: rotate
  • 11: blink based on previous setting
  • 12: slow blink based on previous setting
  • 13: rotate with two lights
  • 14: persistent slow all blink
  • 15: blink once, then previous setting

Rumble

package xpad

import "time"

func ExampleDevice_Rumble() {
	dev, err := OpenFirstXpad()
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := dev.Close(); err != nil {
			panic(err)
		}
	}()

	id, err := dev.UploadRumble(NewRumbleEffect(0xffff, 0x7fff, 500*time.Millisecond))
	if err != nil {
		panic(err)
	}
	if err := dev.PlayEffect(id, 1); err != nil {
		panic(err)
	}
}

Joystick API (Linux)

package xpad

func ExampleJoystick_ReadEvent() {
	devices, err := FindXpadDevices()
	if err != nil {
		panic(err)
	}
	if len(devices) == 0 {
		panic(ErrNotFound)
	}

	js, err := devices[0].OpenJoystick()
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := js.Close(); err != nil {
			panic(err)
		}
	}()

	evt, err := js.ReadEvent(-1)
	if err != nil {
		panic(err)
	}
	_ = evt
}

Tests

The integration tests require a controller connected on Linux. If one is not present, the tests that require it will be skipped.

XPAD_INTERACTIVE=1 go test -run TestIntegrationControllerButtons -v

Use XPAD_EVENT_PATH or XPAD_JOYSTICK_PATH to point tests at a specific controller if discovery fails.

To verify the Windows build from another platform:

GOOS=windows GOARCH=amd64 go test -exec true ./...

To verify the macOS fallback build from another platform:

GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go test -exec true ./...

Resources

Packages

 
 
 

Contributors

Languages