This repository contains a library to read and control WiiMotes and other controllers for the Wii. Originally it was written as a binding to libwiimote but is rewritten in pure Go1. Detailed documentation is located here.
1 go-wiimote makes used of pkg/udev which is a binding to libudev to receive device information and watch for new devices. Additionally go-wiimote asks for kernel-dependant constants (key-codes and syscalls) which are obtained using cgo.
wiimote
├── pkg
│ ├── irpointer -- algorithm to convert IR events to a pointer on a screen
│ ├── udev -- bindings to libudev
│ │ └── sequences -- utilities for iter.Seq (like slices, maps)
│ └── uinput -- library to create a virtual input device using Linux' uinput
└── cmd
├── wiimap -- utility to map wiimote buttons to physical keys.
└── wiipointer -- utility to use wiimote as mouse using IR-tracking.
libwiimote is a library which cooperates with the wiimote-kernel driver which is included since Linux 3.1 and supersedes cwiid which is a driverless implementation.
Supported devices are:
- Nintendo Wii Remote (Nintendo RVL-CNT-01)
- Nintendo Wii Remote Plus (Nintendo RVL-CNT-01-TR)
- Nintendo Wii Nunchuk Extension
- Nintendo Wii Classic Controller Extension
- Nintendo Wii Classic Controller Pro Extension
- Nintendo Wii Balance Board (Nintendo RVL-WBC-01)
- Nintendo Wii U Pro Controller (Nintendo RVL-CNT-01-UC)
- Nintendo Wii Guitar Extensions
- Nintendo Wii Drums Extensions
- Linux 3.1 or newer (3.11 or newer recommended)
- bluez 4.101 or newer (bluez-5.0 or newer recommended)
- Go 1.24 or newer
- libudev
For example usage you can check the cmd-directory.
First you have to choose whether you want to monitor for new devices or only use currently available devices. If you want to monitor for new devices you should use Montor:
monitor := wiimote.NewMonitor(wiimote.MonitorUdev)
defer monitor.Free()
for {
// Wait infinitely for a new device.
path, err := monitor.Wait(-1)
if err != nil || path == "" {
log.Printf("error while polling: %v\n", err)
continue
}
-> device at path
}If you only want to use currently available devices, you can use the IterDevices-function:
for path := range wiimote.IterDevices(wiimote.MonitorUdev) {
-> device at path
}The path returned points at the sysfs location.
This is a sparse example how to create a new device. Refer to the documentation for more information.
// create a new device which is located at path
dev, err := wiimote.NewDevice(path)
if err != nil {
log.Fatalf("error: unable to get device: %s", err)
}
// freeing is not mandatory and is done automatically by GC.
defer dev.Free()
// open features, we're only interested in core functionality.
if err := dev.Open(wiimote.FeatureCore); err != nil {
log.Fatalf("error: unable to open device: %s", err)
}
for {
// Wait infinitely for a new event.
ev, err := dev.Wait(-1)
if err != nil {
log.Printf("unable to poll event: %v\n", err)
}
switch ev := ev.(type) {
case *wiimote.EventKey:
log.Printf("key event: %v\n", ev.Code)
}
}The IRPointer has a state which must be updated when appropriate, after updating the health and position can be read.
pointer := irpointer.NewIRPointer(nil)
var (
lastIR *wiimote.EventIR
lastAccel *wiimote.EventAccel
)
for {
ev, err := dev.Wait(-1)
if err != nil {
log.Printf("unable to poll event: %v\n", err)
}
switch ev := ev.(type) {
case *wiimote.EventIR:
lastIR = ev
case *wiimote.EventAccel:
lastAccel = ev
if lastIR != nil && lastAccel != nil {
pointer.Update(lastIR.Slots, lastAccel.Accel)
/* optionally only update when there is a new IR AND Accel event
lastIR = nil
lastAccel = nil
*/
}
// if the pointer has sufficient health and a valid position -> do somthing
if pointer.Health >= irpointer.IRSingle && pointer.Position != nil {
x, y := pointer.Position.X, pointer.Position.Y
if x >= -340 && x < 340 && y >= -92 && y < 290 {
fmt.Printf("[%v] pointer at (%.2f %.2f) at %.2fm distance\n", pointer.Health, pointer.Position.X, pointer.Position.Y, pointer.Distance)
}
}
}Feel free to add functionality and make a pull request!
This project makes use of morestringer to generate .String() methods for enums.
- Install
morestringer:go install github.com/friedelschoen/morestringer - Run generators:
go generate ./...
Before submitting any changes, please format the project using gofmt.
The irpointer package is licensed under 2-clause-BSD License (as noted in the source), remaining code is licensed under Zlib License.