Commit eba66890 authored by simon's avatar simon
Browse files

comment

parent 71bd7ecd
Loading
Loading
Loading
Loading
+12 −8
Original line number Diff line number Diff line
/*
Package joysticks, provides simplified event routing, by channels, from the Linux joystick driver File-like interface.
Package joysticks, provides simplified event routing, through channels, from the Linux joystick driver File-like interface.

events can be listened for from any thread, re-routed and simulated.

*/
package joysticks
usage:

/*
usage details.
'Capture', a single call to setup and start basic event routing.

or (more flexible)

connect to a joystick by index number then use functions to make event servicing channels, one for each button or hat.
'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 'ProcessEvents'.

event channels provide at least time.
event channels provide at least time. event is an interface with a 'Moment' method which returns a time.Duration.

hat channel event provides current position, (x,y) (with only one axis changing per event.)
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.)

*/
package joysticks
+7 −7
Original line number Diff line number Diff line
@@ -96,34 +96,34 @@ type Channel struct {
}

// button goes open
func (js State) OnOpen(button uint8) chan event {
func (js *State) 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 *State) 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 *State) 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 *State) 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 *State) ButtonExists(button uint8) (ok bool) {
	for _, v := range js.buttons {
		if v.number == button {
			return true
@@ -132,7 +132,7 @@ func (js State) ButtonExists(button uint8) (ok bool) {
	return
}

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

func (js State) InsertSyntheticEvent(v int16, t uint8, i uint8) {
func (js *State) InsertSyntheticEvent(v int16, t uint8, i uint8) {
	js.osEvent <- osEventRecord{Value: v, Type: t, Index: i}
}

+13 −9
Original line number Diff line number Diff line
@@ -21,34 +21,38 @@ type osEventRecord struct {
const maxValue = 1<<15 - 1

// Capture returns a chan, for each registree, getting the events the registree indicates.
// Finds the first unused joystick, from a max of 4.
// Intended for bacic use since doesn't return state object.
func Capture(registrees ...Channel) []chan event {
	js, err := Connect(1)
	if err != nil {
	js:= Connect(1)
	for i:=2;js==nil && i<5;i++{ 
		js = Connect(i)
	}
	if js==nil {
		return nil
	}
	go js.ProcessEvents()
	chans := make([]chan event, len(registrees))
	for i, fns := range registrees {
		chans[i] = fns.Method(js, fns.Number)
		chans[i] = fns.Method(*js, fns.Number)
	}
	return chans
}

// Connect sets up a go routine that puts a joysticks events onto registered channels.
// 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 previously registered event. 
// 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 ProcessEvents() method.(usually in a go routine.)
func Connect(index int) (js State, e error) {
	r, e := os.OpenFile(fmt.Sprintf("/dev/input/js%d", index-1), os.O_RDONLY, 0666)
func Connect(index int) (js *State) {
	r, e := os.OpenFile(fmt.Sprintf("/dev/input/js%d", index-1), os.O_RDWR, 0400)
	if e != nil {
		return
		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 = &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)}
	// start thread to read joystick events to the joystick.state osEvent channel
	go eventPipe(r, js.osEvent)
	js.populate()
	return js, nil
	return js
}

// fill in the joysticks available events from the synthetic state events burst produced initially by the driver.
+36 −3
Original line number Diff line number Diff line
@@ -34,11 +34,44 @@ 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
	)
	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
	)
	var x float32 = .5
	var f time.Duration = time.Second / 440
	for {
		select {
		case <-events1[0]:
			return
		case <-events2[0]:
			return
		case <-events1[1]:
			play(NewSound(NewTone(f, float64(x)), time.Second/3))
		case <-events2[1]:
			play(NewSound(NewTone(f, float64(x)), time.Second/3))
		case h := <-events1[2]:
			x = h.(HatChangeEvent).X/2 + .5
			f = time.Duration(100*math.Pow(2, float64(h.(HatChangeEvent).Y))) * time.Second / 44000
		case h := <-events2[2]:
			x = h.(HatChangeEvent).X/2 + .5
			f = time.Duration(100*math.Pow(2, float64(h.(HatChangeEvent).Y))) * time.Second / 44000
		}
	}
}

func TestJoysticksAdvanced(t *testing.T) {
	js1, err := Connect(1)
	js1:= Connect(1)

	if err != nil {
		panic(err)
	if js1 == nil {
		panic("no joysticks")
	}
	if len(js1.buttons) < 10 || len(js1.hatAxes) < 6 {
		t.Errorf("joystick#1, available buttons %d, Hats %d\n", len(js1.buttons), len(js1.hatAxes)/2)