From 74f49c0dc6bc23cc01a86f0e3e3a4d4f21b41dcf Mon Sep 17 00:00:00 2001 From: Anna Rose Wiggins Date: Fri, 8 Aug 2025 17:18:08 -0400 Subject: [PATCH 1/4] (WIP) Refactor marshal schema to be more declarative. --- internal/config/devices.go | 4 + internal/config/make_rule_targets.go | 11 +- internal/config/make_rule_targets_test.go | 145 +++++++------ internal/config/make_rules.go | 41 ++-- internal/config/schema.go | 207 +++++++++++++------ internal/config/variables.go | 4 +- internal/mappingrules/rule_target_relaxis.go | 5 +- 7 files changed, 253 insertions(+), 164 deletions(-) diff --git a/internal/config/devices.go b/internal/config/devices.go index 9802bff..4fa75da 100644 --- a/internal/config/devices.go +++ b/internal/config/devices.go @@ -22,6 +22,8 @@ func (parser *ConfigParser) CreateVirtualDevices() map[string]*evdev.InputDevice continue } + deviceConfig := deviceConfig.Config.(DeviceConfigVirtual) + name := fmt.Sprintf("joyful-%s", deviceConfig.Name) var capabilities map[evdev.EvType][]evdev.EvCode @@ -88,6 +90,8 @@ func (parser *ConfigParser) ConnectPhysicalDevices() map[string]*evdev.InputDevi continue } + deviceConfig := deviceConfig.Config.(DeviceConfigPhysical) + var infoName string var device *evdev.InputDevice var err error diff --git a/internal/config/make_rule_targets.go b/internal/config/make_rule_targets.go index 7e8c2eb..203a015 100644 --- a/internal/config/make_rule_targets.go +++ b/internal/config/make_rule_targets.go @@ -8,7 +8,7 @@ import ( "github.com/holoplot/go-evdev" ) -func makeRuleTargetButton(targetConfig RuleTargetConfig, devs map[string]Device) (*mappingrules.RuleTargetButton, error) { +func makeRuleTargetButton(targetConfig RuleTargetConfigButton, devs map[string]Device) (*mappingrules.RuleTargetButton, error) { device, ok := devs[targetConfig.Device] if !ok { return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device) @@ -27,7 +27,7 @@ func makeRuleTargetButton(targetConfig RuleTargetConfig, devs map[string]Device) ) } -func makeRuleTargetAxis(targetConfig RuleTargetConfig, devs map[string]Device) (*mappingrules.RuleTargetAxis, error) { +func makeRuleTargetAxis(targetConfig RuleTargetConfigAxis, devs map[string]Device) (*mappingrules.RuleTargetAxis, error) { device, ok := devs[targetConfig.Device] if !ok { return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device) @@ -57,7 +57,7 @@ func makeRuleTargetAxis(targetConfig RuleTargetConfig, devs map[string]Device) ( ) } -func makeRuleTargetRelaxis(targetConfig RuleTargetConfig, devs map[string]Device) (*mappingrules.RuleTargetRelaxis, error) { +func makeRuleTargetRelaxis(targetConfig RuleTargetConfigRelaxis, devs map[string]Device) (*mappingrules.RuleTargetRelaxis, error) { device, ok := devs[targetConfig.Device] if !ok { return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device) @@ -72,11 +72,10 @@ func makeRuleTargetRelaxis(targetConfig RuleTargetConfig, devs map[string]Device targetConfig.Device, device, eventCode, - targetConfig.Inverted, ) } -func makeRuleTargetModeSelect(targetConfig RuleTargetConfig, allModes []string) (*mappingrules.RuleTargetModeSelect, error) { +func makeRuleTargetModeSelect(targetConfig RuleTargetConfigModeSelect, allModes []string) (*mappingrules.RuleTargetModeSelect, error) { if ok := validateModes(targetConfig.Modes, allModes); !ok { return nil, errors.New("undefined mode in mode select list") } @@ -92,7 +91,7 @@ func hasError(_ any, err error) bool { // calculateDeadzones produces the deadzone start and end values in absolute terms // TODO: on the one hand, this logic feels betten encapsulated in mappingrules. On the other hand, // passing even more parameters to NewRuleTargetAxis feels terrible -func calculateDeadzones(targetConfig RuleTargetConfig, device Device, axis evdev.EvCode) (int32, int32, error) { +func calculateDeadzones(targetConfig RuleTargetConfigAxis, device Device, axis evdev.EvCode) (int32, int32, error) { var deadzoneStart, deadzoneEnd int32 deadzoneStart = 0 diff --git a/internal/config/make_rule_targets_test.go b/internal/config/make_rule_targets_test.go index 6e71fa6..1c5b33f 100644 --- a/internal/config/make_rule_targets_test.go +++ b/internal/config/make_rule_targets_test.go @@ -12,7 +12,6 @@ type MakeRuleTargetsTests struct { suite.Suite devs map[string]Device deviceMock *DeviceMock - config RuleTargetConfig } type DeviceMock struct { @@ -47,198 +46,198 @@ func (t *MakeRuleTargetsTests) SetupSuite() { } } -func (t *MakeRuleTargetsTests) SetupSubTest() { - t.config = RuleTargetConfig{ - Device: "test", - } -} - func (t *MakeRuleTargetsTests) TestMakeRuleTargetButton() { + config := RuleTargetConfigButton{Device: "test"} + t.Run("Standard keycode", func() { - t.config.Button = "BTN_TRIGGER" - rule, err := makeRuleTargetButton(t.config, t.devs) + config.Button = "BTN_TRIGGER" + rule, err := makeRuleTargetButton(config, t.devs) t.Nil(err) t.EqualValues(evdev.BTN_TRIGGER, rule.Button) }) t.Run("Hex code", func() { - t.config.Button = "0x2fd" - rule, err := makeRuleTargetButton(t.config, t.devs) + config.Button = "0x2fd" + rule, err := makeRuleTargetButton(config, t.devs) t.Nil(err) t.EqualValues(evdev.EvCode(0x2fd), rule.Button) }) t.Run("Index", func() { - t.config.Button = "3" - rule, err := makeRuleTargetButton(t.config, t.devs) + config.Button = "3" + rule, err := makeRuleTargetButton(config, t.devs) t.Nil(err) t.EqualValues(evdev.BTN_TOP, rule.Button) }) t.Run("Index too high", func() { - t.config.Button = "74" - _, err := makeRuleTargetButton(t.config, t.devs) + config.Button = "74" + _, err := makeRuleTargetButton(config, t.devs) t.NotNil(err) }) t.Run("Un-prefixed keycode", func() { - t.config.Button = "pinkie" - rule, err := makeRuleTargetButton(t.config, t.devs) + config.Button = "pinkie" + rule, err := makeRuleTargetButton(config, t.devs) t.Nil(err) t.EqualValues(evdev.BTN_PINKIE, rule.Button) }) t.Run("Invalid keycode", func() { - t.config.Button = "foo" - _, err := makeRuleTargetButton(t.config, t.devs) + config.Button = "foo" + _, err := makeRuleTargetButton(config, t.devs) t.NotNil(err) }) } func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() { + config := RuleTargetConfigAxis{Device: "test"} + t.Run("Standard code", func() { - t.config.Axis = "ABS_X" - rule, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "ABS_X" + rule, err := makeRuleTargetAxis(config, t.devs) t.Nil(err) t.EqualValues(evdev.ABS_X, rule.Axis) }) t.Run("Hex code", func() { - t.config.Axis = "0x01" - rule, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "0x01" + rule, err := makeRuleTargetAxis(config, t.devs) t.Nil(err) t.EqualValues(evdev.ABS_Y, rule.Axis) }) t.Run("Un-prefixed code", func() { - t.config.Axis = "x" - rule, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + rule, err := makeRuleTargetAxis(config, t.devs) t.Nil(err) t.EqualValues(evdev.ABS_X, rule.Axis) }) t.Run("Invalid code", func() { - t.config.Axis = "foo" - _, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "foo" + _, err := makeRuleTargetAxis(config, t.devs) t.NotNil(err) }) t.Run("Invalid deadzone", func() { - t.config.Axis = "x" - t.config.DeadzoneEnd = 100 - t.config.DeadzoneStart = 1000 - _, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + config.DeadzoneEnd = 100 + config.DeadzoneStart = 1000 + _, err := makeRuleTargetAxis(config, t.devs) t.NotNil(err) }) t.Run("Deadzone center/size", func() { - t.config.Axis = "x" - t.config.DeadzoneCenter = 5000 - t.config.DeadzoneSize = 1000 - rule, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + config.DeadzoneCenter = 5000 + config.DeadzoneSize = 1000 + rule, err := makeRuleTargetAxis(config, t.devs) t.Nil(err) t.EqualValues(4500, rule.DeadzoneStart) t.EqualValues(5500, rule.DeadzoneEnd) }) t.Run("Deadzone center/size lower boundary", func() { - t.config.Axis = "x" - t.config.DeadzoneCenter = 0 - t.config.DeadzoneSize = 500 - rule, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + config.DeadzoneCenter = 0 + config.DeadzoneSize = 500 + rule, err := makeRuleTargetAxis(config, t.devs) t.Nil(err) t.EqualValues(0, rule.DeadzoneStart) t.EqualValues(500, rule.DeadzoneEnd) }) t.Run("Deadzone center/size upper boundary", func() { - t.config.Axis = "x" - t.config.DeadzoneCenter = 10000 - t.config.DeadzoneSize = 500 - rule, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + config.DeadzoneCenter = 10000 + config.DeadzoneSize = 500 + rule, err := makeRuleTargetAxis(config, t.devs) t.Nil(err) t.EqualValues(9500, rule.DeadzoneStart) t.EqualValues(10000, rule.DeadzoneEnd) }) t.Run("Deadzone center/size invalid center", func() { - t.config.Axis = "x" - t.config.DeadzoneCenter = 20000 - t.config.DeadzoneSize = 500 - _, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + config.DeadzoneCenter = 20000 + config.DeadzoneSize = 500 + _, err := makeRuleTargetAxis(config, t.devs) t.NotNil(err) }) t.Run("Deadzone center/percent", func() { - t.config.Axis = "x" - t.config.DeadzoneCenter = 5000 - t.config.DeadzoneSizePercent = 10 - rule, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + config.DeadzoneCenter = 5000 + config.DeadzoneSizePercent = 10 + rule, err := makeRuleTargetAxis(config, t.devs) t.Nil(err) t.EqualValues(4500, rule.DeadzoneStart) t.EqualValues(5500, rule.DeadzoneEnd) }) t.Run("Deadzone center/percent lower boundary", func() { - t.config.Axis = "x" - t.config.DeadzoneCenter = 0 - t.config.DeadzoneSizePercent = 10 - rule, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + config.DeadzoneCenter = 0 + config.DeadzoneSizePercent = 10 + rule, err := makeRuleTargetAxis(config, t.devs) t.Nil(err) t.EqualValues(0, rule.DeadzoneStart) t.EqualValues(1000, rule.DeadzoneEnd) }) t.Run("Deadzone center/percent upper boundary", func() { - t.config.Axis = "x" - t.config.DeadzoneCenter = 10000 - t.config.DeadzoneSizePercent = 10 - rule, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + config.DeadzoneCenter = 10000 + config.DeadzoneSizePercent = 10 + rule, err := makeRuleTargetAxis(config, t.devs) t.Nil(err) t.EqualValues(9000, rule.DeadzoneStart) t.EqualValues(10000, rule.DeadzoneEnd) }) t.Run("Deadzone center/percent invalid center", func() { - t.config.Axis = "x" - t.config.DeadzoneCenter = 20000 - t.config.DeadzoneSizePercent = 10 - _, err := makeRuleTargetAxis(t.config, t.devs) + config.Axis = "x" + config.DeadzoneCenter = 20000 + config.DeadzoneSizePercent = 10 + _, err := makeRuleTargetAxis(config, t.devs) t.NotNil(err) }) } func (t *MakeRuleTargetsTests) TestMakeRuleTargetRelaxis() { + config := RuleTargetConfigRelaxis{Device: "test"} + t.Run("Standard keycode", func() { - t.config.Axis = "REL_WHEEL" - rule, err := makeRuleTargetRelaxis(t.config, t.devs) + config.Axis = "REL_WHEEL" + rule, err := makeRuleTargetRelaxis(config, t.devs) t.Nil(err) t.EqualValues(evdev.REL_WHEEL, rule.Axis) }) t.Run("Hex keycode", func() { - t.config.Axis = "0x00" - rule, err := makeRuleTargetRelaxis(t.config, t.devs) + config.Axis = "0x00" + rule, err := makeRuleTargetRelaxis(config, t.devs) t.Nil(err) t.EqualValues(evdev.REL_X, rule.Axis) }) t.Run("Un-prefixed keycode", func() { - t.config.Axis = "wheel" - rule, err := makeRuleTargetRelaxis(t.config, t.devs) + config.Axis = "wheel" + rule, err := makeRuleTargetRelaxis(config, t.devs) t.Nil(err) t.EqualValues(evdev.REL_WHEEL, rule.Axis) }) t.Run("Invalid keycode", func() { - t.config.Axis = "foo" - _, err := makeRuleTargetRelaxis(t.config, t.devs) + config.Axis = "foo" + _, err := makeRuleTargetRelaxis(config, t.devs) t.NotNil(err) }) t.Run("Incorrect axis type", func() { - t.config.Axis = "ABS_X" - _, err := makeRuleTargetRelaxis(t.config, t.devs) + config.Axis = "ABS_X" + _, err := makeRuleTargetRelaxis(config, t.devs) t.NotNil(err) }) } diff --git a/internal/config/make_rules.go b/internal/config/make_rules.go index 647987c..b3e73f3 100644 --- a/internal/config/make_rules.go +++ b/internal/config/make_rules.go @@ -42,21 +42,21 @@ func (parser *ConfigParser) BuildRules(pInputDevs map[string]*evdev.InputDevice, switch strings.ToLower(ruleConfig.Type) { case RuleTypeButton: - newRule, err = makeMappingRuleButton(ruleConfig, pDevs, vDevs, base) + newRule, err = makeMappingRuleButton(ruleConfig.Config.(RuleConfigButton), pDevs, vDevs, base) case RuleTypeButtonCombo: - newRule, err = makeMappingRuleCombo(ruleConfig, pDevs, vDevs, base) - case RuleTypeLatched: - newRule, err = makeMappingRuleLatched(ruleConfig, pDevs, vDevs, base) + newRule, err = makeMappingRuleCombo(ruleConfig.Config.(RuleConfigButtonCombo), pDevs, vDevs, base) + case RuleTypeButtonLatched: + newRule, err = makeMappingRuleLatched(ruleConfig.Config.(RuleConfigButtonLatched), pDevs, vDevs, base) case RuleTypeAxis: - newRule, err = makeMappingRuleAxis(ruleConfig, pDevs, vDevs, base) + newRule, err = makeMappingRuleAxis(ruleConfig.Config.(RuleConfigAxis), pDevs, vDevs, base) case RuleTypeAxisCombined: - newRule, err = makeMappingRuleAxisCombined(ruleConfig, pDevs, vDevs, base) + newRule, err = makeMappingRuleAxisCombined(ruleConfig.Config.(RuleConfigAxisCombined), pDevs, vDevs, base) case RuleTypeAxisToButton: - newRule, err = makeMappingRuleAxisToButton(ruleConfig, pDevs, vDevs, base) + newRule, err = makeMappingRuleAxisToButton(ruleConfig.Config.(RuleConfigAxisToButton), pDevs, vDevs, base) case RuleTypeAxisToRelaxis: - newRule, err = makeMappingRuleAxisToRelaxis(ruleConfig, pDevs, vDevs, base) + newRule, err = makeMappingRuleAxisToRelaxis(ruleConfig.Config.(RuleConfigAxisToRelaxis), pDevs, vDevs, base) case RuleTypeModeSelect: - newRule, err = makeMappingRuleModeSelect(ruleConfig, pDevs, modes, base) + newRule, err = makeMappingRuleModeSelect(ruleConfig.Config.(RuleConfigModeSelect), pDevs, modes, base) default: err = fmt.Errorf("bad rule type '%s' for rule '%s'", ruleConfig.Type, ruleConfig.Name) } @@ -72,7 +72,14 @@ func (parser *ConfigParser) BuildRules(pInputDevs map[string]*evdev.InputDevice, return rules } -func makeMappingRuleButton(ruleConfig RuleConfig, +// TODO: how much of these functions could we fold into the unmarshaling logic itself? The main problem +// is that we don't have access to the device maps in those functions... could we set device names +// as stand-ins and do a post-processing pass that *just* handles device linking and possibly mode +// checking? +// +// In other words - can we unmarshal the config directly into our target structs and remove most of +// this library? +func makeMappingRuleButton(ruleConfig RuleConfigButton, pDevs map[string]Device, vDevs map[string]Device, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButton, error) { @@ -90,7 +97,7 @@ func makeMappingRuleButton(ruleConfig RuleConfig, return mappingrules.NewMappingRuleButton(base, input, output), nil } -func makeMappingRuleCombo(ruleConfig RuleConfig, +func makeMappingRuleCombo(ruleConfig RuleConfigButtonCombo, pDevs map[string]Device, vDevs map[string]Device, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButtonCombo, error) { @@ -112,7 +119,7 @@ func makeMappingRuleCombo(ruleConfig RuleConfig, return mappingrules.NewMappingRuleButtonCombo(base, inputs, output), nil } -func makeMappingRuleLatched(ruleConfig RuleConfig, +func makeMappingRuleLatched(ruleConfig RuleConfigButtonLatched, pDevs map[string]Device, vDevs map[string]Device, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButtonLatched, error) { @@ -130,7 +137,7 @@ func makeMappingRuleLatched(ruleConfig RuleConfig, return mappingrules.NewMappingRuleButtonLatched(base, input, output), nil } -func makeMappingRuleAxis(ruleConfig RuleConfig, +func makeMappingRuleAxis(ruleConfig RuleConfigAxis, pDevs map[string]Device, vDevs map[string]Device, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxis, error) { @@ -148,7 +155,7 @@ func makeMappingRuleAxis(ruleConfig RuleConfig, return mappingrules.NewMappingRuleAxis(base, input, output), nil } -func makeMappingRuleAxisCombined(ruleConfig RuleConfig, +func makeMappingRuleAxisCombined(ruleConfig RuleConfigAxisCombined, pDevs map[string]Device, vDevs map[string]Device, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxisCombined, error) { @@ -171,7 +178,7 @@ func makeMappingRuleAxisCombined(ruleConfig RuleConfig, return mappingrules.NewMappingRuleAxisCombined(base, inputLower, inputUpper, output), nil } -func makeMappingRuleAxisToButton(ruleConfig RuleConfig, +func makeMappingRuleAxisToButton(ruleConfig RuleConfigAxisToButton, pDevs map[string]Device, vDevs map[string]Device, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxisToButton, error) { @@ -189,7 +196,7 @@ func makeMappingRuleAxisToButton(ruleConfig RuleConfig, return mappingrules.NewMappingRuleAxisToButton(base, input, output, ruleConfig.RepeatRateMin, ruleConfig.RepeatRateMax), nil } -func makeMappingRuleAxisToRelaxis(ruleConfig RuleConfig, +func makeMappingRuleAxisToRelaxis(ruleConfig RuleConfigAxisToRelaxis, pDevs map[string]Device, vDevs map[string]Device, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxisToRelaxis, error) { @@ -211,7 +218,7 @@ func makeMappingRuleAxisToRelaxis(ruleConfig RuleConfig, ruleConfig.Increment), nil } -func makeMappingRuleModeSelect(ruleConfig RuleConfig, +func makeMappingRuleModeSelect(ruleConfig RuleConfigModeSelect, pDevs map[string]Device, modes []string, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleModeSelect, error) { diff --git a/internal/config/schema.go b/internal/config/schema.go index 1ea3527..083005a 100644 --- a/internal/config/schema.go +++ b/internal/config/schema.go @@ -1,25 +1,39 @@ // These types comprise the YAML schema for configuring Joyful. // The config files will be combined and then unmarshalled into this -// -// TODO: currently the types in here aren't especially strong; each one is -// decomposed into a different object based on the Type fields. We should implement -// some sort of delayed unmarshalling technique, for example see ideas at -// https://stackoverflow.com/questions/70635636/unmarshaling-yaml-into-different-struct-based-off-yaml-field -// Then we can be more explicit about the interface here. package config +import "fmt" + type Config struct { - Devices []DeviceConfig `yaml:"devices"` - Modes []string `yaml:"modes,omitempty"` - Rules []RuleConfig `yaml:"rules"` + Devices []DeviceConfig + Modes []string + Rules []RuleConfig } +// These structs use custom unmarshaling to inline each available sub-type type DeviceConfig struct { + Type string + Config interface{} `yaml:",inline"` +} + +type RuleConfig struct { + Type string + Name string + Modes []string + Config interface{} `yaml:",inline"` +} + +type DeviceConfigPhysical struct { + Name string `yaml:"name"` + DeviceName string `yaml:"device_name,omitempty"` + DevicePath string `yaml:"device_path,omitempty"` + Lock bool `yaml:"lock,omitempty"` +} + +// TODO: configure custom unmarshaling so we can overload Buttons, Axes, and RelativeAxes... +type DeviceConfigVirtual struct { Name string `yaml:"name"` - Type string `yaml:"type"` - DeviceName string `yaml:"device_name,omitempty"` - DevicePath string `yaml:"device_path,omitempty"` Preset string `yaml:"preset,omitempty"` NumButtons int `yaml:"num_buttons,omitempty"` NumAxes int `yaml:"num_axes,omitempty"` @@ -27,53 +41,130 @@ type DeviceConfig struct { Buttons []string `yaml:"buttons,omitempty"` Axes []string `yaml:"axes,omitempty"` RelativeAxes []string `yaml:"rel_axes,omitempty"` - Lock bool `yaml:"lock,omitempty"` } -type RuleConfig struct { - Name string `yaml:"name,omitempty"` - Type string `yaml:"type"` - Input RuleTargetConfig `yaml:"input,omitempty"` - InputLower RuleTargetConfig `yaml:"input_lower,omitempty"` - InputUpper RuleTargetConfig `yaml:"input_upper,omitempty"` - Inputs []RuleTargetConfig `yaml:"inputs,omitempty"` - Output RuleTargetConfig `yaml:"output"` - Modes []string `yaml:"modes,omitempty"` - RepeatRateMin int `yaml:"repeat_rate_min,omitempty"` - RepeatRateMax int `yaml:"repeat_rate_max,omitempty"` - Increment int `yaml:"increment,omitempty"` +type RuleConfigButton struct { + Input RuleTargetConfigButton + Output RuleTargetConfigButton } -type RuleTargetConfig struct { - Device string `yaml:"device,omitempty"` - Button string `yaml:"button,omitempty"` - Axis string `yaml:"axis,omitempty"` - DeadzoneCenter int32 `yaml:"deadzone_center,omitempty"` - DeadzoneSize int32 `yaml:"deadzone_size,omitempty"` - DeadzoneSizePercent int32 `yaml:"deadzone_size_percent,omitempty"` - DeadzoneStart int32 `yaml:"deadzone_start,omitempty"` - DeadzoneEnd int32 `yaml:"deadzone_end,omitempty"` - Inverted bool `yaml:"inverted,omitempty"` - Modes []string `yaml:"modes,omitempty"` +type RuleConfigButtonCombo struct { + Inputs []RuleTargetConfigButton + Output RuleTargetConfigButton +} + +type RuleConfigButtonLatched struct { + Input RuleTargetConfigButton + Output RuleTargetConfigButton +} + +type RuleConfigAxis struct { + Input RuleTargetConfigAxis + Output RuleTargetConfigAxis +} + +type RuleConfigAxisCombined struct { + InputLower RuleTargetConfigAxis `yaml:"input_lower,omitempty"` + InputUpper RuleTargetConfigAxis `yaml:"input_upper,omitempty"` + Output RuleTargetConfigAxis +} + +type RuleConfigAxisToButton struct { + RepeatRateMin int `yaml:"repeat_rate_min,omitempty"` + RepeatRateMax int `yaml:"repeat_rate_max,omitempty"` + Input RuleTargetConfigAxis + Output RuleTargetConfigButton +} + +type RuleConfigAxisToRelaxis struct { + RepeatRateMin int `yaml:"repeat_rate_min"` + RepeatRateMax int `yaml:"repeat_rate_max"` + Increment int + Input RuleTargetConfigAxis + Output RuleTargetConfigRelaxis +} + +type RuleConfigModeSelect struct { + Input RuleTargetConfigButton + Output RuleTargetConfigModeSelect +} + +type RuleTargetConfigButton struct { + Device string + Button string + Inverted bool +} + +type RuleTargetConfigAxis struct { + Device string + Axis string + DeadzoneCenter int32 `yaml:"deadzone_center,omitempty"` + DeadzoneSize int32 `yaml:"deadzone_size,omitempty"` + DeadzoneSizePercent int32 `yaml:"deadzone_size_percent,omitempty"` + DeadzoneStart int32 `yaml:"deadzone_start,omitempty"` + DeadzoneEnd int32 `yaml:"deadzone_end,omitempty"` + Inverted bool +} + +type RuleTargetConfigRelaxis struct { + Device string + Axis string +} + +type RuleTargetConfigModeSelect struct { + Modes []string +} + +func (dc *DeviceConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error { + var config interface{} + dc.Config = config + + switch dc.Type { + case DeviceTypePhysical: + config = &DeviceConfigPhysical{} + case DeviceTypeVirtual: + config = &DeviceConfigVirtual{} + default: + return fmt.Errorf("invalid device type '%s'", dc.Type) + } + + return unmarshal(&config) +} + +func (dc *RuleConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error { + switch dc.Type { + case RuleTypeButton: + dc.Config = &RuleConfigButton{} + case RuleTypeButtonCombo: + dc.Config = &RuleConfigButtonCombo{} + case RuleTypeButtonLatched: + dc.Config = &RuleConfigButtonLatched{} + case RuleTypeAxis: + dc.Config = &RuleConfigAxis{} + case RuleTypeAxisCombined: + dc.Config = &RuleConfigAxisCombined{} + case RuleTypeAxisToButton: + dc.Config = &RuleConfigAxisToButton{} + case RuleTypeAxisToRelaxis: + dc.Config = &RuleConfigAxisToRelaxis{} + default: + return fmt.Errorf("invalid rule type '%s'", dc.Type) + } + + return unmarshal(&dc.Config) } // TODO: custom yaml unmarshaling is obtuse; do we really need to do all of this work // just to set a single default value? -func (dc *DeviceConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error { +func (dc *DeviceConfigPhysical) UnmarshalYAML(unmarshal func(data interface{}) error) error { var raw struct { - Name string - Type string - DeviceName string `yaml:"device_name"` - DevicePath string `yaml:"device_path"` - Preset string - NumButtons int `yaml:"num_buttons"` - NumAxes int `yaml:"num_axes"` - NumRelativeAxes int `yaml:"num_rel_axes"` - Buttons []string - Axes []string - RelativeAxes []string `yaml:"relative_axes"` - Lock bool `yaml:"lock,omitempty"` + Name string + DeviceName string `yaml:"device_name"` + DevicePath string `yaml:"device_path"` + Lock bool `yaml:"lock,omitempty"` } + + // Set non-standard defaults raw.Lock = true err := unmarshal(&raw) @@ -81,19 +172,11 @@ func (dc *DeviceConfig) UnmarshalYAML(unmarshal func(data interface{}) error) er return err } - *dc = DeviceConfig{ - Name: raw.Name, - Type: raw.Type, - DeviceName: raw.DeviceName, - DevicePath: raw.DevicePath, - Preset: raw.Preset, - NumButtons: raw.NumButtons, - NumAxes: raw.NumAxes, - NumRelativeAxes: raw.NumRelativeAxes, - Buttons: raw.Buttons, - Axes: raw.Axes, - RelativeAxes: raw.RelativeAxes, - Lock: raw.Lock, + *dc = DeviceConfigPhysical{ + Name: raw.Name, + DeviceName: raw.DeviceName, + DevicePath: raw.DevicePath, + Lock: raw.Lock, } return nil } diff --git a/internal/config/variables.go b/internal/config/variables.go index e4e0bf0..6e62977 100644 --- a/internal/config/variables.go +++ b/internal/config/variables.go @@ -15,12 +15,12 @@ const ( RuleTypeButton = "button" RuleTypeButtonCombo = "button-combo" - RuleTypeLatched = "button-latched" + RuleTypeButtonLatched = "button-latched" RuleTypeAxis = "axis" RuleTypeAxisCombined = "axis-combined" - RuleTypeModeSelect = "mode-select" RuleTypeAxisToButton = "axis-to-button" RuleTypeAxisToRelaxis = "axis-to-relaxis" + RuleTypeModeSelect = "mode-select" CodePrefixButton = "BTN" CodePrefixKey = "KEY" diff --git a/internal/mappingrules/rule_target_relaxis.go b/internal/mappingrules/rule_target_relaxis.go index 8de8c0b..1942c4b 100644 --- a/internal/mappingrules/rule_target_relaxis.go +++ b/internal/mappingrules/rule_target_relaxis.go @@ -8,19 +8,16 @@ type RuleTargetRelaxis struct { DeviceName string Device Device Axis evdev.EvCode - Inverted bool } func NewRuleTargetRelaxis(device_name string, device Device, - axis evdev.EvCode, - inverted bool) (*RuleTargetRelaxis, error) { + axis evdev.EvCode) (*RuleTargetRelaxis, error) { return &RuleTargetRelaxis{ DeviceName: device_name, Device: device, Axis: axis, - Inverted: inverted, }, nil } -- 2.47.2 From f9355c6cece1b4b42ff79d7d8ccad3b9ad55c247 Mon Sep 17 00:00:00 2001 From: Anna Rose Wiggins Date: Fri, 8 Aug 2025 18:21:04 -0400 Subject: [PATCH 2/4] Fix tests. --- internal/config/make_rule_targets_test.go | 160 +++++++++++----------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/internal/config/make_rule_targets_test.go b/internal/config/make_rule_targets_test.go index 1c5b33f..7ee8fb8 100644 --- a/internal/config/make_rule_targets_test.go +++ b/internal/config/make_rule_targets_test.go @@ -1,6 +1,7 @@ package config import ( + "fmt" "testing" "github.com/holoplot/go-evdev" @@ -91,36 +92,35 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetButton() { } func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() { - config := RuleTargetConfigAxis{Device: "test"} + codeTestCases := []struct { + input string + output evdev.EvCode + }{ + {"ABS_X", evdev.ABS_X}, + {"0x01", evdev.ABS_Y}, + {"x", evdev.ABS_X}, + } - t.Run("Standard code", func() { - config.Axis = "ABS_X" - rule, err := makeRuleTargetAxis(config, t.devs) - t.Nil(err) - t.EqualValues(evdev.ABS_X, rule.Axis) - }) + for _, tc := range codeTestCases { + t.Run(fmt.Sprintf("KeyCode %s", tc.input), func() { + config := RuleTargetConfigAxis{Device: "test"} + config.Axis = tc.input + rule, err := makeRuleTargetAxis(config, t.devs) + t.Nil(err) + t.EqualValues(tc.output, rule.Axis) - t.Run("Hex code", func() { - config.Axis = "0x01" - rule, err := makeRuleTargetAxis(config, t.devs) - t.Nil(err) - t.EqualValues(evdev.ABS_Y, rule.Axis) - }) - - t.Run("Un-prefixed code", func() { - config.Axis = "x" - rule, err := makeRuleTargetAxis(config, t.devs) - t.Nil(err) - t.EqualValues(evdev.ABS_X, rule.Axis) - }) + }) + } t.Run("Invalid code", func() { + config := RuleTargetConfigAxis{Device: "test"} config.Axis = "foo" _, err := makeRuleTargetAxis(config, t.devs) t.NotNil(err) }) t.Run("Invalid deadzone", func() { + config := RuleTargetConfigAxis{Device: "test"} config.Axis = "x" config.DeadzoneEnd = 100 config.DeadzoneStart = 1000 @@ -128,78 +128,78 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() { t.NotNil(err) }) - t.Run("Deadzone center/size", func() { - config.Axis = "x" - config.DeadzoneCenter = 5000 - config.DeadzoneSize = 1000 - rule, err := makeRuleTargetAxis(config, t.devs) - t.Nil(err) - t.EqualValues(4500, rule.DeadzoneStart) - t.EqualValues(5500, rule.DeadzoneEnd) - }) + relDeadzoneTestCases := []struct { + inCenter int32 + inSize int32 + outStart int32 + outEnd int32 + }{ + {5000, 1000, 4500, 5500}, + {0, 500, 0, 500}, + {10000, 500, 9500, 10000}, + } - t.Run("Deadzone center/size lower boundary", func() { - config.Axis = "x" - config.DeadzoneCenter = 0 - config.DeadzoneSize = 500 - rule, err := makeRuleTargetAxis(config, t.devs) - t.Nil(err) - t.EqualValues(0, rule.DeadzoneStart) - t.EqualValues(500, rule.DeadzoneEnd) - }) + for _, tc := range relDeadzoneTestCases { + t.Run(fmt.Sprintf("Relative Deadzone %d +- %d", tc.inCenter, tc.inSize), func() { + config := RuleTargetConfigAxis{ + Device: "test", + Axis: "x", + DeadzoneCenter: tc.inCenter, + DeadzoneSize: tc.inSize, + } + rule, err := makeRuleTargetAxis(config, t.devs) - t.Run("Deadzone center/size upper boundary", func() { - config.Axis = "x" - config.DeadzoneCenter = 10000 - config.DeadzoneSize = 500 - rule, err := makeRuleTargetAxis(config, t.devs) - t.Nil(err) - t.EqualValues(9500, rule.DeadzoneStart) - t.EqualValues(10000, rule.DeadzoneEnd) - }) + t.Nil(err) + t.Equal(tc.outStart, rule.DeadzoneStart) + t.Equal(tc.outEnd, rule.DeadzoneEnd) + }) + } t.Run("Deadzone center/size invalid center", func() { - config.Axis = "x" - config.DeadzoneCenter = 20000 - config.DeadzoneSize = 500 + config := RuleTargetConfigAxis{ + Device: "test", + Axis: "x", + DeadzoneCenter: 20000, + DeadzoneSize: 500, + } _, err := makeRuleTargetAxis(config, t.devs) t.NotNil(err) }) - t.Run("Deadzone center/percent", func() { - config.Axis = "x" - config.DeadzoneCenter = 5000 - config.DeadzoneSizePercent = 10 - rule, err := makeRuleTargetAxis(config, t.devs) - t.Nil(err) - t.EqualValues(4500, rule.DeadzoneStart) - t.EqualValues(5500, rule.DeadzoneEnd) - }) + relDeadzonePercentTestCases := []struct { + inCenter int32 + inSizePercent int32 + outStart int32 + outEnd int32 + }{ + {5000, 10, 4500, 5500}, + {0, 10, 0, 1000}, + {10000, 10, 9000, 10000}, + } - t.Run("Deadzone center/percent lower boundary", func() { - config.Axis = "x" - config.DeadzoneCenter = 0 - config.DeadzoneSizePercent = 10 - rule, err := makeRuleTargetAxis(config, t.devs) - t.Nil(err) - t.EqualValues(0, rule.DeadzoneStart) - t.EqualValues(1000, rule.DeadzoneEnd) - }) + for _, tc := range relDeadzonePercentTestCases { + t.Run(fmt.Sprintf("Relative percent deadzone %d +- %d%%", tc.inCenter, tc.inSizePercent), func() { + config := RuleTargetConfigAxis{ + Device: "test", + Axis: "x", + DeadzoneCenter: tc.inCenter, + DeadzoneSizePercent: tc.inSizePercent, + } + rule, err := makeRuleTargetAxis(config, t.devs) - t.Run("Deadzone center/percent upper boundary", func() { - config.Axis = "x" - config.DeadzoneCenter = 10000 - config.DeadzoneSizePercent = 10 - rule, err := makeRuleTargetAxis(config, t.devs) - t.Nil(err) - t.EqualValues(9000, rule.DeadzoneStart) - t.EqualValues(10000, rule.DeadzoneEnd) - }) + t.Nil(err) + t.Equal(tc.outStart, rule.DeadzoneStart) + t.Equal(tc.outEnd, rule.DeadzoneEnd) + }) + } t.Run("Deadzone center/percent invalid center", func() { - config.Axis = "x" - config.DeadzoneCenter = 20000 - config.DeadzoneSizePercent = 10 + config := RuleTargetConfigAxis{ + Device: "test", + Axis: "x", + DeadzoneCenter: 20000, + DeadzoneSizePercent: 10, + } _, err := makeRuleTargetAxis(config, t.devs) t.NotNil(err) }) -- 2.47.2 From 4b4930ebdc85879b4802859e6f99072be5400435 Mon Sep 17 00:00:00 2001 From: Anna Rose Wiggins Date: Sat, 9 Aug 2025 12:10:53 -0400 Subject: [PATCH 3/4] Fix custom unmarshaling. --- internal/config/schema.go | 109 ++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 33 deletions(-) diff --git a/internal/config/schema.go b/internal/config/schema.go index 083005a..ad91f28 100644 --- a/internal/config/schema.go +++ b/internal/config/schema.go @@ -3,7 +3,9 @@ package config -import "fmt" +import ( + "fmt" +) type Config struct { Devices []DeviceConfig @@ -11,35 +13,35 @@ type Config struct { Rules []RuleConfig } -// These structs use custom unmarshaling to inline each available sub-type +// These top-level structs use custom unmarshaling to unpack each available sub-type type DeviceConfig struct { Type string - Config interface{} `yaml:",inline"` + Config interface{} } type RuleConfig struct { Type string Name string Modes []string - Config interface{} `yaml:",inline"` + Config interface{} } type DeviceConfigPhysical struct { - Name string `yaml:"name"` + Name string DeviceName string `yaml:"device_name,omitempty"` DevicePath string `yaml:"device_path,omitempty"` - Lock bool `yaml:"lock,omitempty"` + Lock bool } // TODO: configure custom unmarshaling so we can overload Buttons, Axes, and RelativeAxes... type DeviceConfigVirtual struct { - Name string `yaml:"name"` - Preset string `yaml:"preset,omitempty"` - NumButtons int `yaml:"num_buttons,omitempty"` - NumAxes int `yaml:"num_axes,omitempty"` - NumRelativeAxes int `yaml:"num_rel_axes"` - Buttons []string `yaml:"buttons,omitempty"` - Axes []string `yaml:"axes,omitempty"` + Name string + Preset string + NumButtons int `yaml:"num_buttons,omitempty"` + NumAxes int `yaml:"num_axes,omitempty"` + NumRelativeAxes int `yaml:"num_rel_axes"` + Buttons []string + Axes []string RelativeAxes []string `yaml:"rel_axes,omitempty"` } @@ -116,42 +118,83 @@ type RuleTargetConfigModeSelect struct { } func (dc *DeviceConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error { - var config interface{} - dc.Config = config - - switch dc.Type { - case DeviceTypePhysical: - config = &DeviceConfigPhysical{} - case DeviceTypeVirtual: - config = &DeviceConfigVirtual{} - default: - return fmt.Errorf("invalid device type '%s'", dc.Type) + metaConfig := &struct { + Type string + }{} + err := unmarshal(metaConfig) + if err != nil { + return err } + dc.Type = metaConfig.Type - return unmarshal(&config) + err = nil + switch metaConfig.Type { + case DeviceTypePhysical: + config := DeviceConfigPhysical{} + err = unmarshal(&config) + dc.Config = config + case DeviceTypeVirtual: + config := DeviceConfigVirtual{} + err = unmarshal(&config) + dc.Config = config + default: + err = fmt.Errorf("invalid device type '%s'", dc.Type) + } + return err } func (dc *RuleConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error { + metaConfig := &struct { + Type string + Name string + Modes []string + }{} + err := unmarshal(metaConfig) + if err != nil { + return err + } + dc.Type = metaConfig.Type + dc.Name = metaConfig.Name + dc.Modes = metaConfig.Modes + switch dc.Type { case RuleTypeButton: - dc.Config = &RuleConfigButton{} + config := RuleConfigButton{} + err = unmarshal(&config) + dc.Config = config case RuleTypeButtonCombo: - dc.Config = &RuleConfigButtonCombo{} + config := RuleConfigButtonCombo{} + err = unmarshal(&config) + dc.Config = config case RuleTypeButtonLatched: - dc.Config = &RuleConfigButtonLatched{} + config := RuleConfigButtonLatched{} + err = unmarshal(&config) + dc.Config = config case RuleTypeAxis: - dc.Config = &RuleConfigAxis{} + config := RuleConfigAxis{} + err = unmarshal(&config) + dc.Config = config case RuleTypeAxisCombined: - dc.Config = &RuleConfigAxisCombined{} + config := RuleConfigAxisCombined{} + err = unmarshal(&config) + dc.Config = config case RuleTypeAxisToButton: - dc.Config = &RuleConfigAxisToButton{} + config := RuleConfigAxisToButton{} + err = unmarshal(&config) + dc.Config = config case RuleTypeAxisToRelaxis: - dc.Config = &RuleConfigAxisToRelaxis{} + config := RuleConfigAxisToRelaxis{} + err = unmarshal(&config) + dc.Config = config + case RuleTypeModeSelect: + config := RuleConfigModeSelect{} + err = unmarshal(&config) + dc.Config = config default: - return fmt.Errorf("invalid rule type '%s'", dc.Type) + err = fmt.Errorf("invalid rule type '%s'", dc.Type) } - return unmarshal(&dc.Config) + return err } // TODO: custom yaml unmarshaling is obtuse; do we really need to do all of this work -- 2.47.2 From a876dabe6ef0b3b467fd25c7ae54d4eb95449ea3 Mon Sep 17 00:00:00 2001 From: Anna Rose Wiggins Date: Sat, 9 Aug 2025 12:32:17 -0400 Subject: [PATCH 4/4] Code cleanup and refactoring. --- cmd/joyful/main.go | 28 +++++++++++----------------- internal/config/devices.go | 14 +++++++------- internal/config/make_rules.go | 2 +- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/cmd/joyful/main.go b/cmd/joyful/main.go index 17482bf..f6cf6de 100644 --- a/cmd/joyful/main.go +++ b/cmd/joyful/main.go @@ -28,8 +28,11 @@ func readConfig(configDir string) *config.ConfigParser { return parser } -func initVirtualBuffers(config *config.ConfigParser) (map[string]*virtualdevice.EventBuffer, map[*evdev.InputDevice]*virtualdevice.EventBuffer) { - vDevices := config.CreateVirtualDevices() +func initVirtualBuffers(config *config.ConfigParser) (map[string]*evdev.InputDevice, + map[string]*virtualdevice.EventBuffer, + map[*evdev.InputDevice]*virtualdevice.EventBuffer) { + + vDevices := config.InitVirtualDevices() if len(vDevices) == 0 { logger.Log("Warning: no virtual devices found in configuration. No rules will work.") } @@ -40,20 +43,11 @@ func initVirtualBuffers(config *config.ConfigParser) (map[string]*virtualdevice. vBuffersByName[name] = virtualdevice.NewEventBuffer(device) vBuffersByDevice[device] = vBuffersByName[name] } - return vBuffersByName, vBuffersByDevice -} - -// Extracts the evdev devices from a list of virtual buffers and returns them. -func getVirtualDevices(buffers map[string]*virtualdevice.EventBuffer) map[string]*evdev.InputDevice { - devices := make(map[string]*evdev.InputDevice) - for name, buffer := range buffers { - devices[name] = buffer.Device.(*evdev.InputDevice) - } - return devices + return vDevices, vBuffersByName, vBuffersByDevice } func initPhysicalDevices(config *config.ConfigParser) map[string]*evdev.InputDevice { - pDeviceMap := config.ConnectPhysicalDevices() + pDeviceMap := config.InitPhysicalDevices() if len(pDeviceMap) == 0 { logger.Log("Warning: no physical devices found in configuration. No rules will work.") } @@ -77,13 +71,13 @@ func main() { logger.LogIfError(err, "Failed to initialize TTS") // Initialize virtual devices with event buffers - vBuffersByName, vBuffersByDevice := initVirtualBuffers(config) + vDevicesByName, vBuffersByName, vBuffersByDevice := initVirtualBuffers(config) // Initialize physical devices pDevices := initPhysicalDevices(config) // Load the rules - rules, eventChannel, cancel, wg := loadRules(config, pDevices, getVirtualDevices(vBuffersByName)) + rules, eventChannel, cancel, wg := loadRules(config, pDevices, vDevicesByName) // initialize the mode variable mode := config.GetModes()[0] @@ -139,7 +133,7 @@ func main() { wg.Wait() fmt.Println("Listeners exited. Parsing config.") config := readConfig(configDir) // reload the config - rules, eventChannel, cancel, wg = loadRules(config, pDevices, getVirtualDevices(vBuffersByName)) + rules, eventChannel, cancel, wg = loadRules(config, pDevices, vDevicesByName) fmt.Println("Config re-loaded. Only rule changes applied. Device and Mode changes require restart.") } @@ -159,7 +153,7 @@ func loadRules( ctx, cancel := context.WithCancel(context.Background()) // Initialize rules - rules := config.BuildRules(pDevices, vDevices) + rules := config.InitRules(pDevices, vDevices) logger.Logf("Created %d mapping rules.", len(rules)) // start listening for events on devices and timers diff --git a/internal/config/devices.go b/internal/config/devices.go index 4fa75da..d933ed7 100644 --- a/internal/config/devices.go +++ b/internal/config/devices.go @@ -8,13 +8,13 @@ import ( "github.com/holoplot/go-evdev" ) -// CreateVirtualDevices will register any configured devices with type = virtual +// InitVirtualDevices will register any configured devices with type = virtual // using /dev/uinput, and return a map of those devices. // -// This function assumes you have already called Parse() on the config directory. +// This function assumes Parse() has been called. // -// This function should only be called once, unless you want to create duplicate devices for some reason. -func (parser *ConfigParser) CreateVirtualDevices() map[string]*evdev.InputDevice { +// This function should only be called once, unless we want to create duplicate devices for some reason. +func (parser *ConfigParser) InitVirtualDevices() map[string]*evdev.InputDevice { deviceMap := make(map[string]*evdev.InputDevice) for _, deviceConfig := range parser.config.Devices { @@ -76,13 +76,13 @@ func (parser *ConfigParser) CreateVirtualDevices() map[string]*evdev.InputDevice return deviceMap } -// ConnectPhysicalDevices will create InputDevices corresponding to any registered +// InitPhysicalDevices will create InputDevices corresponding to any registered // devices with type = physical. // -// This function assumes you have already called Parse() on the config directory. +// This function assumes Parse() has been called. // // This function should only be called once. -func (parser *ConfigParser) ConnectPhysicalDevices() map[string]*evdev.InputDevice { +func (parser *ConfigParser) InitPhysicalDevices() map[string]*evdev.InputDevice { deviceMap := make(map[string]*evdev.InputDevice) for _, deviceConfig := range parser.config.Devices { diff --git a/internal/config/make_rules.go b/internal/config/make_rules.go index b3e73f3..9baf9d7 100644 --- a/internal/config/make_rules.go +++ b/internal/config/make_rules.go @@ -14,7 +14,7 @@ import ( // This would speed up rule matching by only checking relevant rules for a given input event. // We could take this further and make it a map[][]rule // For very large rule-bases this may be helpful for staying performant. -func (parser *ConfigParser) BuildRules(pInputDevs map[string]*evdev.InputDevice, vInputDevs map[string]*evdev.InputDevice) []mappingrules.MappingRule { +func (parser *ConfigParser) InitRules(pInputDevs map[string]*evdev.InputDevice, vInputDevs map[string]*evdev.InputDevice) []mappingrules.MappingRule { rules := make([]mappingrules.MappingRule, 0) modes := parser.GetModes() -- 2.47.2