Move rule target builders into the correct locations.
This commit is contained in:
parent
9e4062ba30
commit
33b62496a3
17 changed files with 198 additions and 194 deletions
|
@ -1,156 +0,0 @@
|
||||||
package mappingrules
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"slices"
|
|
||||||
|
|
||||||
"git.annabunches.net/annabunches/joyful/internal/configparser"
|
|
||||||
"git.annabunches.net/annabunches/joyful/internal/eventcodes"
|
|
||||||
"github.com/holoplot/go-evdev"
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeRuleTargetButton(targetConfig configparser.RuleTargetConfigButton, devs map[string]Device) (*RuleTargetButton, error) {
|
|
||||||
device, ok := devs[targetConfig.Device]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
|
||||||
}
|
|
||||||
|
|
||||||
eventCode, err := eventcodes.ParseCodeButton(targetConfig.Button)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewRuleTargetButton(
|
|
||||||
targetConfig.Device,
|
|
||||||
device,
|
|
||||||
eventCode,
|
|
||||||
targetConfig.Inverted,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeRuleTargetAxis(targetConfig configparser.RuleTargetConfigAxis, devs map[string]Device) (*RuleTargetAxis, error) {
|
|
||||||
device, ok := devs[targetConfig.Device]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
|
||||||
}
|
|
||||||
|
|
||||||
if targetConfig.DeadzoneEnd < targetConfig.DeadzoneStart {
|
|
||||||
return nil, errors.New("deadzone_end must be greater than deadzone_start")
|
|
||||||
}
|
|
||||||
|
|
||||||
eventCode, err := eventcodes.ParseCode(targetConfig.Axis, eventcodes.CodePrefixAxis)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
deadzoneStart, deadzoneEnd, err := calculateDeadzones(targetConfig, device, eventCode)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewRuleTargetAxis(
|
|
||||||
targetConfig.Device,
|
|
||||||
device,
|
|
||||||
eventCode,
|
|
||||||
targetConfig.Inverted,
|
|
||||||
deadzoneStart,
|
|
||||||
deadzoneEnd,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeRuleTargetRelaxis(targetConfig configparser.RuleTargetConfigRelaxis, devs map[string]Device) (*RuleTargetRelaxis, error) {
|
|
||||||
device, ok := devs[targetConfig.Device]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
|
||||||
}
|
|
||||||
|
|
||||||
eventCode, err := eventcodes.ParseCode(targetConfig.Axis, eventcodes.CodePrefixRelaxis)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewRuleTargetRelaxis(
|
|
||||||
targetConfig.Device,
|
|
||||||
device,
|
|
||||||
eventCode,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeRuleTargetModeSelect(targetConfig configparser.RuleTargetConfigModeSelect, allModes []string) (*RuleTargetModeSelect, error) {
|
|
||||||
if ok := validateModes(targetConfig.Modes, allModes); !ok {
|
|
||||||
return nil, errors.New("undefined mode in mode select list")
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewRuleTargetModeSelect(targetConfig.Modes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculateDeadzones produces the deadzone start and end values in absolute terms
|
|
||||||
func calculateDeadzones(targetConfig configparser.RuleTargetConfigAxis, device Device, axis evdev.EvCode) (int32, int32, error) {
|
|
||||||
|
|
||||||
var deadzoneStart, deadzoneEnd int32
|
|
||||||
deadzoneStart = 0
|
|
||||||
deadzoneEnd = 0
|
|
||||||
|
|
||||||
if targetConfig.DeadzoneStart != 0 || targetConfig.DeadzoneEnd != 0 {
|
|
||||||
return targetConfig.DeadzoneStart, targetConfig.DeadzoneEnd, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var min, max int32
|
|
||||||
absInfoMap, err := device.AbsInfos()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
min = AxisValueMin
|
|
||||||
max = AxisValueMax
|
|
||||||
} else {
|
|
||||||
absInfo := absInfoMap[axis]
|
|
||||||
min = absInfo.Minimum
|
|
||||||
max = absInfo.Maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
if targetConfig.DeadzoneCenter < min || targetConfig.DeadzoneCenter > max {
|
|
||||||
return 0, 0, fmt.Errorf("deadzone_center '%d' is out of bounds", targetConfig.DeadzoneCenter)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case targetConfig.DeadzoneSize != 0:
|
|
||||||
deadzoneStart = targetConfig.DeadzoneCenter - targetConfig.DeadzoneSize/2
|
|
||||||
deadzoneEnd = targetConfig.DeadzoneCenter + targetConfig.DeadzoneSize/2
|
|
||||||
case targetConfig.DeadzoneSizePercent != 0:
|
|
||||||
deadzoneSize := (max - min) / targetConfig.DeadzoneSizePercent
|
|
||||||
deadzoneStart = targetConfig.DeadzoneCenter - deadzoneSize/2
|
|
||||||
deadzoneEnd = targetConfig.DeadzoneCenter + deadzoneSize/2
|
|
||||||
}
|
|
||||||
|
|
||||||
deadzoneStart, deadzoneEnd = clampAndShift(deadzoneStart, deadzoneEnd, min, max)
|
|
||||||
return deadzoneStart, deadzoneEnd, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func clampAndShift(start, end, min, max int32) (int32, int32) {
|
|
||||||
if start < min {
|
|
||||||
end += min - start
|
|
||||||
start = min
|
|
||||||
}
|
|
||||||
if end > max {
|
|
||||||
start -= end - max
|
|
||||||
end = max
|
|
||||||
}
|
|
||||||
|
|
||||||
return start, end
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateModes checks the provided modes against a larger subset of modes (usually all defined ones)
|
|
||||||
// and returns false if any of the modes are not defined.
|
|
||||||
func validateModes(modes []string, allModes []string) bool {
|
|
||||||
if len(modes) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, mode := range modes {
|
|
||||||
if !slices.Contains(allModes, mode) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
|
@ -53,41 +53,41 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetButton() {
|
||||||
|
|
||||||
t.Run("Standard keycode", func() {
|
t.Run("Standard keycode", func() {
|
||||||
config.Button = "BTN_TRIGGER"
|
config.Button = "BTN_TRIGGER"
|
||||||
rule, err := makeRuleTargetButton(config, t.devs)
|
rule, err := NewRuleTargetButtonFromConfig(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.BTN_TRIGGER, rule.Button)
|
t.EqualValues(evdev.BTN_TRIGGER, rule.Button)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Hex code", func() {
|
t.Run("Hex code", func() {
|
||||||
config.Button = "0x2fd"
|
config.Button = "0x2fd"
|
||||||
rule, err := makeRuleTargetButton(config, t.devs)
|
rule, err := NewRuleTargetButtonFromConfig(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.EvCode(0x2fd), rule.Button)
|
t.EqualValues(evdev.EvCode(0x2fd), rule.Button)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Index", func() {
|
t.Run("Index", func() {
|
||||||
config.Button = "3"
|
config.Button = "3"
|
||||||
rule, err := makeRuleTargetButton(config, t.devs)
|
rule, err := NewRuleTargetButtonFromConfig(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.BTN_TOP, rule.Button)
|
t.EqualValues(evdev.BTN_TOP, rule.Button)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Index too high", func() {
|
t.Run("Index too high", func() {
|
||||||
config.Button = "74"
|
config.Button = "74"
|
||||||
_, err := makeRuleTargetButton(config, t.devs)
|
_, err := NewRuleTargetButtonFromConfig(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Un-prefixed keycode", func() {
|
t.Run("Un-prefixed keycode", func() {
|
||||||
config.Button = "pinkie"
|
config.Button = "pinkie"
|
||||||
rule, err := makeRuleTargetButton(config, t.devs)
|
rule, err := NewRuleTargetButtonFromConfig(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.BTN_PINKIE, rule.Button)
|
t.EqualValues(evdev.BTN_PINKIE, rule.Button)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Invalid keycode", func() {
|
t.Run("Invalid keycode", func() {
|
||||||
config.Button = "foo"
|
config.Button = "foo"
|
||||||
_, err := makeRuleTargetButton(config, t.devs)
|
_, err := NewRuleTargetButtonFromConfig(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() {
|
||||||
t.Run(fmt.Sprintf("KeyCode %s", tc.input), func() {
|
t.Run(fmt.Sprintf("KeyCode %s", tc.input), func() {
|
||||||
config := configparser.RuleTargetConfigAxis{Device: "test"}
|
config := configparser.RuleTargetConfigAxis{Device: "test"}
|
||||||
config.Axis = tc.input
|
config.Axis = tc.input
|
||||||
rule, err := makeRuleTargetAxis(config, t.devs)
|
rule, err := NewRuleTargetAxisFromConfig(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(tc.output, rule.Axis)
|
t.EqualValues(tc.output, rule.Axis)
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() {
|
||||||
t.Run("Invalid code", func() {
|
t.Run("Invalid code", func() {
|
||||||
config := configparser.RuleTargetConfigAxis{Device: "test"}
|
config := configparser.RuleTargetConfigAxis{Device: "test"}
|
||||||
config.Axis = "foo"
|
config.Axis = "foo"
|
||||||
_, err := makeRuleTargetAxis(config, t.devs)
|
_, err := NewRuleTargetAxisFromConfig(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() {
|
||||||
config.Axis = "x"
|
config.Axis = "x"
|
||||||
config.DeadzoneEnd = 100
|
config.DeadzoneEnd = 100
|
||||||
config.DeadzoneStart = 1000
|
config.DeadzoneStart = 1000
|
||||||
_, err := makeRuleTargetAxis(config, t.devs)
|
_, err := NewRuleTargetAxisFromConfig(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() {
|
||||||
DeadzoneCenter: tc.inCenter,
|
DeadzoneCenter: tc.inCenter,
|
||||||
DeadzoneSize: tc.inSize,
|
DeadzoneSize: tc.inSize,
|
||||||
}
|
}
|
||||||
rule, err := makeRuleTargetAxis(config, t.devs)
|
rule, err := NewRuleTargetAxisFromConfig(config, t.devs)
|
||||||
|
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.Equal(tc.outStart, rule.DeadzoneStart)
|
t.Equal(tc.outStart, rule.DeadzoneStart)
|
||||||
|
@ -163,7 +163,7 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() {
|
||||||
DeadzoneCenter: 20000,
|
DeadzoneCenter: 20000,
|
||||||
DeadzoneSize: 500,
|
DeadzoneSize: 500,
|
||||||
}
|
}
|
||||||
_, err := makeRuleTargetAxis(config, t.devs)
|
_, err := NewRuleTargetAxisFromConfig(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() {
|
||||||
DeadzoneCenter: tc.inCenter,
|
DeadzoneCenter: tc.inCenter,
|
||||||
DeadzoneSizePercent: tc.inSizePercent,
|
DeadzoneSizePercent: tc.inSizePercent,
|
||||||
}
|
}
|
||||||
rule, err := makeRuleTargetAxis(config, t.devs)
|
rule, err := NewRuleTargetAxisFromConfig(config, t.devs)
|
||||||
|
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.Equal(tc.outStart, rule.DeadzoneStart)
|
t.Equal(tc.outStart, rule.DeadzoneStart)
|
||||||
|
@ -201,7 +201,7 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() {
|
||||||
DeadzoneCenter: 20000,
|
DeadzoneCenter: 20000,
|
||||||
DeadzoneSizePercent: 10,
|
DeadzoneSizePercent: 10,
|
||||||
}
|
}
|
||||||
_, err := makeRuleTargetAxis(config, t.devs)
|
_, err := NewRuleTargetAxisFromConfig(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -211,34 +211,34 @@ func (t *MakeRuleTargetsTests) TestMakeRuleTargetRelaxis() {
|
||||||
|
|
||||||
t.Run("Standard keycode", func() {
|
t.Run("Standard keycode", func() {
|
||||||
config.Axis = "REL_WHEEL"
|
config.Axis = "REL_WHEEL"
|
||||||
rule, err := makeRuleTargetRelaxis(config, t.devs)
|
rule, err := NewRuleTargetRelaxisFromConfig(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.REL_WHEEL, rule.Axis)
|
t.EqualValues(evdev.REL_WHEEL, rule.Axis)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Hex keycode", func() {
|
t.Run("Hex keycode", func() {
|
||||||
config.Axis = "0x00"
|
config.Axis = "0x00"
|
||||||
rule, err := makeRuleTargetRelaxis(config, t.devs)
|
rule, err := NewRuleTargetRelaxisFromConfig(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.REL_X, rule.Axis)
|
t.EqualValues(evdev.REL_X, rule.Axis)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Un-prefixed keycode", func() {
|
t.Run("Un-prefixed keycode", func() {
|
||||||
config.Axis = "wheel"
|
config.Axis = "wheel"
|
||||||
rule, err := makeRuleTargetRelaxis(config, t.devs)
|
rule, err := NewRuleTargetRelaxisFromConfig(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.REL_WHEEL, rule.Axis)
|
t.EqualValues(evdev.REL_WHEEL, rule.Axis)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Invalid keycode", func() {
|
t.Run("Invalid keycode", func() {
|
||||||
config.Axis = "foo"
|
config.Axis = "foo"
|
||||||
_, err := makeRuleTargetRelaxis(config, t.devs)
|
_, err := NewRuleTargetRelaxisFromConfig(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Incorrect axis type", func() {
|
t.Run("Incorrect axis type", func() {
|
||||||
config.Axis = "ABS_X"
|
config.Axis = "ABS_X"
|
||||||
_, err := makeRuleTargetRelaxis(config, t.devs)
|
_, err := NewRuleTargetRelaxisFromConfig(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package mappingrules
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.annabunches.net/annabunches/joyful/internal/configparser"
|
"git.annabunches.net/annabunches/joyful/internal/configparser"
|
||||||
|
@ -60,3 +61,19 @@ func NewRule(config configparser.RuleConfig, pDevs map[string]Device, vDevs map[
|
||||||
|
|
||||||
return newRule, nil
|
return newRule, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateModes checks the provided modes against a larger subset of modes (usually all defined ones)
|
||||||
|
// and returns false if any of the modes are not defined.
|
||||||
|
func validateModes(modes []string, allModes []string) bool {
|
||||||
|
if len(modes) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mode := range modes {
|
||||||
|
if !slices.Contains(allModes, mode) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -17,12 +17,12 @@ func NewMappingRuleAxis(ruleConfig configparser.RuleConfigAxis,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base MappingRuleBase) (*MappingRuleAxis, error) {
|
base MappingRuleBase) (*MappingRuleAxis, error) {
|
||||||
|
|
||||||
input, err := makeRuleTargetAxis(ruleConfig.Input, pDevs)
|
input, err := NewRuleTargetAxisFromConfig(ruleConfig.Input, pDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := makeRuleTargetAxis(ruleConfig.Output, vDevs)
|
output, err := NewRuleTargetAxisFromConfig(ruleConfig.Output, vDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,17 +18,17 @@ func NewMappingRuleAxisCombined(ruleConfig configparser.RuleConfigAxisCombined,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base MappingRuleBase) (*MappingRuleAxisCombined, error) {
|
base MappingRuleBase) (*MappingRuleAxisCombined, error) {
|
||||||
|
|
||||||
inputLower, err := makeRuleTargetAxis(ruleConfig.InputLower, pDevs)
|
inputLower, err := NewRuleTargetAxisFromConfig(ruleConfig.InputLower, pDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
inputUpper, err := makeRuleTargetAxis(ruleConfig.InputUpper, pDevs)
|
inputUpper, err := NewRuleTargetAxisFromConfig(ruleConfig.InputUpper, pDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := makeRuleTargetAxis(ruleConfig.Output, vDevs)
|
output, err := NewRuleTargetAxisFromConfig(ruleConfig.Output, vDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ func (t *MappingRuleAxisCombinedTests) TearDownSubTest() {
|
||||||
t.inputDevice.Reset()
|
t.inputDevice.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this test sucks
|
||||||
func (t *MappingRuleAxisCombinedTests) TestNewMappingRuleAxisCombined() {
|
func (t *MappingRuleAxisCombinedTests) TestNewMappingRuleAxisCombined() {
|
||||||
t.inputDevice.Stub("AbsInfos").Return(map[evdev.EvCode]evdev.AbsInfo{
|
t.inputDevice.Stub("AbsInfos").Return(map[evdev.EvCode]evdev.AbsInfo{
|
||||||
evdev.ABS_X: {Minimum: 0, Maximum: 10000},
|
evdev.ABS_X: {Minimum: 0, Maximum: 10000},
|
||||||
|
|
|
@ -29,12 +29,12 @@ func NewMappingRuleAxisToButton(ruleConfig configparser.RuleConfigAxisToButton,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base MappingRuleBase) (*MappingRuleAxisToButton, error) {
|
base MappingRuleBase) (*MappingRuleAxisToButton, error) {
|
||||||
|
|
||||||
input, err := makeRuleTargetAxis(ruleConfig.Input, pDevs)
|
input, err := NewRuleTargetAxisFromConfig(ruleConfig.Input, pDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := makeRuleTargetButton(ruleConfig.Output, vDevs)
|
output, err := NewRuleTargetButtonFromConfig(ruleConfig.Output, vDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,12 @@ func NewMappingRuleAxisToRelaxis(ruleConfig configparser.RuleConfigAxisToRelaxis
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base MappingRuleBase) (*MappingRuleAxisToRelaxis, error) {
|
base MappingRuleBase) (*MappingRuleAxisToRelaxis, error) {
|
||||||
|
|
||||||
input, err := makeRuleTargetAxis(ruleConfig.Input, pDevs)
|
input, err := NewRuleTargetAxisFromConfig(ruleConfig.Input, pDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := makeRuleTargetRelaxis(ruleConfig.Output, vDevs)
|
output, err := NewRuleTargetRelaxisFromConfig(ruleConfig.Output, vDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,12 @@ func NewMappingRuleButton(ruleConfig configparser.RuleConfigButton,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base MappingRuleBase) (*MappingRuleButton, error) {
|
base MappingRuleBase) (*MappingRuleButton, error) {
|
||||||
|
|
||||||
input, err := makeRuleTargetButton(ruleConfig.Input, pDevs)
|
input, err := NewRuleTargetButtonFromConfig(ruleConfig.Input, pDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := makeRuleTargetButton(ruleConfig.Output, vDevs)
|
output, err := NewRuleTargetButtonFromConfig(ruleConfig.Output, vDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,14 @@ func NewMappingRuleButtonCombo(ruleConfig configparser.RuleConfigButtonCombo,
|
||||||
|
|
||||||
inputs := make([]*RuleTargetButton, 0)
|
inputs := make([]*RuleTargetButton, 0)
|
||||||
for _, inputConfig := range ruleConfig.Inputs {
|
for _, inputConfig := range ruleConfig.Inputs {
|
||||||
input, err := makeRuleTargetButton(inputConfig, pDevs)
|
input, err := NewRuleTargetButtonFromConfig(inputConfig, pDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
inputs = append(inputs, input)
|
inputs = append(inputs, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := makeRuleTargetButton(ruleConfig.Output, vDevs)
|
output, err := NewRuleTargetButtonFromConfig(ruleConfig.Output, vDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,12 @@ func NewMappingRuleButtonLatched(ruleConfig configparser.RuleConfigButtonLatched
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base MappingRuleBase) (*MappingRuleButtonLatched, error) {
|
base MappingRuleBase) (*MappingRuleButtonLatched, error) {
|
||||||
|
|
||||||
input, err := makeRuleTargetButton(ruleConfig.Input, pDevs)
|
input, err := NewRuleTargetButtonFromConfig(ruleConfig.Input, pDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := makeRuleTargetButton(ruleConfig.Output, vDevs)
|
output, err := NewRuleTargetButtonFromConfig(ruleConfig.Output, vDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,12 @@ func NewMappingRuleModeSelect(ruleConfig configparser.RuleConfigModeSelect,
|
||||||
modes []string,
|
modes []string,
|
||||||
base MappingRuleBase) (*MappingRuleModeSelect, error) {
|
base MappingRuleBase) (*MappingRuleModeSelect, error) {
|
||||||
|
|
||||||
input, err := makeRuleTargetButton(ruleConfig.Input, pDevs)
|
input, err := NewRuleTargetButtonFromConfig(ruleConfig.Input, pDevs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := makeRuleTargetModeSelect(ruleConfig.Output, modes)
|
output, err := NewRuleTargetModeSelectFromConfig(ruleConfig.Output, modes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,3 +28,16 @@ func Clamp[T Numeric](value, min, max T) T {
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clampAndShift(start, end, min, max int32) (int32, int32) {
|
||||||
|
if start < min {
|
||||||
|
end += min - start
|
||||||
|
start = min
|
||||||
|
}
|
||||||
|
if end > max {
|
||||||
|
start -= end - max
|
||||||
|
end = max
|
||||||
|
}
|
||||||
|
|
||||||
|
return start, end
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"git.annabunches.net/annabunches/joyful/internal/configparser"
|
||||||
|
"git.annabunches.net/annabunches/joyful/internal/eventcodes"
|
||||||
"github.com/holoplot/go-evdev"
|
"github.com/holoplot/go-evdev"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,6 +22,77 @@ type RuleTargetAxis struct {
|
||||||
deadzoneSize int32
|
deadzoneSize int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewRuleTargetAxisFromConfig(targetConfig configparser.RuleTargetConfigAxis, devs map[string]Device) (*RuleTargetAxis, error) {
|
||||||
|
device, ok := devs[targetConfig.Device]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetConfig.DeadzoneEnd < targetConfig.DeadzoneStart {
|
||||||
|
return nil, errors.New("deadzone_end must be greater than deadzone_start")
|
||||||
|
}
|
||||||
|
|
||||||
|
eventCode, err := eventcodes.ParseCode(targetConfig.Axis, eventcodes.CodePrefixAxis)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
deadzoneStart, deadzoneEnd, err := calculateDeadzones(targetConfig, device, eventCode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewRuleTargetAxis(
|
||||||
|
targetConfig.Device,
|
||||||
|
device,
|
||||||
|
eventCode,
|
||||||
|
targetConfig.Inverted,
|
||||||
|
deadzoneStart,
|
||||||
|
deadzoneEnd,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateDeadzones produces the deadzone start and end values in absolute terms
|
||||||
|
func calculateDeadzones(targetConfig configparser.RuleTargetConfigAxis, device Device, axis evdev.EvCode) (int32, int32, error) {
|
||||||
|
|
||||||
|
var deadzoneStart, deadzoneEnd int32
|
||||||
|
deadzoneStart = 0
|
||||||
|
deadzoneEnd = 0
|
||||||
|
|
||||||
|
if targetConfig.DeadzoneStart != 0 || targetConfig.DeadzoneEnd != 0 {
|
||||||
|
return targetConfig.DeadzoneStart, targetConfig.DeadzoneEnd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var min, max int32
|
||||||
|
absInfoMap, err := device.AbsInfos()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
min = AxisValueMin
|
||||||
|
max = AxisValueMax
|
||||||
|
} else {
|
||||||
|
absInfo := absInfoMap[axis]
|
||||||
|
min = absInfo.Minimum
|
||||||
|
max = absInfo.Maximum
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetConfig.DeadzoneCenter < min || targetConfig.DeadzoneCenter > max {
|
||||||
|
return 0, 0, fmt.Errorf("deadzone_center '%d' is out of bounds", targetConfig.DeadzoneCenter)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case targetConfig.DeadzoneSize != 0:
|
||||||
|
deadzoneStart = targetConfig.DeadzoneCenter - targetConfig.DeadzoneSize/2
|
||||||
|
deadzoneEnd = targetConfig.DeadzoneCenter + targetConfig.DeadzoneSize/2
|
||||||
|
case targetConfig.DeadzoneSizePercent != 0:
|
||||||
|
deadzoneSize := (max - min) / targetConfig.DeadzoneSizePercent
|
||||||
|
deadzoneStart = targetConfig.DeadzoneCenter - deadzoneSize/2
|
||||||
|
deadzoneEnd = targetConfig.DeadzoneCenter + deadzoneSize/2
|
||||||
|
}
|
||||||
|
|
||||||
|
deadzoneStart, deadzoneEnd = clampAndShift(deadzoneStart, deadzoneEnd, min, max)
|
||||||
|
return deadzoneStart, deadzoneEnd, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewRuleTargetAxis(device_name string,
|
func NewRuleTargetAxis(device_name string,
|
||||||
device Device,
|
device Device,
|
||||||
axis evdev.EvCode,
|
axis evdev.EvCode,
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
package mappingrules
|
package mappingrules
|
||||||
|
|
||||||
import "github.com/holoplot/go-evdev"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.annabunches.net/annabunches/joyful/internal/configparser"
|
||||||
|
"git.annabunches.net/annabunches/joyful/internal/eventcodes"
|
||||||
|
"github.com/holoplot/go-evdev"
|
||||||
|
)
|
||||||
|
|
||||||
type RuleTargetButton struct {
|
type RuleTargetButton struct {
|
||||||
DeviceName string
|
DeviceName string
|
||||||
|
@ -9,6 +15,25 @@ type RuleTargetButton struct {
|
||||||
Inverted bool
|
Inverted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewRuleTargetButtonFromConfig(targetConfig configparser.RuleTargetConfigButton, devs map[string]Device) (*RuleTargetButton, error) {
|
||||||
|
device, ok := devs[targetConfig.Device]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
||||||
|
}
|
||||||
|
|
||||||
|
eventCode, err := eventcodes.ParseCodeButton(targetConfig.Button)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewRuleTargetButton(
|
||||||
|
targetConfig.Device,
|
||||||
|
device,
|
||||||
|
eventCode,
|
||||||
|
targetConfig.Inverted,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func NewRuleTargetButton(device_name string, device Device, code evdev.EvCode, inverted bool) (*RuleTargetButton, error) {
|
func NewRuleTargetButton(device_name string, device Device, code evdev.EvCode, inverted bool) (*RuleTargetButton, error) {
|
||||||
return &RuleTargetButton{
|
return &RuleTargetButton{
|
||||||
DeviceName: device_name,
|
DeviceName: device_name,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
"git.annabunches.net/annabunches/joyful/internal/configparser"
|
||||||
"git.annabunches.net/annabunches/joyful/internal/logger"
|
"git.annabunches.net/annabunches/joyful/internal/logger"
|
||||||
"github.com/holoplot/go-evdev"
|
"github.com/holoplot/go-evdev"
|
||||||
)
|
)
|
||||||
|
@ -12,6 +13,14 @@ type RuleTargetModeSelect struct {
|
||||||
Modes []string
|
Modes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewRuleTargetModeSelectFromConfig(targetConfig configparser.RuleTargetConfigModeSelect, allModes []string) (*RuleTargetModeSelect, error) {
|
||||||
|
if ok := validateModes(targetConfig.Modes, allModes); !ok {
|
||||||
|
return nil, errors.New("undefined mode in mode select list")
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewRuleTargetModeSelect(targetConfig.Modes)
|
||||||
|
}
|
||||||
|
|
||||||
func NewRuleTargetModeSelect(modes []string) (*RuleTargetModeSelect, error) {
|
func NewRuleTargetModeSelect(modes []string) (*RuleTargetModeSelect, error) {
|
||||||
if len(modes) == 0 {
|
if len(modes) == 0 {
|
||||||
return nil, errors.New("cannot create RuleTargetModeSelect: mode list is empty")
|
return nil, errors.New("cannot create RuleTargetModeSelect: mode list is empty")
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package mappingrules
|
package mappingrules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.annabunches.net/annabunches/joyful/internal/configparser"
|
||||||
|
"git.annabunches.net/annabunches/joyful/internal/eventcodes"
|
||||||
"github.com/holoplot/go-evdev"
|
"github.com/holoplot/go-evdev"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,12 +14,30 @@ type RuleTargetRelaxis struct {
|
||||||
Axis evdev.EvCode
|
Axis evdev.EvCode
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRuleTargetRelaxis(device_name string,
|
func NewRuleTargetRelaxisFromConfig(targetConfig configparser.RuleTargetConfigRelaxis, devs map[string]Device) (*RuleTargetRelaxis, error) {
|
||||||
|
device, ok := devs[targetConfig.Device]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
||||||
|
}
|
||||||
|
|
||||||
|
eventCode, err := eventcodes.ParseCode(targetConfig.Axis, eventcodes.CodePrefixRelaxis)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewRuleTargetRelaxis(
|
||||||
|
targetConfig.Device,
|
||||||
|
device,
|
||||||
|
eventCode,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRuleTargetRelaxis(deviceName string,
|
||||||
device Device,
|
device Device,
|
||||||
axis evdev.EvCode) (*RuleTargetRelaxis, error) {
|
axis evdev.EvCode) (*RuleTargetRelaxis, error) {
|
||||||
|
|
||||||
return &RuleTargetRelaxis{
|
return &RuleTargetRelaxis{
|
||||||
DeviceName: device_name,
|
DeviceName: deviceName,
|
||||||
Device: device,
|
Device: device,
|
||||||
Axis: axis,
|
Axis: axis,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue