173 lines
3.4 KiB
Go
173 lines
3.4 KiB
Go
package inputs
|
||
|
||
import (
|
||
"fmt"
|
||
|
||
"github.com/karalabe/hid"
|
||
)
|
||
|
||
type JoystickEvent struct {
|
||
Time uint32 // Event timestamp in milliseconds
|
||
Value int16 // Value of the event (button press or axis movement)
|
||
Type uint8 // Event type (button or axis)
|
||
Number uint8 // Axis/button number
|
||
}
|
||
|
||
const (
|
||
JS_EVENT_BUTTON = 0x01 // Button pressed/released
|
||
JS_EVENT_AXIS = 0x02 // Joystick moved
|
||
JS_EVENT_INIT = 0x80 // Initial state of device
|
||
)
|
||
|
||
type Controller struct {
|
||
Device *hid.Device
|
||
}
|
||
|
||
func (c *Controller) ReadState(buf []byte) (*ControllerState, error) {
|
||
_, err := c.Device.Read(buf)
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
x := buf[0] // Horizontal axis (0–255)
|
||
y := buf[1] // Vertical axis (0–255)
|
||
buttons := buf[6] // Buttons as bitfield
|
||
state := ControllerState{
|
||
Joystick: Vec2B{x, y},
|
||
Buttons: buttons,
|
||
}
|
||
|
||
return &state, nil
|
||
}
|
||
|
||
type Vec2B struct {
|
||
X byte `json:"x"`
|
||
Y byte `json:"y"`
|
||
}
|
||
|
||
type ControllerState struct {
|
||
Id int `json:"id"`
|
||
Joystick Vec2B `json:"joystick"`
|
||
Buttons byte `json:"buttons"`
|
||
}
|
||
|
||
type ConjureControllerButton int
|
||
|
||
const (
|
||
ButtonPower ConjureControllerButton = iota //0
|
||
ButtonStart
|
||
|
||
Button1
|
||
Button2
|
||
Button3
|
||
|
||
ButtonA
|
||
ButtonB
|
||
ButtonC // 7
|
||
)
|
||
|
||
var ConjureControllerButtons = []ConjureControllerButton{
|
||
ButtonStart,
|
||
ButtonPower,
|
||
|
||
Button1,
|
||
Button2,
|
||
Button3,
|
||
|
||
ButtonA,
|
||
ButtonB,
|
||
ButtonC,
|
||
}
|
||
|
||
func (s ConjureControllerButton) String() string {
|
||
switch s {
|
||
case ButtonA:
|
||
return "ButtonA"
|
||
case ButtonB:
|
||
return "ButtonB"
|
||
case ButtonC:
|
||
return "ButtonC"
|
||
case Button1:
|
||
return "Button1"
|
||
case Button2:
|
||
return "Button2"
|
||
case Button3:
|
||
return "Button3"
|
||
case ButtonStart:
|
||
return "ButtonStart"
|
||
case ButtonPower:
|
||
return "ButtonPower"
|
||
default:
|
||
return "Unknown"
|
||
}
|
||
}
|
||
|
||
func Start(onStateChange func(ControllerState)) {
|
||
fmt.Println("Opening devices")
|
||
const vendorID = 0x0079
|
||
const productID = 0x0006
|
||
|
||
devices := hid.Enumerate(vendorID, productID)
|
||
if len(devices) == 0 {
|
||
fmt.Printf("Device with VID:PID %04X:%04X not found\n", vendorID, productID)
|
||
return
|
||
}
|
||
|
||
for i, d := range devices {
|
||
fmt.Printf("Found device %d: %s - VID:%04X PID:%04X\n", i, d.Product, d.VendorID, d.ProductID)
|
||
|
||
go func(i int, d hid.DeviceInfo) {
|
||
device, err := d.Open()
|
||
if err != nil {
|
||
fmt.Printf("Failed to open device %d: %v\n", i, err)
|
||
return
|
||
}
|
||
defer device.Close()
|
||
|
||
controller := Controller{Device: device}
|
||
buf := make([]byte, 32)
|
||
|
||
fmt.Printf("Reading data from device %d... Press Ctrl+C to exit\n", i)
|
||
for {
|
||
state, err := controller.ReadState(buf)
|
||
if err != nil {
|
||
fmt.Printf("Read error on device %d: %v\n", i, err)
|
||
return
|
||
}
|
||
|
||
state.Id = i
|
||
|
||
// TODO Samuel please fix help me
|
||
if (state.Buttons != 0 || state.Joystick.X != 127 || state.Joystick.Y != 127) && !(state.Id == 1 && state.Buttons == 128 && state.Joystick.X == 127 && state.Joystick.Y == 127) {
|
||
// fmt.Printf("Id: %d - %d buttons ", state.Id, state.Buttons)
|
||
onStateChange(*state)
|
||
}
|
||
}
|
||
}(i, d)
|
||
}
|
||
|
||
// Prevent the function from exiting
|
||
select {}
|
||
}
|
||
|
||
// handleJoystickEvent processes joystick events.
|
||
func handleJoystickEvent(e JoystickEvent) {
|
||
if e.Type&JS_EVENT_INIT != 0 {
|
||
// Ignore initial state events
|
||
return
|
||
}
|
||
|
||
if e.Type&JS_EVENT_BUTTON != 0 {
|
||
if e.Value == 1 {
|
||
fmt.Printf("Button %d pressed\n", e.Number)
|
||
} else {
|
||
fmt.Printf("Button %d released\n", e.Number)
|
||
}
|
||
}
|
||
|
||
if e.Type&JS_EVENT_AXIS != 0 {
|
||
fmt.Printf("Axis %d moved to %d\n", e.Number, e.Value)
|
||
}
|
||
}
|