|
@@ -0,0 +1,192 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "flag"
|
|
|
+ "fmt"
|
|
|
+ "log"
|
|
|
+ "net/http"
|
|
|
+
|
|
|
+ "github.com/gvalkov/golang-evdev"
|
|
|
+)
|
|
|
+
|
|
|
+const (
|
|
|
+ gamepadChanBufSize = 16
|
|
|
+ // Logitech gamepad codes
|
|
|
+ codeLeftAnalogX = 0
|
|
|
+ codeLeftAnalogY = 1
|
|
|
+ codeLeftAnalogZ = 2
|
|
|
+ codeRightAnalogX = 3
|
|
|
+ codeRightAnalogY = 4
|
|
|
+ codeRightAnalogZ = 5
|
|
|
+ codeDPadX = 16
|
|
|
+ codeDPadY = 17
|
|
|
+ codeA = 304
|
|
|
+ codeB = 305
|
|
|
+ codeX = 307
|
|
|
+ codeY = 308
|
|
|
+ codeLeft = 310
|
|
|
+ codeRight = 311
|
|
|
+ codeBack = 314
|
|
|
+ codeStart = 315
|
|
|
+ codeLogitech = 316
|
|
|
+ codeLeftAnalog = 317
|
|
|
+ codeRightAnalog = 318
|
|
|
+ // event types
|
|
|
+ button = iota
|
|
|
+ axisX
|
|
|
+ axisY
|
|
|
+ axisZ
|
|
|
+)
|
|
|
+
|
|
|
+type event struct {
|
|
|
+ code int
|
|
|
+ value int32
|
|
|
+}
|
|
|
+
|
|
|
+func (e event) String() string {
|
|
|
+ var code string
|
|
|
+ switch e.code {
|
|
|
+ case button:
|
|
|
+ code = "button"
|
|
|
+ case axisX:
|
|
|
+ code = "X"
|
|
|
+ case axisY:
|
|
|
+ code = "Y"
|
|
|
+ case axisZ:
|
|
|
+ code = "Z"
|
|
|
+ }
|
|
|
+ return fmt.Sprintf("%v %v", code, e.value)
|
|
|
+}
|
|
|
+
|
|
|
+type gamepadEvents struct {
|
|
|
+ leftAnalog, rightAnalog, dpad chan event
|
|
|
+ a, b, x, y chan event
|
|
|
+ left, right chan event
|
|
|
+ back, start, logitech chan event
|
|
|
+}
|
|
|
+
|
|
|
+func main() {
|
|
|
+ var (
|
|
|
+ gamepad string
|
|
|
+ listen string
|
|
|
+ )
|
|
|
+
|
|
|
+ flag.StringVar(&gamepad, "gamepad", "/dev/input/event0", "the gamepad device path")
|
|
|
+ flag.StringVar(&listen, "listen", "localhost:8080", "the HTTP listen address and port")
|
|
|
+ flag.Parse()
|
|
|
+
|
|
|
+ if !evdev.IsInputDevice(gamepad) {
|
|
|
+ log.Fatalf("%v is not an input device", gamepad)
|
|
|
+ }
|
|
|
+ device, err := evdev.Open(gamepad)
|
|
|
+ if err != nil {
|
|
|
+ log.Fatalf("error opening gamepad: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ events := &gamepadEvents{
|
|
|
+ leftAnalog: make(chan event, gamepadChanBufSize),
|
|
|
+ rightAnalog: make(chan event, gamepadChanBufSize),
|
|
|
+ dpad: make(chan event, gamepadChanBufSize),
|
|
|
+ a: make(chan event, gamepadChanBufSize),
|
|
|
+ b: make(chan event, gamepadChanBufSize),
|
|
|
+ x: make(chan event, gamepadChanBufSize),
|
|
|
+ y: make(chan event, gamepadChanBufSize),
|
|
|
+ left: make(chan event, gamepadChanBufSize),
|
|
|
+ right: make(chan event, gamepadChanBufSize),
|
|
|
+ back: make(chan event, gamepadChanBufSize),
|
|
|
+ start: make(chan event, gamepadChanBufSize),
|
|
|
+ logitech: make(chan event, gamepadChanBufSize),
|
|
|
+ }
|
|
|
+
|
|
|
+ go control(events)
|
|
|
+ go gamepadRead(device, events)
|
|
|
+
|
|
|
+ log.Fatalf("error listening and serving: %v", http.ListenAndServe(listen, nil))
|
|
|
+}
|
|
|
+
|
|
|
+func control(events *gamepadEvents) {
|
|
|
+ for {
|
|
|
+ select {
|
|
|
+ case e := <-events.leftAnalog:
|
|
|
+ log.Println("left analog", e)
|
|
|
+ case e := <-events.rightAnalog:
|
|
|
+ log.Println("right analog", e)
|
|
|
+ case e := <-events.dpad:
|
|
|
+ log.Println("dpad", e)
|
|
|
+ case e := <-events.a:
|
|
|
+ log.Println("a", e)
|
|
|
+ case e := <-events.b:
|
|
|
+ log.Println("b", e)
|
|
|
+ case e := <-events.x:
|
|
|
+ log.Println("x", e)
|
|
|
+ case e := <-events.y:
|
|
|
+ log.Println("y", e)
|
|
|
+ case e := <-events.left:
|
|
|
+ log.Println("left", e)
|
|
|
+ case e := <-events.right:
|
|
|
+ log.Println("right", e)
|
|
|
+ case e := <-events.back:
|
|
|
+ log.Println("back", e)
|
|
|
+ case e := <-events.start:
|
|
|
+ log.Println("start", e)
|
|
|
+ case e := <-events.logitech:
|
|
|
+ log.Println("logitech", e)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func gamepadRead(device *evdev.InputDevice, events *gamepadEvents) {
|
|
|
+ for {
|
|
|
+ e, err := device.ReadOne()
|
|
|
+ if err != nil {
|
|
|
+ log.Fatalf("error reading from gamepad: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ switch e.Type {
|
|
|
+ case evdev.EV_ABS:
|
|
|
+ switch e.Code {
|
|
|
+ case codeLeftAnalogX:
|
|
|
+ events.leftAnalog <- event{code: axisX, value: e.Value}
|
|
|
+ case codeLeftAnalogY:
|
|
|
+ events.leftAnalog <- event{code: axisY, value: e.Value}
|
|
|
+ case codeLeftAnalogZ:
|
|
|
+ events.leftAnalog <- event{code: axisZ, value: e.Value}
|
|
|
+ case codeRightAnalogX:
|
|
|
+ events.rightAnalog <- event{code: axisX, value: e.Value}
|
|
|
+ case codeRightAnalogY:
|
|
|
+ events.rightAnalog <- event{code: axisY, value: e.Value}
|
|
|
+ case codeRightAnalogZ:
|
|
|
+ events.rightAnalog <- event{code: axisZ, value: e.Value}
|
|
|
+ case codeDPadX:
|
|
|
+ events.dpad <- event{code: axisX, value: e.Value}
|
|
|
+ case codeDPadY:
|
|
|
+ events.dpad <- event{code: axisY, value: e.Value}
|
|
|
+ }
|
|
|
+ case evdev.EV_KEY:
|
|
|
+ switch e.Code {
|
|
|
+ case codeA:
|
|
|
+ events.a <- event{code: button, value: e.Value}
|
|
|
+ case codeB:
|
|
|
+ events.b <- event{code: button, value: e.Value}
|
|
|
+ case codeX:
|
|
|
+ events.x <- event{code: button, value: e.Value}
|
|
|
+ case codeY:
|
|
|
+ events.y <- event{code: button, value: e.Value}
|
|
|
+ case codeLeft:
|
|
|
+ events.left <- event{code: button, value: e.Value}
|
|
|
+ case codeRight:
|
|
|
+ events.right <- event{code: button, value: e.Value}
|
|
|
+ case codeBack:
|
|
|
+ events.back <- event{code: button, value: e.Value}
|
|
|
+ case codeStart:
|
|
|
+ events.start <- event{code: button, value: e.Value}
|
|
|
+ case codeLogitech:
|
|
|
+ events.logitech <- event{code: button, value: e.Value}
|
|
|
+ case codeLeftAnalog:
|
|
|
+ events.leftAnalog <- event{code: button, value: e.Value}
|
|
|
+ case codeRightAnalog:
|
|
|
+ events.rightAnalog <- event{code: button, value: e.Value}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|