Build rules from config.

This commit is contained in:
Anna Rose Wiggins 2025-07-02 13:54:41 -04:00
parent 50474f9fb2
commit 428749a519
7 changed files with 186 additions and 106 deletions

View file

@ -8,6 +8,7 @@ import (
"strings"
"git.annabunches.net/annabunches/joyful/internal/logger"
"git.annabunches.net/annabunches/joyful/internal/mappingrules"
"github.com/goccy/go-yaml"
"github.com/holoplot/go-evdev"
)
@ -131,6 +132,29 @@ func (parser *ConfigParser) ConnectPhysicalDevices() map[string]*evdev.InputDevi
return deviceMap
}
func (parser *ConfigParser) BuildRules(pDevs map[string]*evdev.InputDevice, vDevs map[string]*evdev.InputDevice) []mappingrules.MappingRule {
rules := make([]mappingrules.MappingRule, 0)
for _, ruleConfig := range parser.config.Rules {
var newRule mappingrules.MappingRule
var err error
switch strings.ToLower(ruleConfig.Type) {
case RuleTypeSimple:
newRule, err = makeSimpleRule(ruleConfig, pDevs, vDevs)
case RuleTypeCombo:
newRule, err = makeComboRule(ruleConfig, pDevs, vDevs)
}
if err != nil {
logger.LogError(err, "")
continue
}
rules = append(rules, newRule)
}
return rules
}
func makeButtons(numButtons int) []evdev.EvCode {
if numButtons > 56 {
numButtons = 56

93
internal/config/rules.go Normal file
View file

@ -0,0 +1,93 @@
package config
import (
"fmt"
"git.annabunches.net/annabunches/joyful/internal/mappingrules"
"github.com/holoplot/go-evdev"
)
func makeSimpleRule(ruleConfig RuleConfig, pDevs map[string]*evdev.InputDevice, vDevs map[string]*evdev.InputDevice) (mappingrules.MappingRule, error) {
input, err := makeRuleTarget(ruleConfig.Input, pDevs)
if err != nil {
return nil, err
}
output, err := makeRuleTarget(ruleConfig.Output, vDevs)
if err != nil {
return nil, err
}
return &mappingrules.SimpleMappingRule{
Input: input,
Output: output,
}, nil
}
func makeComboRule(ruleConfig RuleConfig, pDevs map[string]*evdev.InputDevice, vDevs map[string]*evdev.InputDevice) (mappingrules.MappingRule, error) {
inputs := make([]mappingrules.RuleTarget, 0)
for _, inputConfig := range ruleConfig.Inputs {
input, err := makeRuleTarget(inputConfig, pDevs)
if err != nil {
return nil, err
}
inputs = append(inputs, input)
}
output, err := makeRuleTarget(ruleConfig.Output, vDevs)
if err != nil {
return nil, err
}
return &mappingrules.ComboMappingRule{
Inputs: inputs,
Output: output,
}, nil
}
// makeInputRuleTarget takes an Input declaration from the YAML and returns a fully formed RuleTarget.
func makeRuleTarget(targetConfig RuleTargetConfig, devs map[string]*evdev.InputDevice) (mappingrules.RuleTarget, error) {
ruleTarget := mappingrules.RuleTarget{}
device, ok := devs[targetConfig.Device]
if !ok {
return mappingrules.RuleTarget{}, fmt.Errorf("couldn't build rule due to non-existent device '%s'", targetConfig.Device)
}
ruleTarget.Device = device
eventType, eventCode, err := decodeRuleTargetValues(targetConfig)
if err != nil {
return ruleTarget, err
}
ruleTarget.Type = eventType
ruleTarget.Code = eventCode
return ruleTarget, nil
}
// decodeRuleTargetValues returns the appropriate evdev.EvType and evdev.EvCode values
// for a given RuleTargetConfig, converting the config file strings into appropriate constants
//
// Todo: support different formats for key specification
func decodeRuleTargetValues(target RuleTargetConfig) (evdev.EvType, evdev.EvCode, error) {
var eventType evdev.EvType
var eventCode evdev.EvCode
var ok bool
if target.Button != "" {
eventType = evdev.EV_KEY
eventCode, ok = evdev.KEYFromString[target.Button]
if !ok {
return 0, 0, fmt.Errorf("skipping rule due to invalid button code '%s'", target.Button)
}
}
if target.Axis != "" {
eventType = evdev.EV_ABS
eventCode, ok = evdev.ABSFromString[target.Axis]
if !ok {
return 0, 0, fmt.Errorf("skipping rule due to invalid axis code '%s'", target.Button)
}
}
return eventType, eventCode, nil
}

View file

@ -20,24 +20,17 @@ type DeviceConfig struct {
}
type RuleConfig struct {
Name string `yaml:"name,omitempty"`
Type string `yaml:"type"`
Input RuleInputConfig `yaml:"input,omitempty"`
Inputs []RuleInputConfig `yaml:"inputs,omitempty"`
Output RuleOutputConfig `yaml:"output"`
Name string `yaml:"name,omitempty"`
Type string `yaml:"type"`
Input RuleTargetConfig `yaml:"input,omitempty"`
Inputs []RuleTargetConfig `yaml:"inputs,omitempty"`
Output RuleTargetConfig `yaml:"output"`
}
type RuleInputConfig struct {
type RuleTargetConfig struct {
Device string `yaml:"device"`
Button string `yaml:"button,omitempty"`
Buttons []string `yaml:"buttons,omitempty"`
Axis string `yaml:"axis,omitempty"`
Inverted bool `yaml:"inverted,omitempty"`
}
type RuleOutputConfig struct {
Device string `yaml:"device,omitempty"`
Button string `yaml:"button,omitempty"`
Axis string `yaml:"axis,omitempty"`
Groups string `yaml:"groups,omitempty"`
Groups []string `yaml:"groups,omitempty"`
}