package main import ( "flag" "fmt" "log" "net/http" "github.com/gvalkov/golang-evdev" ) const ( // 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 ) const ( // event types button = iota axisX axisY axisZ ) const gamepadChanBufSize = 16 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 } const ( // drive modes tank = iota joystick ) const driveModeCount = 2 type driveMode int func (d driveMode) String() string { switch d { case tank: return "tank" case joystick: return "joystick" default: return "unknown" } } func (d *driveMode) Set(value string) error { switch value { case "tank": *d = tank case "joystick": *d = joystick default: return fmt.Errorf("unknown drive mode: %v", value) } return nil } func main() { var ( gamepad string listen string mode driveMode ) flag.StringVar(&gamepad, "gamepad", "/dev/input/event0", "the gamepad device path") flag.StringVar(&listen, "listen", "localhost:8080", "the HTTP listen address and port") flag.Var(&mode, "mode", "the drive mode (default \"tank\")") 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(mode, events) go gamepadRead(device, events) log.Print("HTTP server started") log.Fatalf("error listening and serving: %v", http.ListenAndServe(listen, nil)) } func control(mode driveMode, events *gamepadEvents) { log.Printf("control loop started (drive mode: %v)", mode) 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: if e.value > 0 { mode++ mode %= driveModeCount log.Printf("switched drive mode: %v", mode) } } } } func gamepadRead(device *evdev.InputDevice, events *gamepadEvents) { log.Print("gamepad read loop started") 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} } } } }