Start rulemapping refactor to be more explicit about typing intentions.
This commit is contained in:
parent
08fc828b46
commit
a0949e719f
10 changed files with 128 additions and 100 deletions
|
@ -103,11 +103,11 @@ func main() {
|
|||
case evdev.EV_KEY, evdev.EV_ABS:
|
||||
// We have a matchable event type. Check all the events
|
||||
for _, rule := range rules {
|
||||
outputEvent := rule.MatchEvent(channelEvent.Device, channelEvent.Event, &mode)
|
||||
if outputEvent == nil {
|
||||
device, outputEvent := rule.MatchEvent(channelEvent.Device, channelEvent.Event, &mode)
|
||||
if device == nil || outputEvent == nil {
|
||||
continue
|
||||
}
|
||||
vBuffersByName[rule.OutputName()].AddEvent(outputEvent)
|
||||
vBuffersByDevice[device].AddEvent(outputEvent)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ func (parser *ConfigParser) BuildRules(pDevs map[string]*evdev.InputDevice, vDev
|
|||
var newRule mappingrules.MappingRule
|
||||
var err error
|
||||
|
||||
baseParams, err := setBaseRuleParameters(ruleConfig, vDevs, modes)
|
||||
baseParams, err := setBaseRuleParameters(ruleConfig, modes)
|
||||
if err != nil {
|
||||
logger.LogErrorf(err, "couldn't set output parameters, skipping rule '%s'", ruleConfig.Name)
|
||||
continue
|
||||
|
@ -31,11 +31,11 @@ func (parser *ConfigParser) BuildRules(pDevs map[string]*evdev.InputDevice, vDev
|
|||
|
||||
switch strings.ToLower(ruleConfig.Type) {
|
||||
case RuleTypeSimple:
|
||||
newRule, err = makeSimpleRule(ruleConfig, pDevs, baseParams)
|
||||
newRule, err = makeMappingRuleButton(ruleConfig, pDevs, vDevs, baseParams)
|
||||
case RuleTypeCombo:
|
||||
newRule, err = makeComboRule(ruleConfig, pDevs, baseParams)
|
||||
newRule, err = makeComboRule(ruleConfig, pDevs, vDevs, baseParams)
|
||||
case RuleTypeLatched:
|
||||
newRule, err = makeLatchedRule(ruleConfig, pDevs, baseParams)
|
||||
newRule, err = makeLatchedRule(ruleConfig, pDevs, vDevs, baseParams)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -49,7 +49,7 @@ func (parser *ConfigParser) BuildRules(pDevs map[string]*evdev.InputDevice, vDev
|
|||
return rules
|
||||
}
|
||||
|
||||
func setBaseRuleParameters(ruleConfig RuleConfig, vDevs map[string]*evdev.InputDevice, modes []string) (mappingrules.MappingRuleBase, error) {
|
||||
func setBaseRuleParameters(ruleConfig RuleConfig, modes []string) (mappingrules.MappingRuleBase, error) {
|
||||
// We perform this check here instead of in makeRuleTarget because only Output targets
|
||||
// can meaningfully have ModeSelect; this lets us avoid plumbing the modes in on every
|
||||
// makeRuleTarget call.
|
||||
|
@ -60,12 +60,7 @@ func setBaseRuleParameters(ruleConfig RuleConfig, vDevs map[string]*evdev.InputD
|
|||
}
|
||||
}
|
||||
|
||||
output, err := makeRuleTarget(ruleConfig.Output, vDevs)
|
||||
if err != nil {
|
||||
return mappingrules.MappingRuleBase{}, err
|
||||
}
|
||||
|
||||
err = validateModes(ruleConfig.Modes, modes)
|
||||
err := validateModes(ruleConfig.Modes, modes)
|
||||
if err != nil {
|
||||
return mappingrules.MappingRuleBase{}, err
|
||||
}
|
||||
|
@ -73,28 +68,41 @@ func setBaseRuleParameters(ruleConfig RuleConfig, vDevs map[string]*evdev.InputD
|
|||
ruleModes := ensureModes(ruleConfig.Modes)
|
||||
|
||||
return mappingrules.MappingRuleBase{
|
||||
Output: output,
|
||||
Modes: ruleModes,
|
||||
Name: ruleConfig.Name,
|
||||
Modes: ruleModes,
|
||||
Name: ruleConfig.Name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func makeSimpleRule(ruleConfig RuleConfig, pDevs map[string]*evdev.InputDevice, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleSimple, error) {
|
||||
func makeMappingRuleButton(ruleConfig RuleConfig,
|
||||
pDevs map[string]*evdev.InputDevice,
|
||||
vDevs map[string]*evdev.InputDevice,
|
||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButton, error) {
|
||||
|
||||
input, err := makeRuleTarget(ruleConfig.Input, pDevs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &mappingrules.MappingRuleSimple{
|
||||
output, err := makeRuleTarget(ruleConfig.Output, vDevs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &mappingrules.MappingRuleButton{
|
||||
MappingRuleBase: base,
|
||||
Input: input,
|
||||
Input: input.(*mappingrules.RuleTargetButton),
|
||||
Output: output.(*mappingrules.RuleTargetButton),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func makeComboRule(ruleConfig RuleConfig, pDevs map[string]*evdev.InputDevice, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleCombo, error) {
|
||||
inputs := make([]mappingrules.RuleTarget, 0)
|
||||
func makeComboRule(ruleConfig RuleConfig,
|
||||
pDevs map[string]*evdev.InputDevice,
|
||||
vDevs map[string]*evdev.InputDevice,
|
||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleCombo, error) {
|
||||
|
||||
inputs := make([]*mappingrules.RuleTargetButton, 0)
|
||||
for _, inputConfig := range ruleConfig.Inputs {
|
||||
input, err := makeRuleTarget(inputConfig, pDevs)
|
||||
input, err := makeRuleTargetButton(inputConfig, pDevs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -108,8 +116,12 @@ func makeComboRule(ruleConfig RuleConfig, pDevs map[string]*evdev.InputDevice, b
|
|||
}, nil
|
||||
}
|
||||
|
||||
func makeLatchedRule(ruleConfig RuleConfig, pDevs map[string]*evdev.InputDevice, base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleLatched, error) {
|
||||
input, err := makeRuleTarget(ruleConfig.Input, pDevs)
|
||||
func makeLatchedRule(ruleConfig RuleConfig,
|
||||
pDevs map[string]*evdev.InputDevice,
|
||||
vDevs map[string]*evdev.InputDevice,
|
||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleLatched, error) {
|
||||
|
||||
input, err := makeRuleTargetButton(ruleConfig.Input, pDevs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -121,7 +133,30 @@ func makeLatchedRule(ruleConfig RuleConfig, pDevs map[string]*evdev.InputDevice,
|
|||
}, nil
|
||||
}
|
||||
|
||||
// makeInputRuleTarget takes an Input declaration from the YAML and returns a fully formed RuleTarget.
|
||||
func makeRuleTargetButton(targetConfig RuleTargetConfig, devs map[string]*evdev.InputDevice) (*mappingrules.RuleTargetButton, error) {
|
||||
device, ok := devs[targetConfig.Device]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("couldn't build rule due to non-existent device '%s'", targetConfig.Device)
|
||||
}
|
||||
|
||||
_, eventCode, err := decodeRuleTargetValues(targetConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseParams := mappingrules.RuleTargetBase{
|
||||
DeviceName: targetConfig.Device,
|
||||
Device: device,
|
||||
Inverted: targetConfig.Inverted,
|
||||
Code: eventCode,
|
||||
}
|
||||
|
||||
return &mappingrules.RuleTargetButton{
|
||||
RuleTargetBase: baseParams,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// makeRuleTarget takes an Input declaration from the YAML and returns a fully formed RuleTarget.
|
||||
func makeRuleTarget(targetConfig RuleTargetConfig, devs map[string]*evdev.InputDevice) (mappingrules.RuleTarget, error) {
|
||||
if len(targetConfig.ModeSelect) > 0 {
|
||||
return &mappingrules.RuleTargetModeSelect{
|
||||
|
|
|
@ -3,8 +3,7 @@ package mappingrules
|
|||
import "github.com/holoplot/go-evdev"
|
||||
|
||||
type MappingRule interface {
|
||||
MatchEvent(*evdev.InputDevice, *evdev.InputEvent, *string) *evdev.InputEvent
|
||||
OutputName() string
|
||||
MatchEvent(*evdev.InputDevice, *evdev.InputEvent, *string) (*evdev.InputDevice, *evdev.InputEvent)
|
||||
}
|
||||
|
||||
// RuleTargets represent either a device input to match on, or an output to produce.
|
||||
|
@ -21,8 +20,4 @@ type RuleTarget interface {
|
|||
//
|
||||
// TODO: should we normalize inside this function to simplify the interface?
|
||||
CreateEvent(int32, *string) *evdev.InputEvent
|
||||
|
||||
GetCode() evdev.EvCode
|
||||
GetDeviceName() string
|
||||
GetDevice() *evdev.InputDevice
|
||||
}
|
||||
|
|
|
@ -3,13 +3,8 @@ package mappingrules
|
|||
import "slices"
|
||||
|
||||
type MappingRuleBase struct {
|
||||
Name string
|
||||
Output RuleTarget
|
||||
Modes []string
|
||||
}
|
||||
|
||||
func (rule *MappingRuleBase) OutputName() string {
|
||||
return rule.Output.GetDeviceName()
|
||||
Name string
|
||||
Modes []string
|
||||
}
|
||||
|
||||
func (rule *MappingRuleBase) modeCheck(mode *string) bool {
|
||||
|
|
23
internal/mappingrules/mapping_rule_button.go
Normal file
23
internal/mappingrules/mapping_rule_button.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package mappingrules
|
||||
|
||||
import "github.com/holoplot/go-evdev"
|
||||
|
||||
// A Simple Mapping Rule can map a button to a button or an axis to an axis.
|
||||
type MappingRuleButton struct {
|
||||
MappingRuleBase
|
||||
Input *RuleTargetButton
|
||||
Output *RuleTargetButton
|
||||
}
|
||||
|
||||
func (rule *MappingRuleButton) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) (*evdev.InputDevice, *evdev.InputEvent) {
|
||||
if !rule.MappingRuleBase.modeCheck(mode) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if device != rule.Input.GetDevice() ||
|
||||
event.Code != rule.Input.GetCode() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return rule.Output.Device, rule.Output.CreateEvent(rule.Input.NormalizeValue(event.Value), mode)
|
||||
}
|
|
@ -7,17 +7,17 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type SimpleMappingRuleTests struct {
|
||||
type MappingRuleButtonTests struct {
|
||||
suite.Suite
|
||||
inputDevice *evdev.InputDevice
|
||||
wrongInputDevice *evdev.InputDevice
|
||||
outputDevice *evdev.InputDevice
|
||||
mode *string
|
||||
sampleRule *MappingRuleSimple
|
||||
invertedRule *MappingRuleSimple
|
||||
sampleRule *MappingRuleButton
|
||||
invertedRule *MappingRuleButton
|
||||
}
|
||||
|
||||
func (t *SimpleMappingRuleTests) SetupTest() {
|
||||
func (t *MappingRuleButtonTests) SetupTest() {
|
||||
t.inputDevice = &evdev.InputDevice{}
|
||||
t.wrongInputDevice = &evdev.InputDevice{}
|
||||
t.outputDevice = &evdev.InputDevice{}
|
||||
|
@ -25,24 +25,24 @@ func (t *SimpleMappingRuleTests) SetupTest() {
|
|||
t.mode = &mode
|
||||
|
||||
// TODO: implement a constructor function...
|
||||
t.sampleRule = &MappingRuleSimple{
|
||||
t.sampleRule = &MappingRuleButton{
|
||||
MappingRuleBase: MappingRuleBase{
|
||||
Output: NewRuleTargetButton("", t.outputDevice, evdev.BTN_TRIGGER, false),
|
||||
Modes: []string{"*"},
|
||||
Modes: []string{"*"},
|
||||
},
|
||||
Input: NewRuleTargetButton("", t.inputDevice, evdev.BTN_TRIGGER, false),
|
||||
Input: NewRuleTargetButton("", t.inputDevice, evdev.BTN_TRIGGER, false),
|
||||
Output: NewRuleTargetButton("", t.outputDevice, evdev.BTN_TRIGGER, false),
|
||||
}
|
||||
|
||||
t.invertedRule = &MappingRuleSimple{
|
||||
t.invertedRule = &MappingRuleButton{
|
||||
MappingRuleBase: MappingRuleBase{
|
||||
Output: NewRuleTargetButton("", t.outputDevice, evdev.BTN_TRIGGER, false),
|
||||
Modes: []string{"*"},
|
||||
Modes: []string{"*"},
|
||||
},
|
||||
Input: NewRuleTargetButton("", t.inputDevice, evdev.BTN_TRIGGER, true),
|
||||
Output: NewRuleTargetButton("", t.outputDevice, evdev.BTN_TRIGGER, false),
|
||||
Input: NewRuleTargetButton("", t.inputDevice, evdev.BTN_TRIGGER, true),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *SimpleMappingRuleTests) TestMatchEvent() {
|
||||
func (t *MappingRuleButtonTests) TestMatchEvent() {
|
||||
// A matching input event should produce an output event
|
||||
correctOutput := &evdev.InputEvent{
|
||||
Type: evdev.EV_KEY,
|
||||
|
@ -50,25 +50,25 @@ func (t *SimpleMappingRuleTests) TestMatchEvent() {
|
|||
Value: 1,
|
||||
}
|
||||
|
||||
event := t.sampleRule.MatchEvent(
|
||||
_, event := t.sampleRule.MatchEvent(
|
||||
t.inputDevice,
|
||||
&evdev.InputEvent{Code: evdev.BTN_TRIGGER, Value: 1}, t.mode)
|
||||
t.EqualValues(correctOutput, event)
|
||||
|
||||
// An input event from the wrong device should produce a nil event
|
||||
event = t.sampleRule.MatchEvent(
|
||||
_, event = t.sampleRule.MatchEvent(
|
||||
t.wrongInputDevice,
|
||||
&evdev.InputEvent{Code: evdev.BTN_TRIGGER, Value: 1}, t.mode)
|
||||
t.Nil(event)
|
||||
|
||||
// An input event from the wrong button should produce a nil event
|
||||
event = t.sampleRule.MatchEvent(
|
||||
_, event = t.sampleRule.MatchEvent(
|
||||
t.inputDevice,
|
||||
&evdev.InputEvent{Code: evdev.BTN_TOP, Value: 1}, t.mode)
|
||||
t.Nil(event)
|
||||
}
|
||||
|
||||
func (t *SimpleMappingRuleTests) TestMatchEventInverted() {
|
||||
func (t *MappingRuleButtonTests) TestMatchEventInverted() {
|
||||
// A matching input event should produce an output event
|
||||
correctOutput := &evdev.InputEvent{
|
||||
Type: evdev.EV_KEY,
|
||||
|
@ -77,18 +77,18 @@ func (t *SimpleMappingRuleTests) TestMatchEventInverted() {
|
|||
|
||||
// Should get the opposite value out that we send in
|
||||
correctOutput.Value = 0
|
||||
event := t.invertedRule.MatchEvent(
|
||||
_, event := t.invertedRule.MatchEvent(
|
||||
t.inputDevice,
|
||||
&evdev.InputEvent{Code: evdev.BTN_TRIGGER, Value: 1}, t.mode)
|
||||
t.EqualValues(correctOutput, event)
|
||||
|
||||
correctOutput.Value = 1
|
||||
event = t.invertedRule.MatchEvent(
|
||||
_, event = t.invertedRule.MatchEvent(
|
||||
t.inputDevice,
|
||||
&evdev.InputEvent{Code: evdev.BTN_TRIGGER, Value: 0}, t.mode)
|
||||
t.EqualValues(correctOutput, event)
|
||||
}
|
||||
|
||||
func TestRunnerMatching(t *testing.T) {
|
||||
suite.Run(t, new(SimpleMappingRuleTests))
|
||||
suite.Run(t, new(MappingRuleButtonTests))
|
||||
}
|
|
@ -5,13 +5,14 @@ import "github.com/holoplot/go-evdev"
|
|||
// A Combo Mapping Rule can require multiple physical button presses for a single output button
|
||||
type MappingRuleCombo struct {
|
||||
MappingRuleBase
|
||||
Inputs []RuleTarget
|
||||
Inputs []*RuleTargetButton
|
||||
Output *RuleTargetButton
|
||||
State int
|
||||
}
|
||||
|
||||
func (rule *MappingRuleCombo) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) *evdev.InputEvent {
|
||||
func (rule *MappingRuleCombo) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) (*evdev.InputDevice, *evdev.InputEvent) {
|
||||
if !rule.MappingRuleBase.modeCheck(mode) {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Check each of the inputs, and if we find a match, proceed
|
||||
|
@ -24,7 +25,7 @@ func (rule *MappingRuleCombo) MatchEvent(device *evdev.InputDevice, event *evdev
|
|||
}
|
||||
|
||||
if match == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Get the value and add/subtract it from State
|
||||
|
@ -39,10 +40,10 @@ func (rule *MappingRuleCombo) MatchEvent(device *evdev.InputDevice, event *evdev
|
|||
targetState := len(rule.Inputs)
|
||||
|
||||
if oldState == targetState-1 && rule.State == targetState {
|
||||
return rule.Output.CreateEvent(1, mode)
|
||||
return rule.Output.GetDevice(), rule.Output.CreateEvent(1, mode)
|
||||
}
|
||||
if oldState == targetState && rule.State == targetState-1 {
|
||||
return rule.Output.CreateEvent(0, mode)
|
||||
return rule.Output.GetDevice(), rule.Output.CreateEvent(0, mode)
|
||||
}
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -4,19 +4,20 @@ import "github.com/holoplot/go-evdev"
|
|||
|
||||
type MappingRuleLatched struct {
|
||||
MappingRuleBase
|
||||
Input RuleTarget
|
||||
State bool
|
||||
Input *RuleTargetButton
|
||||
Output *RuleTargetButton
|
||||
State bool
|
||||
}
|
||||
|
||||
func (rule *MappingRuleLatched) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) *evdev.InputEvent {
|
||||
func (rule *MappingRuleLatched) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) (*evdev.InputDevice, *evdev.InputEvent) {
|
||||
if !rule.MappingRuleBase.modeCheck(mode) {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if device != rule.Input.GetDevice() ||
|
||||
event.Code != rule.Input.GetCode() ||
|
||||
if device != rule.Input.Device ||
|
||||
event.Code != rule.Input.Code ||
|
||||
rule.Input.NormalizeValue(event.Value) == 0 {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Input is pressed, so toggle state and emit event
|
||||
|
@ -28,5 +29,5 @@ func (rule *MappingRuleLatched) MatchEvent(device *evdev.InputDevice, event *evd
|
|||
value = 0
|
||||
}
|
||||
|
||||
return rule.Output.CreateEvent(value, mode)
|
||||
return rule.Output.Device, rule.Output.CreateEvent(value, mode)
|
||||
}
|
||||
|
|
|
@ -16,19 +16,19 @@ type MappingRuleProportionalAxis struct {
|
|||
LastEvent time.Time
|
||||
}
|
||||
|
||||
func (rule *MappingRuleProportionalAxis) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) *evdev.InputEvent {
|
||||
func (rule *MappingRuleProportionalAxis) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) (*evdev.InputDevice, *evdev.InputEvent) {
|
||||
if !rule.MappingRuleBase.modeCheck(mode) {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if device != rule.Input.GetDevice() ||
|
||||
event.Code != rule.Input.GetCode() {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// set the last value to the normalized input value
|
||||
rule.LastValue = rule.Input.NormalizeValue(event.Value)
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// TimerEvent returns an event when enough time has passed (compared to the last recorded axis value)
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package mappingrules
|
||||
|
||||
import "github.com/holoplot/go-evdev"
|
||||
|
||||
// A Simple Mapping Rule can map a button to a button or an axis to an axis.
|
||||
type MappingRuleSimple struct {
|
||||
MappingRuleBase
|
||||
Input RuleTarget
|
||||
}
|
||||
|
||||
func (rule *MappingRuleSimple) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) *evdev.InputEvent {
|
||||
if !rule.MappingRuleBase.modeCheck(mode) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if device != rule.Input.GetDevice() ||
|
||||
event.Code != rule.Input.GetCode() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return rule.Output.CreateEvent(rule.Input.NormalizeValue(event.Value), mode)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue