wiimote

package module
v0.3.2-0...-75e00e6 Latest Latest
Warning

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

Go to latest
Published: Mar 1, 2026 License: Zlib Imports: 5 Imported by: 0

README

go-wiimote - Read and Control Wii devices

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

Prerequisite

  • 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

Usage

For example usage you can check the cmd-directory.

Find new devices

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.

Create a device

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)
    }
}
Use a IR pointer

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)
        }
    }
}

Contributing

Feel free to add functionality and make a pull request!

Tooling

This project makes use of morestringer to generate .String() methods for enums.

  • Install morestringer:
    go install github.com/friedelschoen/morestringer
    
  • Run generators:
    go generate ./...
    
Formatting

Before submitting any changes, please format the project using gofmt.

Licensing

The irpointer package is licensed under 2-clause-BSD License (as noted in the source), remaining code is licensed under Zlib License.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Device

type Device interface {
	fmt.Stringer
	Poller[Event]

	// Syspath returns the sysfs path of the underlying device. It is not neccesarily
	// the same as the one during NewDevice. However, it is guaranteed to
	// point at the same device (symlinks may be resolved).
	Syspath() string

	// OpenFeatures all the requested features. If FeatureWritable is also set,
	// the features are opened with write-access. Note that features that are
	// already opened are ignored and not touched.
	// If any feature fails to open, this function still tries to open the other
	// requested features and then returns the error afterwards. Hence, if this
	// function fails, you should use Opened() to get a bitmask of opened
	// features and see which failed (if that is of interest).
	//
	// Note that features may be closed automatically during runtime if the
	// kernel removes the feature or on error conditions. You always get an
	// EventWatch event which you should react on. This is returned
	// regardless whether Watch() was enabled or not.
	OpenFeatures(ifaces FeatureKind, wr bool) error

	// Feature receives an feature and returns nil this feature is not opened
	Feature(ifaces FeatureKind) Feature

	// IsAvailable returns a bitmask of available devices. These devices can be opened and are
	// guaranteed to be present on the hardware at this time. If you watch your
	// device for hotplug events you will get notified whenever this bitmask changes.
	// See the WatchEvent event for more information.
	Available(iface FeatureKind) bool

	// SetIRFull sets
	IRFull() bool

	// SetIRFull sets
	SetIRFull(fullreport bool)

	// LED reads the LED state for the given LED.
	//
	// LEDs are a static feature that does not have to be opened first.
	LED() (result Led, _ error)

	// SetLED writes the LED state for the given LED.
	//
	// LEDs are a static feature that does not have to be opened first.
	SetLED(leds Led) error

	// Battery reads the current battery capacity. The capacity is represented as percentage, thus the return value is an integer between 0 and 100.
	//
	// Batteries are a static feature that does not have to be opened first.
	Battery() (uint, error)

	// DevType returns the device type. If the device type cannot be determined,
	// it returns "unknown" and the corresponding error.
	//
	// This is a static feature that does not have to be opened first.
	DevType() (string, error)

	// Extension returns the extension type. If no extension is connected or the
	// extension cannot be determined, it returns a string "none" and the corresponding error.
	//
	// This is a static feature that does not have to be opened first.
	Extension() (string, error)
}

type DeviceEnumerator

type DeviceEnumerator interface {
	// AddMatchSubsystem adds a filter for a subsystem of the device to include in the list.
	AddMatchSubsystem(subsystem string) (err error)

	// AddNomatchSubsystem adds a filter for a subsystem of the device to exclude from the list.
	AddNomatchSubsystem(subsystem string) (err error)

	// AddMatchSysattr adds a filter for a sys attribute at the device to include in the list.
	AddMatchSysattr(sysattr, value string) (err error)

	// AddNomatchSysattr adds a filter for a sys attribute at the device to exclude from the list.
	AddNomatchSysattr(sysattr, value string) (err error)

	// AddMatchSysname adds a filter for the name of the device to include in the list.
	AddMatchSysname(sysname string) (err error)

	// AddMatchParent adds a filter for a parent Device to include in the list.
	AddMatchParent(parent DeviceInfo) error

	// AddSyspath adds a device to the list of enumerated devices, to retrieve it back sorted in dependency order.
	AddSyspath(syspath string) (err error)

	// Devices returns an Iterator over the device syspaths matching the filter, sorted in dependency order.
	// The Iterator is using the github.com/jkeiser/iter package.
	Devices() (it iter.Seq[DeviceInfo], err error)

	// Subsystems returns an Iterator over the subsystem syspaths matching the filter, sorted in dependency order.
	// The Iterator is using the github.com/jkeiser/iter package.
	Subsystems() (it iter.Seq[string], err error)
}

type DeviceInfo

type DeviceInfo interface {
	// Parent returns the parent Device, or nil if the receiver has no parent Device
	Parent() DeviceInfo

	// Subsystem returns the subsystem string of the udev device.
	// The string does not contain any "/".
	Subsystem() string

	// Sysname returns the sysname of the udev device (e.g. ttyS3, sda1...).
	Sysname() string

	// Syspath returns the sys path of the udev device.
	// The path is an absolute path and starts with the sys mount point.
	Syspath() string

	// Devnode returns the device node file name belonging to the udev device.
	// The path is an absolute path, and starts with the device directory.
	Devnode() string

	// Driver returns the driver for the receiver
	Driver() string

	// Action returns the action for the event.
	// This is only valid if the device was received through a monitor.
	// Devices read from sys do not have an action string.
	// Usual actions are: add, remove, change, online, offline.
	Action() string

	// SysattrValue retrieves the content of a sys attribute file, and returns an empty string if there is no sys attribute value.
	// The retrieved value is cached in the device.
	// Repeated calls will return the same value and not open the attribute again.
	SysattrValue(sysattr string) string
}

type DeviceMonitor

type DeviceMonitor interface {
	// FD receives a file descriptor which can be checked for rediness
	FD() int

	EnableReceiving() (err error)

	ReceiveDevice() DeviceInfo

	// SetReceiveBufferSize sets the size of the kernel socket buffer.
	// This call needs the appropriate privileges to succeed.
	SetReceiveBufferSize(size int) (err error)

	// FilterAddMatchSubsystem adds a filter matching the device against a subsystem.
	// This filter is efficiently executed inside the kernel, and libudev subscribers will usually not be woken up for devices which do not match.
	// The filter must be installed before the monitor is switched to listening mode with the DeviceChan function.
	FilterAddMatchSubsystem(subsystem string) (err error)

	// FilterUpdate updates the installed socket filter.
	// This is only needed, if the filter was removed or changed.
	FilterUpdate() (err error)

	// FilterRemove removes all filter from the Monitor.
	FilterRemove() (err error)
}

type Event

type Event interface {
	Feature() Feature
	Timestamp() time.Time
}

Event feature describes an event fired by Device.Dispatch(), consider using a type-switch to retrieve the specific event type and data

type EventAccel

type EventAccel struct {
	Event
	Accel Vec3 `json:"accel"`
}

EventAccel provides accelerometer data. Note that the accelerometer reports acceleration data, not speed data!

type EventBalanceBoard

type EventBalanceBoard struct {
	Event
	Weights [4]int32 `json:"weights"`
}

EventBalanceBoard provides balance-board weight data. Four sensors report weight-data for each of the four edges of the board.

type EventClassicControllerKey

type EventClassicControllerKey struct {
	EventKey
}

EventClassicControllerKey provides Classic Controller key events. Button events of the classic controller are reported via this feature and not via the core-feature (which only reports core-buttons). Valid buttons include: LEFT, RIGHT, UP, DOWN, PLUS, MINUS, HOME, X, Y, A, B, TR, TL, ZR, ZL.

type EventClassicControllerMove

type EventClassicControllerMove struct {
	Event
	StickLeft     Vec2  `json:"stick_left"`
	StickRight    Vec2  `json:"stick_right"`
	ShoulderLeft  int32 `json:"shoulder_left"`
	ShoulderRight int32 `json:"shoulder_right"`
}

EventClassicControllerMove provides Classic Controller movement events. Movement of analog sticks are reported via this event. The payload is a struct wii_event_abs and the first two array elements contain the absolute x and y position of both analog sticks. The x value of the third array element contains the absolute position of the TL trigger. The y value contains the absolute position for the TR trigger. Note that many classic controllers do not have analog TL/TR triggers, in which case these read 0 or MAX (63). The digital TL/TR buttons are always reported correctly.

type EventDrumsKey

type EventDrumsKey struct {
	EventKey
}

EventDrumsKey provides Drums key events. Button events for drums controllers. Valid buttons are PLUS and MINUS for the +/- buttons on the center-bar.

type EventDrumsMove

type EventDrumsMove struct {
	Event
	Pad         Vec2  `json:"pad"`
	CymbalLeft  int32 `json:"cymbal_left"`
	CymbalRight int32 `json:"cymbal_right"`
	TomLeft     int32 `json:"tom_left"`
	TomRight    int32 `json:"tom_right"`
	TomFarRight int32 `json:"tom_far_right"`
	Bass        int32 `json:"bass"`
	HiHat       int32 `json:"hihat"`
}

EventDrumsMove provides Drums movement event Movement and pressure events for drums controllers.

type EventFeature

type EventFeature struct {
	Event
	Kind    FeatureKind
	Removed bool
}

EventFeature is provided when a feature is added.

type EventGone

type EventGone struct {
	Event
}

EventGone provides Removal Event. This event is sent whenever the device was removed. No payload is provided. Non-hotplug aware applications may discard this event. Optionally Feature can be set, if nil the whole device is removed.

type EventGuitarKey

type EventGuitarKey struct {
	EventKey
}

EventGuitarKey provides Guitar key events Button events for guitar controllers. Valid buttons are HOME and PLUS for the StarPower/Home button and the + button. Furthermore, you get FRET_FAR_UP, FRET_UP, FRET_MID, FRET_LOW, FRET_FAR_LOW for fret activity and STRUM_BAR_UP and STRUM_BAR_LOW for the strum bar.

type EventGuitarMove

type EventGuitarMove struct {
	Event
	Stick     Vec2  `json:"stick"`
	WhammyBar int32 `json:"whammy_bar"`
	FretBar   int32 `json:"fret_bar"`
}

EventGuitarMove provides Guitar movement events. Movement information for guitar controllers.

type EventIR

type EventIR struct {
	Event
	Slots [4]IRSlot `json:"slots"`
}

EventIR provides IR-camera events. The camera can track up two four IR sources. As long as a single source is tracked, it stays at it's pre-allocated slot.

Use IRSlot.Valid() to see whether a specific slot is currently valid or whether it currently doesn't track any IR source.

type EventKey

type EventKey struct {
	Event
	Code    Key  `json:"code"`
	Pressed bool `json:"pressed"`
}

EventKey is fired whenever a key is pressed or released. Valid key-events include all the events reported by the core-feature, which is normally only LEFT, RIGHT, UP, DOWN, A, B, PLUS, MINUS, HOME, ONE, TWO.

type EventMotionPlus

type EventMotionPlus struct {
	Event
	Speed Vec3 `json:"speed"`
}

EventMotionPlus provides gyroscope events. These describe rotational speed, not acceleration, of the motion-plus extension.

type EventNunchukKey

type EventNunchukKey struct {
	EventKey
}

EventNunchukKey provides Nunchuk key events. Button events of the nunchuk controller are reported via this feature and not via the core-feature (which only reports core-buttons). Valid buttons include: C, Z

type EventNunchukMove

type EventNunchukMove struct {
	Event
	Stick Vec2 `json:"stick"`
	Accel Vec3 `json:"accel"`
}

EventNunchukMove provides Nunchuk movement events. Movement events of the nunchuk controller are reported via this feature. Payload is of type struct wii_event_abs. The first array element contains the x/y positions of the analog stick. The second array element contains the accelerometer information.

type EventProControllerKey

type EventProControllerKey struct {
	EventKey
}

EventProControllerKey provides button events of the pro-controller and are reported via this feature and not via the core-feature (which only reports core-buttons). Valid buttons include: LEFT, RIGHT, UP, DOWN, PLUS, MINUS, HOME, X, Y, A, B, TR, TL, ZR, ZL, THUMBL, THUMBR. Payload type is struct wii_event_key.

type EventProControllerMove

type EventProControllerMove struct {
	Event
	Sticks [2]Vec2 `json:"sticks"`
}

EventProControllerMove provides movement of analog sticks on the pro-controller and is reported via this event.

type EventWatch

type EventWatch struct {
	Event
}

EventWatch is sent whenever an extension was hotplugged (plugged or unplugged), a device-detection finished or some other static data changed which cannot be monitored separately. An application should check what changed by examining the device is testing whether all required features are still available. Non-hotplug aware devices may discard this event.

This is only returned if you explicitly watched for hotplug events. See Device.Watch().

This event is also returned if an feature is closed because the kernel closed our file-descriptor (for whatever reason). This is returned regardless whether you watch for hotplug events or not.

type Feature

type Feature interface {
	io.Closer
	// Type of this feature
	Kind() FeatureKind
	// Device is the parent of this feature. When opened, a device is bound to this feature.
	Device() Device
	// Opened returns a bitmask of opened features. Features may be closed due to
	// error-conditions at any time. However, features are never opened
	// automatically.
	//
	// You will get notified whenever this bitmask changes, except on explicit
	// calls to Open() and Close(). See the EventWatch event for more information.
	Opened() bool
}

type FeatureKind

type FeatureKind uint
const (
	FeatureCore FeatureKind = 1 << iota
	FeatureAccel
	FeatureIR
	FeatureSpeaker
	FeatureMotionPlus
	FeatureNunchuck
	FeatureClassicController
	FeatureBalanceBoard
	FeatureProController
	FeatureDrums
	FeatureGuitar

	FeatureSetCore = FeatureCore | FeatureAccel | FeatureIR | FeatureSpeaker
)

func LookupFeatureKind

func LookupFeatureKind(name string) (FeatureKind, bool)

func (FeatureKind) String

func (i FeatureKind) String() string

type IRSlot

type IRSlot struct {
	Vec2
	Size      uint8
	Bounds    Rect
	Intensity uint8
}

IRSlot describes Infra-Red Tracking on a WiiMote

func (IRSlot) Valid

func (slot IRSlot) Valid() bool

Valid returns wether this slot holds a valid source. If not it has no track and is considered disabled.

type Key

type Key uint

Key Event Identifiers

For each key found on a supported device, a separate key identifier is defined. Note that a device may have a specific key (for instance: HOME) on the main device and on an extension device. An application can detect which key was pressed examining the event-type field. Some devices report common keys as both, extension and core events. In this case the kernel is required to filter these and you should report it as a bug. A single physical key-press should never be reported twice, even on two different features.

const (
	KeyLeft Key = iota
	KeyRight
	KeyUp
	KeyDown
	KeyA
	KeyB
	KeyPlus
	KeyMinus
	KeyHome
	KeyOne
	KeyTwo
	KeyX
	KeyY
	KeyTL
	KeyTR
	KeyZL
	KeyZR

	// Left thumb button
	//
	// This is reported if the left analog stick is pressed. Not all analog
	// sticks support this. The Wii-U Pro Controller is one of few devices
	// that report this event.
	KeyThumbL

	// Right thumb button
	//
	// This is reported if the right analog stick is pressed. Not all analog
	// sticks support this. The Wii-U Pro Controller is one of few devices
	// that report this event.
	KeyThumbR

	// Extra C button
	//
	// This button is not part of the standard action pad but reported by
	// extension controllers like the Nunchuk. It is supposed to extend the
	// standard A and B buttons.
	KeyC

	// Extra Z button
	//
	// This button is not part of the standard action pad but reported by
	// extension controllers like the Nunchuk. It is supposed to extend the
	// standard X and Y buttons.
	KeyZ

	// Guitar Strum-bar-up event
	//
	// Emitted by guitars if the strum-bar is moved up.
	KeyStrumBarUp

	// Guitar Strum-bar-down event
	//
	// Emitted by guitars if the strum-bar is moved down.
	KeyStrumBarDown

	// Guitar Fret-Far-Up event
	//
	// Emitted by guitars if the upper-most fret-bar is pressed.
	KeyFretFarUp

	// Guitar Fret-Up event
	//
	// Emitted by guitars if the second-upper fret-bar is pressed.
	KeyFretUp

	// Guitar Fret-Mid event
	//
	// Emitted by guitars if the mid fret-bar is pressed.
	KeyFretMid

	// Guitar Fret-Low event
	//
	// Emitted by guitars if the second-lowest fret-bar is pressed.
	KeyFretLow

	// Guitar Fret-Far-Low event
	//
	// Emitted by guitars if the lower-most fret-bar is pressed.
	KeyFretFarLow
)

func LookupKey

func LookupKey(name string) (Key, bool)

func (Key) String

func (i Key) String() string

type Led

type Led uint8

Led described a Led of an device. The leds are counted left-to-right and can be OR'ed together.

const (
	Led1 Led = 1 << iota
	Led2
	Led3
	Led4
)

func LookupLed

func LookupLed(name string) (Led, bool)

func (Led) String

func (i Led) String() string

type Memory

type Memory interface {
	io.WriterAt
	io.ReaderAt
	io.Closer
}

type MemoryFeature

type MemoryFeature interface {
	Feature

	Memory() (Memory, error)
}

type MotionPlusFeature

type MotionPlusFeature interface {
	Feature

	// SetMPNormalization sets Motion-Plus normalization and calibration values. The Motion-Plus sensor is very
	// sensitive and may return really crappy values. This features allows to
	// apply 3 absolute offsets x, y and z which are subtracted from any MP data
	// before it is returned to the application. That is, if you set these values
	// to 0, this has no effect (which is also the initial state).
	//
	// The calibration factor is used to perform runtime calibration. If
	// it is 0 (the initial state), no runtime calibration is performed. Otherwise,
	// the factor is used to re-calibrate the zero-point of MP data depending on MP
	// input. This is an angoing calibration which modifies the internal state of
	// the x, y and z values.
	SetMPNormalization(x, y, z, factor int32)

	// MPNormalization reads the Motion-Plus normalization and calibration values. Please see
	// SetMPNormalization() how this is handled.
	//
	// Note that if the calibration factor is not 0, the normalization values may
	// change depending on incoming MP data. Therefore, the data read via this
	// function may differ from the values that you wrote to previously. However,
	// apart from applied calibration, these value are the same as were set
	// previously via SetMPNormalization() and you can feed them back
	// in later.
	MPNormalization() (x, y, z, factor int32)
}

type Poller

type Poller[T any] interface {
	// Poll attempts to retrieve an event or data.
	//
	// Return values:
	//   T:     the retrieved data (invalid if error == ErrRetry)
	//   bool:  indicates whether more data is immediately available without
	//          waiting for I/O readiness
	//   error: nil on success. If ErrRetry is returned, the call should be
	//          repeated without waiting. Any other error aborts the attempt.
	Poll() (T, bool, error)

	// Wait waits for an event up to the specified timeout. A negative timeout is considered forever.
	// It handles ErrRetry internally and returns the first valid event or error.
	Wait(timeout time.Duration) (T, error)

	// Wait waits for an event up to the specified timeout. A negative timeout is considered forever.
	WaitReadable(timeout time.Duration) error

	// Handle continuously polls and calls `yield` with new events.
	// It blocks forever and should be used in a new goroutine.
	Handle(yield func(T)) error

	// Stream continuously polls and writes events into ch. It is a wrapper for Handle.
	// It blocks forever and should be used in a new goroutine.
	//
	//	p.Handle(func(ev T) { ch <- ev })
	Stream(ch chan<- T)
}

type Rect

type Rect struct {
	Min, Max Vec2
}

Rect represents a 2D floating point rectangle, streched over an Min and Max point.

func (Rect) Contains

func (r Rect) Contains(p Vec2) bool

func (Rect) Empty

func (r Rect) Empty() bool

func (Rect) Height

func (r Rect) Height() int32

func (Rect) Width

func (r Rect) Width() int32

type RumbleFeature

type RumbleFeature interface {
	Feature

	// Rumble sets the rumble motor.
	//
	// This requires the core-feature to be opened in writable mode.
	Rumble(state bool) error
}

type Vec2

type Vec2 struct {
	X int32 `json:"x"`
	Y int32 `json:"y"`
}

Vec2 represents a 2D point or vector to X and Y, may be interpreted different depending on the event .

type Vec3

type Vec3 struct {
	X int32 `json:"x"`
	Y int32 `json:"y"`
	Z int32 `json:"z"`
}

Vec3 represents a 3D point or vector to X, Y and Z, may be interpreted different depending on the event.

Directories

Path Synopsis
cmd
wiilog command
wiimap command
wiimii command
wiipointer command
internal
sequences
Package sequences contains some utility functions releated to iter.Seq and iter.Seq2
Package sequences contains some utility functions releated to iter.Seq and iter.Seq2
pkg
irpointer
Package irpointe contains an algorithm to use your wiimote IR-sensors as pointer on a screen
Package irpointe contains an algorithm to use your wiimote IR-sensors as pointer on a screen

Jump to

Keyboard shortcuts

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