(WIP) Refactor marshal schema to be more declarative.
This commit is contained in:
parent
1a7b288083
commit
74f49c0dc6
7 changed files with 253 additions and 164 deletions
|
@ -22,6 +22,8 @@ func (parser *ConfigParser) CreateVirtualDevices() map[string]*evdev.InputDevice
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deviceConfig := deviceConfig.Config.(DeviceConfigVirtual)
|
||||||
|
|
||||||
name := fmt.Sprintf("joyful-%s", deviceConfig.Name)
|
name := fmt.Sprintf("joyful-%s", deviceConfig.Name)
|
||||||
|
|
||||||
var capabilities map[evdev.EvType][]evdev.EvCode
|
var capabilities map[evdev.EvType][]evdev.EvCode
|
||||||
|
@ -88,6 +90,8 @@ func (parser *ConfigParser) ConnectPhysicalDevices() map[string]*evdev.InputDevi
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deviceConfig := deviceConfig.Config.(DeviceConfigPhysical)
|
||||||
|
|
||||||
var infoName string
|
var infoName string
|
||||||
var device *evdev.InputDevice
|
var device *evdev.InputDevice
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/holoplot/go-evdev"
|
"github.com/holoplot/go-evdev"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeRuleTargetButton(targetConfig RuleTargetConfig, devs map[string]Device) (*mappingrules.RuleTargetButton, error) {
|
func makeRuleTargetButton(targetConfig RuleTargetConfigButton, devs map[string]Device) (*mappingrules.RuleTargetButton, error) {
|
||||||
device, ok := devs[targetConfig.Device]
|
device, ok := devs[targetConfig.Device]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
||||||
|
@ -27,7 +27,7 @@ func makeRuleTargetButton(targetConfig RuleTargetConfig, devs map[string]Device)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRuleTargetAxis(targetConfig RuleTargetConfig, devs map[string]Device) (*mappingrules.RuleTargetAxis, error) {
|
func makeRuleTargetAxis(targetConfig RuleTargetConfigAxis, devs map[string]Device) (*mappingrules.RuleTargetAxis, error) {
|
||||||
device, ok := devs[targetConfig.Device]
|
device, ok := devs[targetConfig.Device]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
||||||
|
@ -57,7 +57,7 @@ func makeRuleTargetAxis(targetConfig RuleTargetConfig, devs map[string]Device) (
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRuleTargetRelaxis(targetConfig RuleTargetConfig, devs map[string]Device) (*mappingrules.RuleTargetRelaxis, error) {
|
func makeRuleTargetRelaxis(targetConfig RuleTargetConfigRelaxis, devs map[string]Device) (*mappingrules.RuleTargetRelaxis, error) {
|
||||||
device, ok := devs[targetConfig.Device]
|
device, ok := devs[targetConfig.Device]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
return nil, fmt.Errorf("non-existent device '%s'", targetConfig.Device)
|
||||||
|
@ -72,11 +72,10 @@ func makeRuleTargetRelaxis(targetConfig RuleTargetConfig, devs map[string]Device
|
||||||
targetConfig.Device,
|
targetConfig.Device,
|
||||||
device,
|
device,
|
||||||
eventCode,
|
eventCode,
|
||||||
targetConfig.Inverted,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRuleTargetModeSelect(targetConfig RuleTargetConfig, allModes []string) (*mappingrules.RuleTargetModeSelect, error) {
|
func makeRuleTargetModeSelect(targetConfig RuleTargetConfigModeSelect, allModes []string) (*mappingrules.RuleTargetModeSelect, error) {
|
||||||
if ok := validateModes(targetConfig.Modes, allModes); !ok {
|
if ok := validateModes(targetConfig.Modes, allModes); !ok {
|
||||||
return nil, errors.New("undefined mode in mode select list")
|
return nil, errors.New("undefined mode in mode select list")
|
||||||
}
|
}
|
||||||
|
@ -92,7 +91,7 @@ func hasError(_ any, err error) bool {
|
||||||
// calculateDeadzones produces the deadzone start and end values in absolute terms
|
// calculateDeadzones produces the deadzone start and end values in absolute terms
|
||||||
// TODO: on the one hand, this logic feels betten encapsulated in mappingrules. On the other hand,
|
// TODO: on the one hand, this logic feels betten encapsulated in mappingrules. On the other hand,
|
||||||
// passing even more parameters to NewRuleTargetAxis feels terrible
|
// passing even more parameters to NewRuleTargetAxis feels terrible
|
||||||
func calculateDeadzones(targetConfig RuleTargetConfig, device Device, axis evdev.EvCode) (int32, int32, error) {
|
func calculateDeadzones(targetConfig RuleTargetConfigAxis, device Device, axis evdev.EvCode) (int32, int32, error) {
|
||||||
|
|
||||||
var deadzoneStart, deadzoneEnd int32
|
var deadzoneStart, deadzoneEnd int32
|
||||||
deadzoneStart = 0
|
deadzoneStart = 0
|
||||||
|
|
|
@ -12,7 +12,6 @@ type MakeRuleTargetsTests struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
devs map[string]Device
|
devs map[string]Device
|
||||||
deviceMock *DeviceMock
|
deviceMock *DeviceMock
|
||||||
config RuleTargetConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeviceMock struct {
|
type DeviceMock struct {
|
||||||
|
@ -47,198 +46,198 @@ func (t *MakeRuleTargetsTests) SetupSuite() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MakeRuleTargetsTests) SetupSubTest() {
|
|
||||||
t.config = RuleTargetConfig{
|
|
||||||
Device: "test",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *MakeRuleTargetsTests) TestMakeRuleTargetButton() {
|
func (t *MakeRuleTargetsTests) TestMakeRuleTargetButton() {
|
||||||
|
config := RuleTargetConfigButton{Device: "test"}
|
||||||
|
|
||||||
t.Run("Standard keycode", func() {
|
t.Run("Standard keycode", func() {
|
||||||
t.config.Button = "BTN_TRIGGER"
|
config.Button = "BTN_TRIGGER"
|
||||||
rule, err := makeRuleTargetButton(t.config, t.devs)
|
rule, err := makeRuleTargetButton(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() {
|
||||||
t.config.Button = "0x2fd"
|
config.Button = "0x2fd"
|
||||||
rule, err := makeRuleTargetButton(t.config, t.devs)
|
rule, err := makeRuleTargetButton(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() {
|
||||||
t.config.Button = "3"
|
config.Button = "3"
|
||||||
rule, err := makeRuleTargetButton(t.config, t.devs)
|
rule, err := makeRuleTargetButton(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() {
|
||||||
t.config.Button = "74"
|
config.Button = "74"
|
||||||
_, err := makeRuleTargetButton(t.config, t.devs)
|
_, err := makeRuleTargetButton(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Un-prefixed keycode", func() {
|
t.Run("Un-prefixed keycode", func() {
|
||||||
t.config.Button = "pinkie"
|
config.Button = "pinkie"
|
||||||
rule, err := makeRuleTargetButton(t.config, t.devs)
|
rule, err := makeRuleTargetButton(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() {
|
||||||
t.config.Button = "foo"
|
config.Button = "foo"
|
||||||
_, err := makeRuleTargetButton(t.config, t.devs)
|
_, err := makeRuleTargetButton(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() {
|
func (t *MakeRuleTargetsTests) TestMakeRuleTargetAxis() {
|
||||||
|
config := RuleTargetConfigAxis{Device: "test"}
|
||||||
|
|
||||||
t.Run("Standard code", func() {
|
t.Run("Standard code", func() {
|
||||||
t.config.Axis = "ABS_X"
|
config.Axis = "ABS_X"
|
||||||
rule, err := makeRuleTargetAxis(t.config, t.devs)
|
rule, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.ABS_X, rule.Axis)
|
t.EqualValues(evdev.ABS_X, rule.Axis)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Hex code", func() {
|
t.Run("Hex code", func() {
|
||||||
t.config.Axis = "0x01"
|
config.Axis = "0x01"
|
||||||
rule, err := makeRuleTargetAxis(t.config, t.devs)
|
rule, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.ABS_Y, rule.Axis)
|
t.EqualValues(evdev.ABS_Y, rule.Axis)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Un-prefixed code", func() {
|
t.Run("Un-prefixed code", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
rule, err := makeRuleTargetAxis(t.config, t.devs)
|
rule, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(evdev.ABS_X, rule.Axis)
|
t.EqualValues(evdev.ABS_X, rule.Axis)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Invalid code", func() {
|
t.Run("Invalid code", func() {
|
||||||
t.config.Axis = "foo"
|
config.Axis = "foo"
|
||||||
_, err := makeRuleTargetAxis(t.config, t.devs)
|
_, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Invalid deadzone", func() {
|
t.Run("Invalid deadzone", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
t.config.DeadzoneEnd = 100
|
config.DeadzoneEnd = 100
|
||||||
t.config.DeadzoneStart = 1000
|
config.DeadzoneStart = 1000
|
||||||
_, err := makeRuleTargetAxis(t.config, t.devs)
|
_, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Deadzone center/size", func() {
|
t.Run("Deadzone center/size", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
t.config.DeadzoneCenter = 5000
|
config.DeadzoneCenter = 5000
|
||||||
t.config.DeadzoneSize = 1000
|
config.DeadzoneSize = 1000
|
||||||
rule, err := makeRuleTargetAxis(t.config, t.devs)
|
rule, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(4500, rule.DeadzoneStart)
|
t.EqualValues(4500, rule.DeadzoneStart)
|
||||||
t.EqualValues(5500, rule.DeadzoneEnd)
|
t.EqualValues(5500, rule.DeadzoneEnd)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Deadzone center/size lower boundary", func() {
|
t.Run("Deadzone center/size lower boundary", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
t.config.DeadzoneCenter = 0
|
config.DeadzoneCenter = 0
|
||||||
t.config.DeadzoneSize = 500
|
config.DeadzoneSize = 500
|
||||||
rule, err := makeRuleTargetAxis(t.config, t.devs)
|
rule, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(0, rule.DeadzoneStart)
|
t.EqualValues(0, rule.DeadzoneStart)
|
||||||
t.EqualValues(500, rule.DeadzoneEnd)
|
t.EqualValues(500, rule.DeadzoneEnd)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Deadzone center/size upper boundary", func() {
|
t.Run("Deadzone center/size upper boundary", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
t.config.DeadzoneCenter = 10000
|
config.DeadzoneCenter = 10000
|
||||||
t.config.DeadzoneSize = 500
|
config.DeadzoneSize = 500
|
||||||
rule, err := makeRuleTargetAxis(t.config, t.devs)
|
rule, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(9500, rule.DeadzoneStart)
|
t.EqualValues(9500, rule.DeadzoneStart)
|
||||||
t.EqualValues(10000, rule.DeadzoneEnd)
|
t.EqualValues(10000, rule.DeadzoneEnd)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Deadzone center/size invalid center", func() {
|
t.Run("Deadzone center/size invalid center", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
t.config.DeadzoneCenter = 20000
|
config.DeadzoneCenter = 20000
|
||||||
t.config.DeadzoneSize = 500
|
config.DeadzoneSize = 500
|
||||||
_, err := makeRuleTargetAxis(t.config, t.devs)
|
_, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Deadzone center/percent", func() {
|
t.Run("Deadzone center/percent", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
t.config.DeadzoneCenter = 5000
|
config.DeadzoneCenter = 5000
|
||||||
t.config.DeadzoneSizePercent = 10
|
config.DeadzoneSizePercent = 10
|
||||||
rule, err := makeRuleTargetAxis(t.config, t.devs)
|
rule, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(4500, rule.DeadzoneStart)
|
t.EqualValues(4500, rule.DeadzoneStart)
|
||||||
t.EqualValues(5500, rule.DeadzoneEnd)
|
t.EqualValues(5500, rule.DeadzoneEnd)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Deadzone center/percent lower boundary", func() {
|
t.Run("Deadzone center/percent lower boundary", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
t.config.DeadzoneCenter = 0
|
config.DeadzoneCenter = 0
|
||||||
t.config.DeadzoneSizePercent = 10
|
config.DeadzoneSizePercent = 10
|
||||||
rule, err := makeRuleTargetAxis(t.config, t.devs)
|
rule, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(0, rule.DeadzoneStart)
|
t.EqualValues(0, rule.DeadzoneStart)
|
||||||
t.EqualValues(1000, rule.DeadzoneEnd)
|
t.EqualValues(1000, rule.DeadzoneEnd)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Deadzone center/percent upper boundary", func() {
|
t.Run("Deadzone center/percent upper boundary", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
t.config.DeadzoneCenter = 10000
|
config.DeadzoneCenter = 10000
|
||||||
t.config.DeadzoneSizePercent = 10
|
config.DeadzoneSizePercent = 10
|
||||||
rule, err := makeRuleTargetAxis(t.config, t.devs)
|
rule, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.Nil(err)
|
t.Nil(err)
|
||||||
t.EqualValues(9000, rule.DeadzoneStart)
|
t.EqualValues(9000, rule.DeadzoneStart)
|
||||||
t.EqualValues(10000, rule.DeadzoneEnd)
|
t.EqualValues(10000, rule.DeadzoneEnd)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Deadzone center/percent invalid center", func() {
|
t.Run("Deadzone center/percent invalid center", func() {
|
||||||
t.config.Axis = "x"
|
config.Axis = "x"
|
||||||
t.config.DeadzoneCenter = 20000
|
config.DeadzoneCenter = 20000
|
||||||
t.config.DeadzoneSizePercent = 10
|
config.DeadzoneSizePercent = 10
|
||||||
_, err := makeRuleTargetAxis(t.config, t.devs)
|
_, err := makeRuleTargetAxis(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MakeRuleTargetsTests) TestMakeRuleTargetRelaxis() {
|
func (t *MakeRuleTargetsTests) TestMakeRuleTargetRelaxis() {
|
||||||
|
config := RuleTargetConfigRelaxis{Device: "test"}
|
||||||
|
|
||||||
t.Run("Standard keycode", func() {
|
t.Run("Standard keycode", func() {
|
||||||
t.config.Axis = "REL_WHEEL"
|
config.Axis = "REL_WHEEL"
|
||||||
rule, err := makeRuleTargetRelaxis(t.config, t.devs)
|
rule, err := makeRuleTargetRelaxis(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() {
|
||||||
t.config.Axis = "0x00"
|
config.Axis = "0x00"
|
||||||
rule, err := makeRuleTargetRelaxis(t.config, t.devs)
|
rule, err := makeRuleTargetRelaxis(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() {
|
||||||
t.config.Axis = "wheel"
|
config.Axis = "wheel"
|
||||||
rule, err := makeRuleTargetRelaxis(t.config, t.devs)
|
rule, err := makeRuleTargetRelaxis(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() {
|
||||||
t.config.Axis = "foo"
|
config.Axis = "foo"
|
||||||
_, err := makeRuleTargetRelaxis(t.config, t.devs)
|
_, err := makeRuleTargetRelaxis(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Incorrect axis type", func() {
|
t.Run("Incorrect axis type", func() {
|
||||||
t.config.Axis = "ABS_X"
|
config.Axis = "ABS_X"
|
||||||
_, err := makeRuleTargetRelaxis(t.config, t.devs)
|
_, err := makeRuleTargetRelaxis(config, t.devs)
|
||||||
t.NotNil(err)
|
t.NotNil(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,21 +42,21 @@ func (parser *ConfigParser) BuildRules(pInputDevs map[string]*evdev.InputDevice,
|
||||||
|
|
||||||
switch strings.ToLower(ruleConfig.Type) {
|
switch strings.ToLower(ruleConfig.Type) {
|
||||||
case RuleTypeButton:
|
case RuleTypeButton:
|
||||||
newRule, err = makeMappingRuleButton(ruleConfig, pDevs, vDevs, base)
|
newRule, err = makeMappingRuleButton(ruleConfig.Config.(RuleConfigButton), pDevs, vDevs, base)
|
||||||
case RuleTypeButtonCombo:
|
case RuleTypeButtonCombo:
|
||||||
newRule, err = makeMappingRuleCombo(ruleConfig, pDevs, vDevs, base)
|
newRule, err = makeMappingRuleCombo(ruleConfig.Config.(RuleConfigButtonCombo), pDevs, vDevs, base)
|
||||||
case RuleTypeLatched:
|
case RuleTypeButtonLatched:
|
||||||
newRule, err = makeMappingRuleLatched(ruleConfig, pDevs, vDevs, base)
|
newRule, err = makeMappingRuleLatched(ruleConfig.Config.(RuleConfigButtonLatched), pDevs, vDevs, base)
|
||||||
case RuleTypeAxis:
|
case RuleTypeAxis:
|
||||||
newRule, err = makeMappingRuleAxis(ruleConfig, pDevs, vDevs, base)
|
newRule, err = makeMappingRuleAxis(ruleConfig.Config.(RuleConfigAxis), pDevs, vDevs, base)
|
||||||
case RuleTypeAxisCombined:
|
case RuleTypeAxisCombined:
|
||||||
newRule, err = makeMappingRuleAxisCombined(ruleConfig, pDevs, vDevs, base)
|
newRule, err = makeMappingRuleAxisCombined(ruleConfig.Config.(RuleConfigAxisCombined), pDevs, vDevs, base)
|
||||||
case RuleTypeAxisToButton:
|
case RuleTypeAxisToButton:
|
||||||
newRule, err = makeMappingRuleAxisToButton(ruleConfig, pDevs, vDevs, base)
|
newRule, err = makeMappingRuleAxisToButton(ruleConfig.Config.(RuleConfigAxisToButton), pDevs, vDevs, base)
|
||||||
case RuleTypeAxisToRelaxis:
|
case RuleTypeAxisToRelaxis:
|
||||||
newRule, err = makeMappingRuleAxisToRelaxis(ruleConfig, pDevs, vDevs, base)
|
newRule, err = makeMappingRuleAxisToRelaxis(ruleConfig.Config.(RuleConfigAxisToRelaxis), pDevs, vDevs, base)
|
||||||
case RuleTypeModeSelect:
|
case RuleTypeModeSelect:
|
||||||
newRule, err = makeMappingRuleModeSelect(ruleConfig, pDevs, modes, base)
|
newRule, err = makeMappingRuleModeSelect(ruleConfig.Config.(RuleConfigModeSelect), pDevs, modes, base)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("bad rule type '%s' for rule '%s'", ruleConfig.Type, ruleConfig.Name)
|
err = fmt.Errorf("bad rule type '%s' for rule '%s'", ruleConfig.Type, ruleConfig.Name)
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,14 @@ func (parser *ConfigParser) BuildRules(pInputDevs map[string]*evdev.InputDevice,
|
||||||
return rules
|
return rules
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMappingRuleButton(ruleConfig RuleConfig,
|
// TODO: how much of these functions could we fold into the unmarshaling logic itself? The main problem
|
||||||
|
// is that we don't have access to the device maps in those functions... could we set device names
|
||||||
|
// as stand-ins and do a post-processing pass that *just* handles device linking and possibly mode
|
||||||
|
// checking?
|
||||||
|
//
|
||||||
|
// In other words - can we unmarshal the config directly into our target structs and remove most of
|
||||||
|
// this library?
|
||||||
|
func makeMappingRuleButton(ruleConfig RuleConfigButton,
|
||||||
pDevs map[string]Device,
|
pDevs map[string]Device,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButton, error) {
|
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButton, error) {
|
||||||
|
@ -90,7 +97,7 @@ func makeMappingRuleButton(ruleConfig RuleConfig,
|
||||||
return mappingrules.NewMappingRuleButton(base, input, output), nil
|
return mappingrules.NewMappingRuleButton(base, input, output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMappingRuleCombo(ruleConfig RuleConfig,
|
func makeMappingRuleCombo(ruleConfig RuleConfigButtonCombo,
|
||||||
pDevs map[string]Device,
|
pDevs map[string]Device,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButtonCombo, error) {
|
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButtonCombo, error) {
|
||||||
|
@ -112,7 +119,7 @@ func makeMappingRuleCombo(ruleConfig RuleConfig,
|
||||||
return mappingrules.NewMappingRuleButtonCombo(base, inputs, output), nil
|
return mappingrules.NewMappingRuleButtonCombo(base, inputs, output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMappingRuleLatched(ruleConfig RuleConfig,
|
func makeMappingRuleLatched(ruleConfig RuleConfigButtonLatched,
|
||||||
pDevs map[string]Device,
|
pDevs map[string]Device,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButtonLatched, error) {
|
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleButtonLatched, error) {
|
||||||
|
@ -130,7 +137,7 @@ func makeMappingRuleLatched(ruleConfig RuleConfig,
|
||||||
return mappingrules.NewMappingRuleButtonLatched(base, input, output), nil
|
return mappingrules.NewMappingRuleButtonLatched(base, input, output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMappingRuleAxis(ruleConfig RuleConfig,
|
func makeMappingRuleAxis(ruleConfig RuleConfigAxis,
|
||||||
pDevs map[string]Device,
|
pDevs map[string]Device,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxis, error) {
|
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxis, error) {
|
||||||
|
@ -148,7 +155,7 @@ func makeMappingRuleAxis(ruleConfig RuleConfig,
|
||||||
return mappingrules.NewMappingRuleAxis(base, input, output), nil
|
return mappingrules.NewMappingRuleAxis(base, input, output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMappingRuleAxisCombined(ruleConfig RuleConfig,
|
func makeMappingRuleAxisCombined(ruleConfig RuleConfigAxisCombined,
|
||||||
pDevs map[string]Device,
|
pDevs map[string]Device,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxisCombined, error) {
|
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxisCombined, error) {
|
||||||
|
@ -171,7 +178,7 @@ func makeMappingRuleAxisCombined(ruleConfig RuleConfig,
|
||||||
return mappingrules.NewMappingRuleAxisCombined(base, inputLower, inputUpper, output), nil
|
return mappingrules.NewMappingRuleAxisCombined(base, inputLower, inputUpper, output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMappingRuleAxisToButton(ruleConfig RuleConfig,
|
func makeMappingRuleAxisToButton(ruleConfig RuleConfigAxisToButton,
|
||||||
pDevs map[string]Device,
|
pDevs map[string]Device,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxisToButton, error) {
|
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxisToButton, error) {
|
||||||
|
@ -189,7 +196,7 @@ func makeMappingRuleAxisToButton(ruleConfig RuleConfig,
|
||||||
return mappingrules.NewMappingRuleAxisToButton(base, input, output, ruleConfig.RepeatRateMin, ruleConfig.RepeatRateMax), nil
|
return mappingrules.NewMappingRuleAxisToButton(base, input, output, ruleConfig.RepeatRateMin, ruleConfig.RepeatRateMax), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMappingRuleAxisToRelaxis(ruleConfig RuleConfig,
|
func makeMappingRuleAxisToRelaxis(ruleConfig RuleConfigAxisToRelaxis,
|
||||||
pDevs map[string]Device,
|
pDevs map[string]Device,
|
||||||
vDevs map[string]Device,
|
vDevs map[string]Device,
|
||||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxisToRelaxis, error) {
|
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleAxisToRelaxis, error) {
|
||||||
|
@ -211,7 +218,7 @@ func makeMappingRuleAxisToRelaxis(ruleConfig RuleConfig,
|
||||||
ruleConfig.Increment), nil
|
ruleConfig.Increment), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMappingRuleModeSelect(ruleConfig RuleConfig,
|
func makeMappingRuleModeSelect(ruleConfig RuleConfigModeSelect,
|
||||||
pDevs map[string]Device,
|
pDevs map[string]Device,
|
||||||
modes []string,
|
modes []string,
|
||||||
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleModeSelect, error) {
|
base mappingrules.MappingRuleBase) (*mappingrules.MappingRuleModeSelect, error) {
|
||||||
|
|
|
@ -1,25 +1,39 @@
|
||||||
// These types comprise the YAML schema for configuring Joyful.
|
// These types comprise the YAML schema for configuring Joyful.
|
||||||
// The config files will be combined and then unmarshalled into this
|
// The config files will be combined and then unmarshalled into this
|
||||||
//
|
|
||||||
// TODO: currently the types in here aren't especially strong; each one is
|
|
||||||
// decomposed into a different object based on the Type fields. We should implement
|
|
||||||
// some sort of delayed unmarshalling technique, for example see ideas at
|
|
||||||
// https://stackoverflow.com/questions/70635636/unmarshaling-yaml-into-different-struct-based-off-yaml-field
|
|
||||||
// Then we can be more explicit about the interface here.
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Devices []DeviceConfig `yaml:"devices"`
|
Devices []DeviceConfig
|
||||||
Modes []string `yaml:"modes,omitempty"`
|
Modes []string
|
||||||
Rules []RuleConfig `yaml:"rules"`
|
Rules []RuleConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These structs use custom unmarshaling to inline each available sub-type
|
||||||
type DeviceConfig struct {
|
type DeviceConfig struct {
|
||||||
|
Type string
|
||||||
|
Config interface{} `yaml:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleConfig struct {
|
||||||
|
Type string
|
||||||
|
Name string
|
||||||
|
Modes []string
|
||||||
|
Config interface{} `yaml:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeviceConfigPhysical struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
DeviceName string `yaml:"device_name,omitempty"`
|
||||||
|
DevicePath string `yaml:"device_path,omitempty"`
|
||||||
|
Lock bool `yaml:"lock,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: configure custom unmarshaling so we can overload Buttons, Axes, and RelativeAxes...
|
||||||
|
type DeviceConfigVirtual struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
Type string `yaml:"type"`
|
|
||||||
DeviceName string `yaml:"device_name,omitempty"`
|
|
||||||
DevicePath string `yaml:"device_path,omitempty"`
|
|
||||||
Preset string `yaml:"preset,omitempty"`
|
Preset string `yaml:"preset,omitempty"`
|
||||||
NumButtons int `yaml:"num_buttons,omitempty"`
|
NumButtons int `yaml:"num_buttons,omitempty"`
|
||||||
NumAxes int `yaml:"num_axes,omitempty"`
|
NumAxes int `yaml:"num_axes,omitempty"`
|
||||||
|
@ -27,53 +41,130 @@ type DeviceConfig struct {
|
||||||
Buttons []string `yaml:"buttons,omitempty"`
|
Buttons []string `yaml:"buttons,omitempty"`
|
||||||
Axes []string `yaml:"axes,omitempty"`
|
Axes []string `yaml:"axes,omitempty"`
|
||||||
RelativeAxes []string `yaml:"rel_axes,omitempty"`
|
RelativeAxes []string `yaml:"rel_axes,omitempty"`
|
||||||
Lock bool `yaml:"lock,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RuleConfig struct {
|
type RuleConfigButton struct {
|
||||||
Name string `yaml:"name,omitempty"`
|
Input RuleTargetConfigButton
|
||||||
Type string `yaml:"type"`
|
Output RuleTargetConfigButton
|
||||||
Input RuleTargetConfig `yaml:"input,omitempty"`
|
|
||||||
InputLower RuleTargetConfig `yaml:"input_lower,omitempty"`
|
|
||||||
InputUpper RuleTargetConfig `yaml:"input_upper,omitempty"`
|
|
||||||
Inputs []RuleTargetConfig `yaml:"inputs,omitempty"`
|
|
||||||
Output RuleTargetConfig `yaml:"output"`
|
|
||||||
Modes []string `yaml:"modes,omitempty"`
|
|
||||||
RepeatRateMin int `yaml:"repeat_rate_min,omitempty"`
|
|
||||||
RepeatRateMax int `yaml:"repeat_rate_max,omitempty"`
|
|
||||||
Increment int `yaml:"increment,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RuleTargetConfig struct {
|
type RuleConfigButtonCombo struct {
|
||||||
Device string `yaml:"device,omitempty"`
|
Inputs []RuleTargetConfigButton
|
||||||
Button string `yaml:"button,omitempty"`
|
Output RuleTargetConfigButton
|
||||||
Axis string `yaml:"axis,omitempty"`
|
}
|
||||||
DeadzoneCenter int32 `yaml:"deadzone_center,omitempty"`
|
|
||||||
DeadzoneSize int32 `yaml:"deadzone_size,omitempty"`
|
type RuleConfigButtonLatched struct {
|
||||||
DeadzoneSizePercent int32 `yaml:"deadzone_size_percent,omitempty"`
|
Input RuleTargetConfigButton
|
||||||
DeadzoneStart int32 `yaml:"deadzone_start,omitempty"`
|
Output RuleTargetConfigButton
|
||||||
DeadzoneEnd int32 `yaml:"deadzone_end,omitempty"`
|
}
|
||||||
Inverted bool `yaml:"inverted,omitempty"`
|
|
||||||
Modes []string `yaml:"modes,omitempty"`
|
type RuleConfigAxis struct {
|
||||||
|
Input RuleTargetConfigAxis
|
||||||
|
Output RuleTargetConfigAxis
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleConfigAxisCombined struct {
|
||||||
|
InputLower RuleTargetConfigAxis `yaml:"input_lower,omitempty"`
|
||||||
|
InputUpper RuleTargetConfigAxis `yaml:"input_upper,omitempty"`
|
||||||
|
Output RuleTargetConfigAxis
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleConfigAxisToButton struct {
|
||||||
|
RepeatRateMin int `yaml:"repeat_rate_min,omitempty"`
|
||||||
|
RepeatRateMax int `yaml:"repeat_rate_max,omitempty"`
|
||||||
|
Input RuleTargetConfigAxis
|
||||||
|
Output RuleTargetConfigButton
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleConfigAxisToRelaxis struct {
|
||||||
|
RepeatRateMin int `yaml:"repeat_rate_min"`
|
||||||
|
RepeatRateMax int `yaml:"repeat_rate_max"`
|
||||||
|
Increment int
|
||||||
|
Input RuleTargetConfigAxis
|
||||||
|
Output RuleTargetConfigRelaxis
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleConfigModeSelect struct {
|
||||||
|
Input RuleTargetConfigButton
|
||||||
|
Output RuleTargetConfigModeSelect
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleTargetConfigButton struct {
|
||||||
|
Device string
|
||||||
|
Button string
|
||||||
|
Inverted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleTargetConfigAxis struct {
|
||||||
|
Device string
|
||||||
|
Axis string
|
||||||
|
DeadzoneCenter int32 `yaml:"deadzone_center,omitempty"`
|
||||||
|
DeadzoneSize int32 `yaml:"deadzone_size,omitempty"`
|
||||||
|
DeadzoneSizePercent int32 `yaml:"deadzone_size_percent,omitempty"`
|
||||||
|
DeadzoneStart int32 `yaml:"deadzone_start,omitempty"`
|
||||||
|
DeadzoneEnd int32 `yaml:"deadzone_end,omitempty"`
|
||||||
|
Inverted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleTargetConfigRelaxis struct {
|
||||||
|
Device string
|
||||||
|
Axis string
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleTargetConfigModeSelect struct {
|
||||||
|
Modes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc *DeviceConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error {
|
||||||
|
var config interface{}
|
||||||
|
dc.Config = config
|
||||||
|
|
||||||
|
switch dc.Type {
|
||||||
|
case DeviceTypePhysical:
|
||||||
|
config = &DeviceConfigPhysical{}
|
||||||
|
case DeviceTypeVirtual:
|
||||||
|
config = &DeviceConfigVirtual{}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid device type '%s'", dc.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
return unmarshal(&config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc *RuleConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error {
|
||||||
|
switch dc.Type {
|
||||||
|
case RuleTypeButton:
|
||||||
|
dc.Config = &RuleConfigButton{}
|
||||||
|
case RuleTypeButtonCombo:
|
||||||
|
dc.Config = &RuleConfigButtonCombo{}
|
||||||
|
case RuleTypeButtonLatched:
|
||||||
|
dc.Config = &RuleConfigButtonLatched{}
|
||||||
|
case RuleTypeAxis:
|
||||||
|
dc.Config = &RuleConfigAxis{}
|
||||||
|
case RuleTypeAxisCombined:
|
||||||
|
dc.Config = &RuleConfigAxisCombined{}
|
||||||
|
case RuleTypeAxisToButton:
|
||||||
|
dc.Config = &RuleConfigAxisToButton{}
|
||||||
|
case RuleTypeAxisToRelaxis:
|
||||||
|
dc.Config = &RuleConfigAxisToRelaxis{}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid rule type '%s'", dc.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
return unmarshal(&dc.Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: custom yaml unmarshaling is obtuse; do we really need to do all of this work
|
// TODO: custom yaml unmarshaling is obtuse; do we really need to do all of this work
|
||||||
// just to set a single default value?
|
// just to set a single default value?
|
||||||
func (dc *DeviceConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error {
|
func (dc *DeviceConfigPhysical) UnmarshalYAML(unmarshal func(data interface{}) error) error {
|
||||||
var raw struct {
|
var raw struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
DeviceName string `yaml:"device_name"`
|
||||||
DeviceName string `yaml:"device_name"`
|
DevicePath string `yaml:"device_path"`
|
||||||
DevicePath string `yaml:"device_path"`
|
Lock bool `yaml:"lock,omitempty"`
|
||||||
Preset string
|
|
||||||
NumButtons int `yaml:"num_buttons"`
|
|
||||||
NumAxes int `yaml:"num_axes"`
|
|
||||||
NumRelativeAxes int `yaml:"num_rel_axes"`
|
|
||||||
Buttons []string
|
|
||||||
Axes []string
|
|
||||||
RelativeAxes []string `yaml:"relative_axes"`
|
|
||||||
Lock bool `yaml:"lock,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set non-standard defaults
|
||||||
raw.Lock = true
|
raw.Lock = true
|
||||||
|
|
||||||
err := unmarshal(&raw)
|
err := unmarshal(&raw)
|
||||||
|
@ -81,19 +172,11 @@ func (dc *DeviceConfig) UnmarshalYAML(unmarshal func(data interface{}) error) er
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*dc = DeviceConfig{
|
*dc = DeviceConfigPhysical{
|
||||||
Name: raw.Name,
|
Name: raw.Name,
|
||||||
Type: raw.Type,
|
DeviceName: raw.DeviceName,
|
||||||
DeviceName: raw.DeviceName,
|
DevicePath: raw.DevicePath,
|
||||||
DevicePath: raw.DevicePath,
|
Lock: raw.Lock,
|
||||||
Preset: raw.Preset,
|
|
||||||
NumButtons: raw.NumButtons,
|
|
||||||
NumAxes: raw.NumAxes,
|
|
||||||
NumRelativeAxes: raw.NumRelativeAxes,
|
|
||||||
Buttons: raw.Buttons,
|
|
||||||
Axes: raw.Axes,
|
|
||||||
RelativeAxes: raw.RelativeAxes,
|
|
||||||
Lock: raw.Lock,
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@ const (
|
||||||
|
|
||||||
RuleTypeButton = "button"
|
RuleTypeButton = "button"
|
||||||
RuleTypeButtonCombo = "button-combo"
|
RuleTypeButtonCombo = "button-combo"
|
||||||
RuleTypeLatched = "button-latched"
|
RuleTypeButtonLatched = "button-latched"
|
||||||
RuleTypeAxis = "axis"
|
RuleTypeAxis = "axis"
|
||||||
RuleTypeAxisCombined = "axis-combined"
|
RuleTypeAxisCombined = "axis-combined"
|
||||||
RuleTypeModeSelect = "mode-select"
|
|
||||||
RuleTypeAxisToButton = "axis-to-button"
|
RuleTypeAxisToButton = "axis-to-button"
|
||||||
RuleTypeAxisToRelaxis = "axis-to-relaxis"
|
RuleTypeAxisToRelaxis = "axis-to-relaxis"
|
||||||
|
RuleTypeModeSelect = "mode-select"
|
||||||
|
|
||||||
CodePrefixButton = "BTN"
|
CodePrefixButton = "BTN"
|
||||||
CodePrefixKey = "KEY"
|
CodePrefixKey = "KEY"
|
||||||
|
|
|
@ -8,19 +8,16 @@ type RuleTargetRelaxis struct {
|
||||||
DeviceName string
|
DeviceName string
|
||||||
Device Device
|
Device Device
|
||||||
Axis evdev.EvCode
|
Axis evdev.EvCode
|
||||||
Inverted bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRuleTargetRelaxis(device_name string,
|
func NewRuleTargetRelaxis(device_name string,
|
||||||
device Device,
|
device Device,
|
||||||
axis evdev.EvCode,
|
axis evdev.EvCode) (*RuleTargetRelaxis, error) {
|
||||||
inverted bool) (*RuleTargetRelaxis, error) {
|
|
||||||
|
|
||||||
return &RuleTargetRelaxis{
|
return &RuleTargetRelaxis{
|
||||||
DeviceName: device_name,
|
DeviceName: device_name,
|
||||||
Device: device,
|
Device: device,
|
||||||
Axis: axis,
|
Axis: axis,
|
||||||
Inverted: inverted,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue