package mappingrules import ( "time" "github.com/holoplot/go-evdev" ) // MappingRuleAxisToButton represents a rule that converts an axis input into a (potentially repeating) // button output. // // TODO: Add Tests type MappingRuleAxisToButton struct { MappingRuleBase Input *RuleTargetAxis Output *RuleTargetButton RepeatRateMin int RepeatRateMax int nextEvent time.Duration lastEvent time.Time pressed bool } const ( NoNextEvent = time.Duration(-1) ) func NewMappingRuleAxisToButton(base MappingRuleBase, input *RuleTargetAxis, output *RuleTargetButton, repeatRateMin, repeatRateMax int) *MappingRuleAxisToButton { return &MappingRuleAxisToButton{ MappingRuleBase: base, Input: input, Output: output, RepeatRateMin: repeatRateMin, RepeatRateMax: repeatRateMax, lastEvent: time.Now(), nextEvent: NoNextEvent, pressed: false, } } func (rule *MappingRuleAxisToButton) MatchEvent(device *evdev.InputDevice, event *evdev.InputEvent, mode *string) (*evdev.InputDevice, *evdev.InputEvent) { // TODO: we're using this instead of the RuleTarget's MatchEvent because we need to check inside the deadzone // We should find a cleaner way to do this... if !rule.MappingRuleBase.modeCheck(mode) || !rule.Input.MatchEventDeviceAndCode(device, event) { return nil, nil } // If we're inside the deadzone, unset the next event if rule.Input.InDeadZone(event.Value) { rule.nextEvent = NoNextEvent return nil, nil } // If we aren't repeating, we trigger the event immediately if rule.RepeatRateMin == 0 || rule.RepeatRateMax == 0 { rule.nextEvent = time.Millisecond return nil, nil } // use the axis value and the repeat rate to set a target time until the next event strength := 1.0 - rule.Input.GetAxisStrength(event.Value) rate := int64(LerpInt(rule.RepeatRateMax, rule.RepeatRateMin, strength)) rule.nextEvent = time.Duration(rate * int64(time.Millisecond)) return nil, nil } // TimerEvent returns an event when enough time has passed (compared to the last recorded axis value) // to emit an event. func (rule *MappingRuleAxisToButton) TimerEvent() *evdev.InputEvent { // If we pressed the button last tick, release it if rule.pressed { rule.pressed = false return rule.Output.CreateEvent(0, nil) } // This indicates that we should not emit another event if rule.nextEvent == -1 { rule.lastEvent = time.Now() return nil } if time.Now().Compare(rule.lastEvent.Add(rule.nextEvent)) > -1 { rule.lastEvent = time.Now() rule.pressed = true return rule.Output.CreateEvent(1, nil) } return nil }