156 lines
4.1 KiB
Go
156 lines
4.1 KiB
Go
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
|
|
}
|