Add support for multiple types of button/axis specification.

This commit is contained in:
Anna Rose Wiggins 2025-07-15 22:17:53 -04:00
parent e1940006d8
commit 23422fac3c
3 changed files with 115 additions and 14 deletions

View file

@ -3,6 +3,8 @@ package config
import (
"errors"
"fmt"
"strconv"
"strings"
"git.annabunches.net/annabunches/joyful/internal/mappingrules"
"github.com/holoplot/go-evdev"
@ -14,9 +16,39 @@ func makeRuleTargetButton(targetConfig RuleTargetConfig, devs map[string]*evdev.
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
}
eventCode, ok := evdev.KEYFromString[targetConfig.Button]
if !ok {
return nil, fmt.Errorf("invalid button code '%s'", targetConfig.Button)
var eventCode evdev.EvCode
buttonConfig := strings.ToUpper(targetConfig.Button)
switch {
case strings.HasPrefix(buttonConfig, "BTN_"):
eventCode, ok = evdev.KEYFromString[buttonConfig]
if !ok {
return nil, fmt.Errorf("invalid button specification '%s'", buttonConfig)
}
case strings.HasPrefix(buttonConfig, "0X"):
codeInt, err := strconv.ParseUint(buttonConfig[2:], 16, 32)
if err != nil {
return nil, err
}
eventCode = evdev.EvCode(codeInt)
case !hasError(strconv.Atoi(buttonConfig)):
index, err := strconv.Atoi(buttonConfig)
if err != nil {
return nil, err
}
if index >= len(ButtonFromIndex) {
return nil, fmt.Errorf("button index '%d' out of bounds", index)
}
eventCode = ButtonFromIndex[index]
default:
eventCode, ok = evdev.KEYFromString["BTN_"+buttonConfig]
if !ok {
return nil, fmt.Errorf("invalid button specification '%s'", buttonConfig)
}
}
return mappingrules.NewRuleTargetButton(
@ -33,9 +65,27 @@ func makeRuleTargetAxis(targetConfig RuleTargetConfig, devs map[string]*evdev.In
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
}
eventCode, ok := evdev.ABSFromString[targetConfig.Axis]
if !ok {
return nil, fmt.Errorf("invalid button code '%s'", targetConfig.Button)
var eventCode evdev.EvCode
axisConfig := strings.ToUpper(targetConfig.Axis)
switch {
case strings.HasPrefix(axisConfig, "ABS_"):
eventCode, ok = evdev.ABSFromString[axisConfig]
if !ok {
return nil, fmt.Errorf("invalid axis code '%s'", axisConfig)
}
case strings.HasPrefix(axisConfig, "0X"):
codeInt, err := strconv.ParseUint(axisConfig[2:], 16, 32)
if err != nil {
return nil, err
}
eventCode = evdev.EvCode(codeInt)
default:
eventCode, ok = evdev.ABSFromString["ABS_"+axisConfig]
if !ok {
return nil, fmt.Errorf("invalid axis code '%s'", axisConfig)
}
}
return mappingrules.NewRuleTargetAxis(
@ -54,11 +104,28 @@ func makeRuleTargetRelaxis(targetConfig RuleTargetConfig, devs map[string]*evdev
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
}
eventCode, ok := evdev.RELFromString[targetConfig.Axis]
if !ok {
return nil, fmt.Errorf("invalid button code '%s'", targetConfig.Button)
}
var eventCode evdev.EvCode
axisConfig := strings.ToUpper(targetConfig.Axis)
switch {
case strings.HasPrefix(axisConfig, "REL_"):
eventCode, ok = evdev.RELFromString[axisConfig]
if !ok {
return nil, fmt.Errorf("invalid axis code '%s'", axisConfig)
}
case strings.HasPrefix(axisConfig, "0X"):
codeInt, err := strconv.ParseUint(axisConfig[2:], 16, 32)
if err != nil {
return nil, err
}
eventCode = evdev.EvCode(codeInt)
default:
eventCode, ok = evdev.ABSFromString["REL_"+axisConfig]
if !ok {
return nil, fmt.Errorf("invalid axis code '%s'", axisConfig)
}
}
return mappingrules.NewRuleTargetRelaxis(
targetConfig.Device,
device,
@ -74,3 +141,8 @@ func makeRuleTargetModeSelect(targetConfig RuleTargetConfig, allModes []string)
return mappingrules.NewRuleTargetModeSelect(targetConfig.Modes)
}
// hasError exists solely to switch on errors in case statements
func hasError(_ interface{}, err error) bool {
return err != nil
}

View file

@ -31,6 +31,10 @@ var (
evdev.BTN_BASE4,
evdev.BTN_BASE5,
evdev.BTN_BASE6,
evdev.EvCode(0x12c),
evdev.EvCode(0x12d),
evdev.EvCode(0x12e),
evdev.BTN_DEAD,
evdev.BTN_TRIGGER_HAPPY1,
evdev.BTN_TRIGGER_HAPPY2,
evdev.BTN_TRIGGER_HAPPY3,
@ -71,5 +75,23 @@ var (
evdev.BTN_TRIGGER_HAPPY38,
evdev.BTN_TRIGGER_HAPPY39,
evdev.BTN_TRIGGER_HAPPY40,
evdev.EvCode(0x2e8),
evdev.EvCode(0x2e9),
evdev.EvCode(0x2f0),
evdev.EvCode(0x2f1),
evdev.EvCode(0x2f2),
evdev.EvCode(0x2f3),
evdev.EvCode(0x2f4),
evdev.EvCode(0x2f5),
evdev.EvCode(0x2f6),
evdev.EvCode(0x2f7),
evdev.EvCode(0x2f8),
evdev.EvCode(0x2f9),
evdev.EvCode(0x2fa),
evdev.EvCode(0x2fb),
evdev.EvCode(0x2fc),
evdev.EvCode(0x2fd),
evdev.EvCode(0x2fe),
evdev.EvCode(0x2ff),
}
)