Read events from multiple devices.

This commit is contained in:
Anna Rose Wiggins 2025-07-02 17:01:17 -04:00
parent a5b59bf39e
commit a078dcb193
4 changed files with 59 additions and 31 deletions

View file

@ -1,9 +1,9 @@
package main package main
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"time"
"git.annabunches.net/annabunches/joyful/internal/config" "git.annabunches.net/annabunches/joyful/internal/config"
"git.annabunches.net/annabunches/joyful/internal/logger" "git.annabunches.net/annabunches/joyful/internal/logger"
@ -63,38 +63,56 @@ func main() {
// Initialize rules // Initialize rules
rules := config.BuildRules(pDevices, getVirtualDevices(vBuffers)) rules := config.BuildRules(pDevices, getVirtualDevices(vBuffers))
// TEST CODE // Listen for events and map them forever
testDriver(vBuffers, pDevices, rules) mapEvents(vBuffers, pDevices, rules)
} }
func testDriver(vBuffers map[string]*virtualdevice.EventBuffer, pDevices map[string]*evdev.InputDevice, rules []mappingrules.MappingRule) { type ChannelEvent struct {
pDevice := pDevices["right-stick"] Device *evdev.InputDevice
buffer := vBuffers["main"] Event *evdev.InputEvent
for { }
// Get the first event for this report
event, err := pDevice.ReadOne()
logger.LogIfError(err, "Error while reading event")
for event.Code != evdev.SYN_REPORT { func mapEvents(vBuffers map[string]*virtualdevice.EventBuffer, pDevices map[string]*evdev.InputDevice, rules []mappingrules.MappingRule) {
// start listening for events on all devices
eventChannel := make(chan *ChannelEvent, 1000)
for _, device := range pDevices {
go eventWatcher(device, eventChannel)
}
fmt.Println("Joyful Running! Press Ctrl+C to quit.")
for {
// Get an event (blocks if necessary)
wrapper := <-eventChannel
switch wrapper.Event.Type {
case evdev.EV_SYN:
// We've received a SYN_REPORT, so now we send all of our pending events
for _, buffer := range vBuffers {
buffer.SendEvents()
}
case evdev.EV_KEY:
case evdev.EV_ABS:
// We have a matchable event type. Check all the events
for _, rule := range rules { for _, rule := range rules {
event := rule.MatchEvent(pDevice, event) outputEvent := rule.MatchEvent(wrapper.Device, wrapper.Event)
if event == nil { if outputEvent == nil {
continue continue
} }
buffer.AddEvent(event) vBuffers[rule.OutputName()].AddEvent(outputEvent)
} }
// Get the next event
event, err = pDevice.ReadOne()
logger.LogIfError(err, "Error while reading event")
} }
// We've received a SYN_REPORT, so now we can send all of our events
// TODO: how shall we handle this when dealing with multiple devices?
buffer.SendEvents()
time.Sleep(1 * time.Millisecond)
} }
// END TEST CODE }
func eventWatcher(device *evdev.InputDevice, channel chan *ChannelEvent) {
for {
event, err := device.ReadOne()
if err != nil {
logger.LogError(err, "Error while reading event")
continue
}
channel <- &ChannelEvent{Device: device, Event: event}
}
} }

View file

@ -64,6 +64,7 @@ func makeRuleTarget(targetConfig RuleTargetConfig, devs map[string]*evdev.InputD
ruleTarget.Type = eventType ruleTarget.Type = eventType
ruleTarget.Code = eventCode ruleTarget.Code = eventCode
ruleTarget.Inverted = targetConfig.Inverted ruleTarget.Inverted = targetConfig.Inverted
ruleTarget.DeviceName = targetConfig.Device
return ruleTarget, nil return ruleTarget, nil
} }
@ -83,8 +84,7 @@ func decodeRuleTargetValues(target RuleTargetConfig) (evdev.EvType, evdev.EvCode
if !ok { if !ok {
return 0, 0, fmt.Errorf("skipping rule due to invalid button code '%s'", target.Button) return 0, 0, fmt.Errorf("skipping rule due to invalid button code '%s'", target.Button)
} }
} } else if target.Axis != "" {
if target.Axis != "" {
eventType = evdev.EV_ABS eventType = evdev.EV_ABS
eventCode, ok = evdev.ABSFromString[target.Axis] eventCode, ok = evdev.ABSFromString[target.Axis]
if !ok { if !ok {

View file

@ -78,3 +78,11 @@ func (rule *ComboMappingRule) MatchEvent(device *evdev.InputDevice, event *evdev
} }
return nil return nil
} }
func (rule *SimpleMappingRule) OutputName() string {
return rule.Output.DeviceName
}
func (rule *ComboMappingRule) OutputName() string {
return rule.Output.DeviceName
}

View file

@ -4,6 +4,7 @@ import "github.com/holoplot/go-evdev"
type MappingRule interface { type MappingRule interface {
MatchEvent(*evdev.InputDevice, *evdev.InputEvent) *evdev.InputEvent MatchEvent(*evdev.InputDevice, *evdev.InputEvent) *evdev.InputEvent
OutputName() string
} }
// A Simple Mapping Rule can map a button to a button or an axis to an axis. // A Simple Mapping Rule can map a button to a button or an axis to an axis.
@ -22,8 +23,9 @@ type ComboMappingRule struct {
} }
type RuleTarget struct { type RuleTarget struct {
Device *evdev.InputDevice DeviceName string
Type evdev.EvType Device *evdev.InputDevice
Code evdev.EvCode Type evdev.EvType
Inverted bool Code evdev.EvCode
Inverted bool
} }