Commit 8349cff8 authored by simon's avatar simon
Browse files

State -> Joystick

parent d5180efc
Loading
Loading
Loading
Loading
+5 −6
Original line number Diff line number Diff line
@@ -11,20 +11,19 @@ or (more flexible)

'Connect' to a joystick by index number, then use methods to add event channels, one for each button or hat, and start running by calling 'ParcelOutEvents'.

event channels provide at least time. event is an interface with a 'Moment' method which returns a time.Duration.
event, an interface with a 'Moment' method, provides a time.Duration. Moment() returns whatever the underlying Linux driver provides as the events timestamp, in time.Duration.

event 'Moment' returns whatever the underlying Linux driver provides as the events timestamp, in time.Duration.

hat channel event provides current position, (x,y) the event will need casting to the hat event to access these. (with only one axis changing per event.)
hat channel event provides current position, (x,y) the event will need casting to the hat event to access these. (and only one axis actually changes per event.)

or (DIY)

'Connect' to a joystick by index number

handle all events directly using the returned State's OSEvent channel.
handle all events directly using the returned Joystick's OSEvent channel.

*/
package joysticks

/*

could be used with little change on any linux 'input'
+12 −11
Original line number Diff line number Diff line
@@ -17,7 +17,8 @@ type button struct {
	value  bool
}

type State struct {
//Joystick holds the in-coming event channel, mappings, and registered events for a joystick, and has methods to control and adjust behaviour.
type Joystick struct {
	OSEvent               chan osEventRecord
	buttons               map[uint8]button
	hatAxes               map[uint8]hatAxis
@@ -48,8 +49,8 @@ func (b ButtonChangeEvent) Moment() time.Duration {
	return b.time
}

// while its open, interpret whats on the State.OSEvent channel, then put the required event(s), on any registered channel(s).
func (js State) ParcelOutEvents() {
// ParcelOutEvents interprets whats on the State.OSEvent channel, then puts the required event(s), on any registered channel(s).
func (js Joystick) ParcelOutEvents() {
	for {
		evt, ok := <-js.OSEvent
		if !ok {
@@ -92,38 +93,38 @@ func (js State) ParcelOutEvents() {
// Type of registerable methods and the index they are called with. (Note: the event type is indicated by the method.)
type Channel struct {
	Number uint8
	Method func(State, uint8) chan event
	Method func(Joystick, uint8) chan event
}

// button goes open
func (js State) OnOpen(button uint8) chan event {
func (js Joystick) OnOpen(button uint8) chan event {
	c := make(chan event)
	js.buttonOpenEvents[button] = c
	return c
}

// button goes closed
func (js State) OnClose(button uint8) chan event {
func (js Joystick) OnClose(button uint8) chan event {
	c := make(chan event)
	js.buttonCloseEvents[button] = c
	return c
}

// button goes open and last event on it, closed, wasn't recent. (within 1 second)
func (js State) OnLong(button uint8) chan event {
func (js Joystick) OnLong(button uint8) chan event {
	c := make(chan event)
	js.buttonLongPressEvents[button] = c
	return c
}

// hat moved
func (js State) OnMove(hat uint8) chan event {
func (js Joystick) OnMove(hat uint8) chan event {
	c := make(chan event)
	js.hatChangeEvents[hat] = c
	return c
}

func (js State) ButtonExists(button uint8) (ok bool) {
func (js Joystick) ButtonExists(button uint8) (ok bool) {
	for _, v := range js.buttons {
		if v.number == button {
			return true
@@ -132,7 +133,7 @@ func (js State) ButtonExists(button uint8) (ok bool) {
	return
}

func (js State) HatExists(hat uint8) (ok bool) {
func (js Joystick) HatExists(hat uint8) (ok bool) {
	for _, v := range js.hatAxes {
		if v.number == hat {
			return true
@@ -141,6 +142,6 @@ func (js State) HatExists(hat uint8) (ok bool) {
	return
}

func (js State) InsertSyntheticEvent(v int16, t uint8, i uint8) {
func (js Joystick) InsertSyntheticEvent(v int16, t uint8, i uint8) {
	js.OSEvent <- osEventRecord{Value: v, Type: t, Index: i}
}
+5 −9
Original line number Diff line number Diff line
@@ -4,9 +4,9 @@ package joysticks

import (
	"encoding/binary"
	"strconv"
	"io"
	"os"
	"strconv"
	"time"
)

@@ -45,12 +45,12 @@ var inputPathSlice = []byte("/dev/input/js ")[0:13]
// register channels by using the returned state object's On<xxx>(index) methods.
// Note: only one event, of each type '<xxx>', for each 'index', re-registering stops events going on the old channel.
// then activate using state objects ParcelOutEvents() method.(usually in a go routine.)
func Connect(index int) (js *State) {
func Connect(index int) (js *Joystick) {
	r, e := os.OpenFile(string(strconv.AppendUint(inputPathSlice, uint64(index-1), 10)), os.O_RDWR, 0)
	if e != nil {
		return nil
	}
	js = &State{make(chan osEventRecord), make(map[uint8]button), make(map[uint8]hatAxis), make(map[uint8]chan event), make(map[uint8]chan event), make(map[uint8]chan event), make(map[uint8]chan event)}
	js = &Joystick{make(chan osEventRecord), make(map[uint8]button), make(map[uint8]hatAxis), make(map[uint8]chan event), make(map[uint8]chan event), make(map[uint8]chan event), make(map[uint8]chan event)}
	// start thread to read joystick events to the joystick.state osEvent channel
	go eventPipe(r, js.OSEvent)
	js.populate()
@@ -58,7 +58,7 @@ func Connect(index int) (js *State) {
}

// fill in the joysticks available events from the synthetic state events burst produced initially by the driver.
func (js State) populate() {
func (js Joystick) populate() {
	for buttonNumber, hatNumber, axisNumber := 1, 1, 1; ; {
		evt := <-js.OSEvent
		switch evt.Type {
@@ -77,7 +77,6 @@ func (js State) populate() {
			return
		}
	}
	return
}

// pipe any readable events onto channel.
@@ -95,6 +94,3 @@ func eventPipe(r io.Reader, c chan osEventRecord) {
func toDuration(m uint32) time.Duration {
	return time.Duration(m) * 1000000
}


+9 −11
Original line number Diff line number Diff line
@@ -15,9 +15,9 @@ import "math"

func TestJoysticksCapture(t *testing.T) {
	events := Capture(
		Channel{10, State.OnLong}, // event[0] button #10 long pressed
		Channel{1, State.OnClose}, // event[1] button #1 closes
		Channel{1, State.OnMove},  // event[2] hat #1 moves
		Channel{10, Joystick.OnLong}, // event[0] button #10 long pressed
		Channel{1, Joystick.OnClose}, // event[1] button #1 closes
		Channel{1, Joystick.OnMove},  // event[2] hat #1 moves
	)
	var x float32 = .5
	var f time.Duration = time.Second / 440
@@ -36,14 +36,14 @@ func TestJoysticksCapture(t *testing.T) {

func TestJoysticksMutipleCapture(t *testing.T) {
	events1 := Capture(
		Channel{10, State.OnLong}, // event[0] button #10 long pressed
		Channel{1, State.OnClose}, // event[1] button #1 closes
		Channel{1, State.OnMove},  // event[2] hat #1 moves
		Channel{10, Joystick.OnLong}, // event[0] button #10 long pressed
		Channel{1, Joystick.OnClose}, // event[1] button #1 closes
		Channel{1, Joystick.OnMove},  // event[2] hat #1 moves
	)
	events2 := Capture(
		Channel{10, State.OnLong}, // event[0] button #10 long pressed
		Channel{1, State.OnClose}, // event[1] button #1 closes
		Channel{1, State.OnMove},  // event[2] hat #1 moves
		Channel{10, Joystick.OnLong}, // event[0] button #10 long pressed
		Channel{1, Joystick.OnClose}, // event[1] button #1 closes
		Channel{1, Joystick.OnMove},  // event[2] hat #1 moves
	)
	var x float32 = .5
	var f time.Duration = time.Second / 440
@@ -123,5 +123,3 @@ func play(s Sound) {
		panic(err)
	}
}