Support keyboard buttons and add presets. #14

Merged
anna merged 5 commits from keyboard-output into main 2025-08-04 19:55:56 +00:00
4 changed files with 123 additions and 88 deletions
Showing only changes of commit 32fa7d27e0 - Show all commits

View file

@ -8,13 +8,23 @@ import (
"github.com/holoplot/go-evdev" "github.com/holoplot/go-evdev"
) )
func parseCodeButton(code string) (evdev.EvCode, error) {
prefix := CodePrefixButton
if strings.HasPrefix(code, CodePrefixKey+"_") {
prefix = CodePrefixKey
}
return parseCode(code, prefix)
}
func parseCode(code, prefix string) (evdev.EvCode, error) { func parseCode(code, prefix string) (evdev.EvCode, error) {
code = strings.ToUpper(code) code = strings.ToUpper(code)
var codeLookup map[string]evdev.EvCode var codeLookup map[string]evdev.EvCode
switch prefix { switch prefix {
case CodePrefixButton: case CodePrefixButton, CodePrefixKey:
codeLookup = evdev.KEYFromString codeLookup = evdev.KEYFromString
case CodePrefixAxis: case CodePrefixAxis:
codeLookup = evdev.ABSFromString codeLookup = evdev.ABSFromString

View file

@ -16,7 +16,7 @@ func TestRunnerEventCodeParserTests(t *testing.T) {
suite.Run(t, new(EventCodeParserTests)) suite.Run(t, new(EventCodeParserTests))
} }
func parseCodeTestCase(t *EventCodeParserTests, in string, out int, prefix string) { func parseCodeTestCase(t *EventCodeParserTests, in string, out evdev.EvCode, prefix string) {
t.Run(fmt.Sprintf("%s: %s", prefix, in), func() { t.Run(fmt.Sprintf("%s: %s", prefix, in), func() {
code, err := parseCode(in, prefix) code, err := parseCode(in, prefix)
t.Nil(err) t.Nil(err)
@ -24,10 +24,33 @@ func parseCodeTestCase(t *EventCodeParserTests, in string, out int, prefix strin
}) })
} }
func (t *EventCodeParserTests) TestParseCodeABS() { func (t *EventCodeParserTests) TestParseCodeButton() {
testCases := []struct { testCases := []struct {
in string in string
out int out evdev.EvCode
}{
{"BTN_A", evdev.BTN_A},
{"A", evdev.BTN_A},
{"BTN_TRIGGER_HAPPY", evdev.BTN_TRIGGER_HAPPY},
{"KEY_A", evdev.KEY_A},
{"KEY_ESC", evdev.KEY_ESC},
}
for _, testCase := range testCases {
t.Run(testCase.in, func() {
code, err := parseCodeButton(testCase.in)
t.Nil(err)
t.EqualValues(code, testCase.out)
})
}
}
func (t *EventCodeParserTests) TestParseCode() {
t.Run("ABS", func() {
testCases := []struct {
in string
out evdev.EvCode
}{ }{
{"ABS_X", evdev.ABS_X}, {"ABS_X", evdev.ABS_X},
{"ABS_Y", evdev.ABS_Y}, {"ABS_Y", evdev.ABS_Y},
@ -50,12 +73,12 @@ func (t *EventCodeParserTests) TestParseCodeABS() {
for _, testCase := range testCases { for _, testCase := range testCases {
parseCodeTestCase(t, testCase.in, testCase.out, "ABS") parseCodeTestCase(t, testCase.in, testCase.out, "ABS")
} }
} })
func (t *EventCodeParserTests) TestParseCodeREL() { t.Run("REL", func() {
testCases := []struct { testCases := []struct {
in string in string
out int out evdev.EvCode
}{ }{
{"REL_X", evdev.REL_X}, {"REL_X", evdev.REL_X},
{"REL_Y", evdev.REL_Y}, {"REL_Y", evdev.REL_Y},
@ -77,12 +100,12 @@ func (t *EventCodeParserTests) TestParseCodeREL() {
for _, testCase := range testCases { for _, testCase := range testCases {
parseCodeTestCase(t, testCase.in, testCase.out, "REL") parseCodeTestCase(t, testCase.in, testCase.out, "REL")
} }
} })
func (t *EventCodeParserTests) TestParseCodeBTN() { t.Run("BTN", func() {
testCases := []struct { testCases := []struct {
in string in string
out int out evdev.EvCode
}{ }{
{"BTN_TRIGGER", evdev.BTN_TRIGGER}, {"BTN_TRIGGER", evdev.BTN_TRIGGER},
{"trigger", evdev.BTN_TRIGGER}, {"trigger", evdev.BTN_TRIGGER},
@ -93,9 +116,9 @@ func (t *EventCodeParserTests) TestParseCodeBTN() {
for _, testCase := range testCases { for _, testCase := range testCases {
parseCodeTestCase(t, testCase.in, testCase.out, "BTN") parseCodeTestCase(t, testCase.in, testCase.out, "BTN")
} }
} })
func (t *EventCodeParserTests) TestParseCodeInvalid() { t.Run("Invalid", func() {
testCases := []struct { testCases := []struct {
in string in string
prefix string prefix string
@ -115,4 +138,5 @@ func (t *EventCodeParserTests) TestParseCodeInvalid() {
t.NotNil(err) t.NotNil(err)
}) })
} }
})
} }

View file

@ -14,7 +14,7 @@ func makeRuleTargetButton(targetConfig RuleTargetConfig, devs map[string]Device)
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device) return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
} }
eventCode, err := parseCode(targetConfig.Button, "BTN") eventCode, err := parseCodeButton(targetConfig.Button)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -37,7 +37,7 @@ func makeRuleTargetAxis(targetConfig RuleTargetConfig, devs map[string]Device) (
return nil, errors.New("deadzone_end must be greater than deadzone_start") return nil, errors.New("deadzone_end must be greater than deadzone_start")
} }
eventCode, err := parseCode(targetConfig.Axis, "ABS") eventCode, err := parseCode(targetConfig.Axis, CodePrefixAxis)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -63,7 +63,7 @@ func makeRuleTargetRelaxis(targetConfig RuleTargetConfig, devs map[string]Device
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device) return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
} }
eventCode, err := parseCode(targetConfig.Axis, "REL") eventCode, err := parseCode(targetConfig.Axis, CodePrefixRelaxis)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -18,6 +18,7 @@ const (
RuleTypeAxisToRelaxis = "axis-to-relaxis" RuleTypeAxisToRelaxis = "axis-to-relaxis"
CodePrefixButton = "BTN" CodePrefixButton = "BTN"
CodePrefixKey = "KEY"
CodePrefixAxis = "ABS" CodePrefixAxis = "ABS"
CodePrefixRelaxis = "REL" CodePrefixRelaxis = "REL"