From eeebb6d0b13d0ea6f00deba92ce97ab909f7d1ec Mon Sep 17 00:00:00 2001 From: Anna Rose Wiggins Date: Sat, 28 Jun 2025 22:30:59 -0400 Subject: [PATCH] Small fixes for config parsing, and start plumbing it into our main program. --- cmd/joyful/main.go | 66 +++------------ internal/config/configparser.go | 75 ++++++++++++++++- internal/config/maps.go | 114 ++++++++++++-------------- internal/config/types.go | 5 +- internal/virtualdevice/eventbuffer.go | 8 +- 5 files changed, 144 insertions(+), 124 deletions(-) diff --git a/cmd/joyful/main.go b/cmd/joyful/main.go index 271f922..3abb9b8 100644 --- a/cmd/joyful/main.go +++ b/cmd/joyful/main.go @@ -4,61 +4,34 @@ import ( "fmt" "time" + "git.annabunches.net/annabunches/joyful/internal/config" "git.annabunches.net/annabunches/joyful/internal/logger" "git.annabunches.net/annabunches/joyful/internal/virtualdevice" "github.com/holoplot/go-evdev" ) func main() { - // STUB: parse virtual device config + // parse configs + parser := &config.ConfigParser{} + parser.Parse("~/.config/joyful") // TODO: make ~ work here - // STUB: parse mapping config - - // Define virtual device - // TODO: create virtual devices from config - vDevice, err := evdev.CreateDevice( - "joyful-joystick", - evdev.InputID{ - BusType: 0x03, - Vendor: 0x4711, - Product: 0x0816, - Version: 1, - }, - map[evdev.EvType][]evdev.EvCode{ - evdev.EV_KEY: jsButtons(), - evdev.EV_ABS: { - evdev.ABS_X, - evdev.ABS_Y, - evdev.ABS_Z, - evdev.ABS_RX, - evdev.ABS_RY, - evdev.ABS_RZ, - evdev.ABS_THROTTLE, - evdev.ABS_WHEEL, - }, - }, - ) - logger.FatalIfError(err, "Failed to create virtual device") - - buffer := virtualdevice.NewEventBuffer(vDevice) - - name, err := vDevice.Name() - if err != nil { - name = "Unknown" + vDevices := parser.CreateVirtualDevices() + vBuffers := make(map[string]*virtualdevice.EventBuffer) + for name, device := range vDevices { + vBuffers[name] = virtualdevice.NewEventBuffer(device) } - fmt.Printf("Virtual device created as %s.\n", name) pDevice, err := evdev.Open("/dev/input/event12") logger.FatalIfError(err, "Couldn't open physical device") - name, err = pDevice.Name() + name, err := pDevice.Name() if err != nil { name = "Unknown" } fmt.Printf("Connected to physical device %s\n", name) var combo int32 = 0 - + buffer := vBuffers["test"] for { last := combo @@ -126,21 +99,4 @@ func main() { time.Sleep(1 * time.Millisecond) } -} - -func jsButtons() []evdev.EvCode { - buttons := make([]evdev.EvCode, 80) - i := 0 - - for code := 0x120; code <= 0x12f; code++ { - buttons[i] = evdev.EvCode(code) - i++ - } - - for code := 0x2c0; code <= 0x2ff; code++ { - buttons[i] = evdev.EvCode(code) - i++ - } - - return buttons -} +} \ No newline at end of file diff --git a/internal/config/configparser.go b/internal/config/configparser.go index 7ad5388..cc94590 100644 --- a/internal/config/configparser.go +++ b/internal/config/configparser.go @@ -8,6 +8,7 @@ import ( "git.annabunches.net/annabunches/joyful/internal/logger" "github.com/goccy/go-yaml" + "github.com/holoplot/go-evdev" ) type ConfigParser struct { @@ -19,7 +20,10 @@ type ConfigParser struct { func (parser *ConfigParser) Parse(directory string) { // Find the config files in the directory dirEntries, err := os.ReadDir(directory) - logger.FatalIfError(err, "Failed to read config directory") + if err != nil { + err = os.Mkdir(directory, 0755) + logger.FatalIfError(err, "Failed to create config directory at "+directory) + } for _, file := range dirEntries { name := file.Name() @@ -54,9 +58,76 @@ func (parser *ConfigParser) parseConfigFiles() []byte { } if len(rawData) == 0 { - logger.Log("No config data found") + logger.Log("No config data found. Write .yml config files in ~/.config/joyful") return nil } return rawData } + +func (parser *ConfigParser) CreateVirtualDevices() map[string]*evdev.InputDevice { + deviceMap := make(map[string]*evdev.InputDevice) + + for _, deviceConfig := range parser.config.Devices.Virtual { + vDevice, err := evdev.CreateDevice( + fmt.Sprintf("joyful-%s", deviceConfig.Name), + // TODO: who knows what these should actually be + evdev.InputID{ + BusType: 0x03, + Vendor: 0x4711, + Product: 0x0816, + Version: 1, + }, + map[evdev.EvType][]evdev.EvCode{ + evdev.EV_KEY: makeButtons(int(deviceConfig.Buttons)), + evdev.EV_ABS: makeAxes(int(deviceConfig.Axes)), + }, + ) + + if err != nil { + logger.LogIfError(err, "Failed to create virtual device") + continue + } + + deviceMap[deviceConfig.Name] = vDevice + } + + return deviceMap +} + +func makeButtons(numButtons int) []evdev.EvCode { + if numButtons > 56 { + numButtons = 56 + logger.Log("Limiting virtual device buttons to 56") + } + + buttons := make([]evdev.EvCode, numButtons) + + startCode := 0x120 + for i := 0; i < numButtons && i < 16; i++ { + buttons[i] = evdev.EvCode(startCode + i) + } + + if numButtons > 16 { + startCode = 0x2c0 + for i := 0; i < numButtons - 16; i++ { + buttons[16+i] = evdev.EvCode(startCode+i) + } + } + + return buttons +} + +func makeAxes(numAxes int) []evdev.EvCode { + if numAxes > 8 { + numAxes = 8 + logger.Log("Limiting virtual device axes to 8") + } + + axes := make([]evdev.EvCode, numAxes) + for i := 0; i < numAxes; i++ { + axes[i] = evdev.EvCode(i) + } + + return axes +} \ No newline at end of file diff --git a/internal/config/maps.go b/internal/config/maps.go index 962e631..fdab86d 100644 --- a/internal/config/maps.go +++ b/internal/config/maps.go @@ -5,66 +5,58 @@ import ( ) var ( - EvCodeMap = map[string]evdev.EvCode{ - "ABS_X": evdev.ABS_X, - "ABS_Y": evdev.ABS_Y, - "ABS_Z": evdev.ABS_Z, - "ABS_RX": evdev.ABS_RX, - "ABS_RY": evdev.ABS_RY, - "ABS_RZ": evdev.ABS_RZ, - "ABS_THROTTLE": evdev.ABS_THROTTLE, - "ABS_WHEEL": evdev.ABS_WHEEL, - "BTN_TRIGGER": evdev.BTN_TRIGGER, - "BTN_THUMB": evdev.BTN_THUMB, - "BTN_THUMB2": evdev.BTN_THUMB2, - "BTN_TOP": evdev.BTN_TOP, - "BTN_TOP2": evdev.BTN_TOP2, - "BTN_PINKIE": evdev.BTN_PINKIE, - "BTN_BASE": evdev.BTN_BASE, - "BTN_BASE2": evdev.BTN_BASE2, - "BTN_BASE3": evdev.BTN_BASE3, - "BTN_BASE4": evdev.BTN_BASE4, - "BTN_BASE5": evdev.BTN_BASE5, - "BTN_BASE6": evdev.BTN_BASE6, - "BTN_TRIGGER_HAPPY1": evdev.BTN_TRIGGER_HAPPY1, - "BTN_TRIGGER_HAPPY2": evdev.BTN_TRIGGER_HAPPY2, - "BTN_TRIGGER_HAPPY3": evdev.BTN_TRIGGER_HAPPY3, - "BTN_TRIGGER_HAPPY4": evdev.BTN_TRIGGER_HAPPY4, - "BTN_TRIGGER_HAPPY5": evdev.BTN_TRIGGER_HAPPY5, - "BTN_TRIGGER_HAPPY6": evdev.BTN_TRIGGER_HAPPY6, - "BTN_TRIGGER_HAPPY7": evdev.BTN_TRIGGER_HAPPY7, - "BTN_TRIGGER_HAPPY8": evdev.BTN_TRIGGER_HAPPY8, - "BTN_TRIGGER_HAPPY9": evdev.BTN_TRIGGER_HAPPY9, - "BTN_TRIGGER_HAPPY10": evdev.BTN_TRIGGER_HAPPY10, - "BTN_TRIGGER_HAPPY11": evdev.BTN_TRIGGER_HAPPY11, - "BTN_TRIGGER_HAPPY12": evdev.BTN_TRIGGER_HAPPY12, - "BTN_TRIGGER_HAPPY13": evdev.BTN_TRIGGER_HAPPY13, - "BTN_TRIGGER_HAPPY14": evdev.BTN_TRIGGER_HAPPY14, - "BTN_TRIGGER_HAPPY15": evdev.BTN_TRIGGER_HAPPY15, - "BTN_TRIGGER_HAPPY16": evdev.BTN_TRIGGER_HAPPY16, - "BTN_TRIGGER_HAPPY17": evdev.BTN_TRIGGER_HAPPY17, - "BTN_TRIGGER_HAPPY18": evdev.BTN_TRIGGER_HAPPY18, - "BTN_TRIGGER_HAPPY19": evdev.BTN_TRIGGER_HAPPY19, - "BTN_TRIGGER_HAPPY20": evdev.BTN_TRIGGER_HAPPY20, - "BTN_TRIGGER_HAPPY21": evdev.BTN_TRIGGER_HAPPY21, - "BTN_TRIGGER_HAPPY22": evdev.BTN_TRIGGER_HAPPY22, - "BTN_TRIGGER_HAPPY23": evdev.BTN_TRIGGER_HAPPY23, - "BTN_TRIGGER_HAPPY24": evdev.BTN_TRIGGER_HAPPY24, - "BTN_TRIGGER_HAPPY25": evdev.BTN_TRIGGER_HAPPY25, - "BTN_TRIGGER_HAPPY26": evdev.BTN_TRIGGER_HAPPY26, - "BTN_TRIGGER_HAPPY27": evdev.BTN_TRIGGER_HAPPY27, - "BTN_TRIGGER_HAPPY28": evdev.BTN_TRIGGER_HAPPY28, - "BTN_TRIGGER_HAPPY29": evdev.BTN_TRIGGER_HAPPY29, - "BTN_TRIGGER_HAPPY30": evdev.BTN_TRIGGER_HAPPY30, - "BTN_TRIGGER_HAPPY31": evdev.BTN_TRIGGER_HAPPY31, - "BTN_TRIGGER_HAPPY32": evdev.BTN_TRIGGER_HAPPY32, - "BTN_TRIGGER_HAPPY33": evdev.BTN_TRIGGER_HAPPY33, - "BTN_TRIGGER_HAPPY34": evdev.BTN_TRIGGER_HAPPY34, - "BTN_TRIGGER_HAPPY35": evdev.BTN_TRIGGER_HAPPY35, - "BTN_TRIGGER_HAPPY36": evdev.BTN_TRIGGER_HAPPY36, - "BTN_TRIGGER_HAPPY37": evdev.BTN_TRIGGER_HAPPY37, - "BTN_TRIGGER_HAPPY38": evdev.BTN_TRIGGER_HAPPY38, - "BTN_TRIGGER_HAPPY39": evdev.BTN_TRIGGER_HAPPY39, - "BTN_TRIGGER_HAPPY40": evdev.BTN_TRIGGER_HAPPY40, + ButtonFromIndex = []evdev.EvCode{ + evdev.BTN_TRIGGER, + evdev.BTN_THUMB, + evdev.BTN_THUMB2, + evdev.BTN_TOP, + evdev.BTN_TOP2, + evdev.BTN_PINKIE, + evdev.BTN_BASE, + evdev.BTN_BASE2, + evdev.BTN_BASE3, + evdev.BTN_BASE4, + evdev.BTN_BASE5, + evdev.BTN_BASE6, + evdev.BTN_TRIGGER_HAPPY1, + evdev.BTN_TRIGGER_HAPPY2, + evdev.BTN_TRIGGER_HAPPY3, + evdev.BTN_TRIGGER_HAPPY4, + evdev.BTN_TRIGGER_HAPPY5, + evdev.BTN_TRIGGER_HAPPY6, + evdev.BTN_TRIGGER_HAPPY7, + evdev.BTN_TRIGGER_HAPPY8, + evdev.BTN_TRIGGER_HAPPY9, + evdev.BTN_TRIGGER_HAPPY10, + evdev.BTN_TRIGGER_HAPPY11, + evdev.BTN_TRIGGER_HAPPY12, + evdev.BTN_TRIGGER_HAPPY13, + evdev.BTN_TRIGGER_HAPPY14, + evdev.BTN_TRIGGER_HAPPY15, + evdev.BTN_TRIGGER_HAPPY16, + evdev.BTN_TRIGGER_HAPPY17, + evdev.BTN_TRIGGER_HAPPY18, + evdev.BTN_TRIGGER_HAPPY19, + evdev.BTN_TRIGGER_HAPPY20, + evdev.BTN_TRIGGER_HAPPY21, + evdev.BTN_TRIGGER_HAPPY22, + evdev.BTN_TRIGGER_HAPPY23, + evdev.BTN_TRIGGER_HAPPY24, + evdev.BTN_TRIGGER_HAPPY25, + evdev.BTN_TRIGGER_HAPPY26, + evdev.BTN_TRIGGER_HAPPY27, + evdev.BTN_TRIGGER_HAPPY28, + evdev.BTN_TRIGGER_HAPPY29, + evdev.BTN_TRIGGER_HAPPY30, + evdev.BTN_TRIGGER_HAPPY31, + evdev.BTN_TRIGGER_HAPPY32, + evdev.BTN_TRIGGER_HAPPY33, + evdev.BTN_TRIGGER_HAPPY34, + evdev.BTN_TRIGGER_HAPPY35, + evdev.BTN_TRIGGER_HAPPY36, + evdev.BTN_TRIGGER_HAPPY37, + evdev.BTN_TRIGGER_HAPPY38, + evdev.BTN_TRIGGER_HAPPY39, + evdev.BTN_TRIGGER_HAPPY40, } ) diff --git a/internal/config/types.go b/internal/config/types.go index b54c593..2e78cc6 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -16,8 +16,9 @@ type PhysicalDeviceConfig struct { } type VirtualDeviceConfig struct { - NumButtons int `yaml:"num_buttons"` - NumAxes int `yaml:"num_axes"` + Name string `yaml:"name"` + Buttons int `yaml:"buttons"` + Axes int `yaml:"axes"` } type RuleConfig struct { diff --git a/internal/virtualdevice/eventbuffer.go b/internal/virtualdevice/eventbuffer.go index 8279fff..e95c099 100644 --- a/internal/virtualdevice/eventbuffer.go +++ b/internal/virtualdevice/eventbuffer.go @@ -10,13 +10,13 @@ import ( type EventBuffer struct { events []*evdev.InputEvent - device *evdev.InputDevice + Device *evdev.InputDevice } func NewEventBuffer(device *evdev.InputDevice) *EventBuffer { return &EventBuffer{ events: make([]*evdev.InputEvent, 0), - device: device, + Device: device, } } @@ -29,10 +29,10 @@ func (buffer *EventBuffer) SendEvents() { for i := 0; i < len(buffer.events); i++ { buffer.events[i].Time = eventTime - buffer.device.WriteOne(buffer.events[i]) + buffer.Device.WriteOne(buffer.events[i]) } - buffer.device.WriteOne(&evdev.InputEvent{ + buffer.Device.WriteOne(&evdev.InputEvent{ Time: eventTime, Type: evdev.EV_SYN, Code: evdev.SYN_REPORT,