diff --git a/cmd/joyful/threads.go b/cmd/joyful/threads.go index 410bf5c..dabd2c7 100644 --- a/cmd/joyful/threads.go +++ b/cmd/joyful/threads.go @@ -32,7 +32,11 @@ func timerWatcher(rule *mappingrules.ProportionalAxisMappingRule, channel chan<- for { event := rule.TimerEvent() if event != nil { - channel <- ChannelEvent{Device: rule.Output.Device, Event: event, Type: ChannelEventTimer} + channel <- ChannelEvent{ + Device: rule.Output.(*mappingrules.RuleTargetModeSelect).Device, + Event: event, + Type: ChannelEventTimer, + } } time.Sleep(TimerCheckIntervalMs * time.Millisecond) } diff --git a/internal/mappingrules/matching.go b/internal/mappingrules/matching.go index 07a0d66..ae849f1 100644 --- a/internal/mappingrules/matching.go +++ b/internal/mappingrules/matching.go @@ -3,7 +3,6 @@ package mappingrules import ( "slices" - "git.annabunches.net/annabunches/joyful/internal/logger" "github.com/holoplot/go-evdev" ) @@ -18,53 +17,6 @@ func (rule *MappingRuleBase) modeCheck(mode *string) bool { return slices.Contains(rule.Modes, *mode) } -// eventFromTarget creates an outputtable event from a RuleTarget -func eventFromTarget(output RuleTarget, value int32, mode *string) *evdev.InputEvent { - // TODO: this could perhaps use some sort of multiclassing... then again, maybe this is fine? - if len(output.ModeSelect) > 0 { - if value == 0 { - return nil - } - index := 0 - if currentMode := slices.Index(output.ModeSelect, *mode); currentMode != -1 { - // find the next mode - index = (currentMode + 1) % len(output.ModeSelect) - } - - *mode = output.ModeSelect[index] - logger.Logf("Mode changed to '%s'", *mode) - return nil - } - - return &evdev.InputEvent{ - Type: output.Type, - Code: output.Code, - Value: value, - } -} - -// valueFromTarget determines the value to output from an input specification,given a RuleTarget's constraints -func valueFromTarget(rule RuleTarget, event *evdev.InputEvent) int32 { - // how we process inverted rules depends on the event type - value := event.Value - if rule.Inverted { - switch rule.Type { - case evdev.EV_KEY: - if value == 0 { - value = 1 - } else { - value = 0 - } - case evdev.EV_ABS: - logger.Logf("STUB: Inverting axes is not yet implemented.") - default: - logger.Logf("Inverted rule for unknown event type '%d'. Not inverting value", event.Type) - } - } - - return value -} - func (rule *SimpleMappingRule) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) *evdev.InputEvent { if !rule.MappingRuleBase.modeCheck(mode) { return nil @@ -123,7 +75,7 @@ func (rule *LatchedMappingRule) MatchEvent(device *evdev.InputDevice, event *evd if device != rule.Input.Device || event.Code != rule.Input.Code || - valueFromTarget(rule.Input, event) == 0 { + rule.Input.NormalizeValue(event.Value) == 0 { return nil } @@ -136,7 +88,7 @@ func (rule *LatchedMappingRule) MatchEvent(device *evdev.InputDevice, event *evd value = 0 } - return eventFromTarget(rule.Output, value, mode) + return rule.Output.CreateEvent(value, mode) } func (rule *ProportionalAxisMappingRule) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) *evdev.InputEvent { diff --git a/internal/mappingrules/targets.go b/internal/mappingrules/targets.go new file mode 100644 index 0000000..e8036d3 --- /dev/null +++ b/internal/mappingrules/targets.go @@ -0,0 +1,75 @@ +package mappingrules + +import ( + "slices" + + "git.annabunches.net/annabunches/joyful/internal/logger" + "github.com/holoplot/go-evdev" +) + +func (target *RuleTargetButton) NormalizeValue(value int32) int32 { + if value == 0 { + return 1 + } + return 0 +} + +func (target *RuleTargetAxis) NormalizeValue(value int32) int32 { + if !target.Inverted { + return value + } + + axisRange := target.AxisEnd - target.AxisStart + axisMid := target.AxisEnd - axisRange/2 + delta := value - axisMid + if delta < 0 { + delta = -delta + } + + if value < axisMid { + return axisMid + delta + } else if value > axisMid { + return axisMid - delta + } + + // If we reach here, we're either exactly at the midpoint or something + // strange has happened. Either way, just return the value. + return value +} + +// RuleTargetModeSelect doesn't make sense as an input type +func (target *RuleTargetModeSelect) NormalizeValue(value int32) int32 { + return -1 +} + +func (target *RuleTargetButton) CreateEvent(value int32, mode *string) *evdev.InputEvent { + return &evdev.InputEvent{ + Type: evdev.EV_KEY, + Code: target.Code, + Value: value, + } +} + +func (target *RuleTargetAxis) CreateEvent(value int32, mode *string) *evdev.InputEvent { + return &evdev.InputEvent{ + Type: evdev.EV_ABS, + Code: target.Code, + Value: value, + } +} + +func (target *RuleTargetModeSelect) CreateEvent(value int32, mode *string) *evdev.InputEvent { + if value == 0 { + return nil + } + + index := 0 + if currentMode := slices.Index(target.ModeSelect, *mode); currentMode != -1 { + // find the next mode + index = (currentMode + 1) % len(target.ModeSelect) + } + + *mode = target.ModeSelect[index] + logger.Logf("Mode changed to '%s'", *mode) + return nil +} diff --git a/internal/mappingrules/types.go b/internal/mappingrules/types.go index dcd79a6..a889689 100644 --- a/internal/mappingrules/types.go +++ b/internal/mappingrules/types.go @@ -44,11 +44,30 @@ type ProportionalAxisMappingRule struct { LastEvent time.Time } -type RuleTarget struct { +type RuleTarget interface { + NormalizeValue(int32) int32 + CreateEvent(int32, *string) *evdev.InputEvent +} + +type RuleTargetBase struct { DeviceName string - ModeSelect []string Device *evdev.InputDevice - Type evdev.EvType Code evdev.EvCode Inverted bool } + +type RuleTargetButton struct { + RuleTargetBase +} + +type RuleTargetAxis struct { + RuleTargetBase + AxisStart int32 + AxisEnd int32 + Sensitivity float64 +} + +type RuleTargetModeSelect struct { + RuleTargetBase + ModeSelect []string +}