Clamp values falling outside of the axis bounds.

This commit is contained in:
Anna Rose Wiggins 2025-07-10 19:58:31 -04:00
parent 681e1fef70
commit a6ad1b609a
3 changed files with 17 additions and 6 deletions

View file

@ -4,17 +4,22 @@ import (
"golang.org/x/exp/constraints" "golang.org/x/exp/constraints"
) )
func AbsInt[T constraints.Integer](value T) T { type Numeric interface {
constraints.Integer | constraints.Float
}
func Abs[T Numeric](value T) T {
return max(value, -value) return max(value, -value)
} }
// LerpInt linearly interpolates between two integer values using // LerpInt linearly interpolates between two integer values using
// a float64 index value // a float64 index value
func LerpInt[T constraints.Integer](min, max T, t float64) T { func LerpInt[T constraints.Integer](min, max T, t float64) T {
t = Clamp(t, 0.0, 1.0)
return T((1-t)*float64(min) + t*float64(max)) return T((1-t)*float64(min) + t*float64(max))
} }
func ClampInt[T constraints.Integer](value, min, max T) T { func Clamp[T Numeric](value, min, max T) T {
if value < min { if value < min {
value = min value = min
} }

View file

@ -51,7 +51,7 @@ func NewRuleTargetAxis(device_name string,
return nil, errors.New("deadzone_end must be a higher value than deadzone_start") return nil, errors.New("deadzone_end must be a higher value than deadzone_start")
} }
deadzoneSize := AbsInt(deadzoneEnd - deadzoneStart) deadzoneSize := Abs(deadzoneEnd - deadzoneStart)
// Our output range is limited to 16 bits, but we represent values internally with 32 bits. // Our output range is limited to 16 bits, but we represent values internally with 32 bits.
// As a result, we shouldn't need to worry about integer overruns // As a result, we shouldn't need to worry about integer overruns
@ -82,6 +82,7 @@ func NewRuleTargetAxis(device_name string,
// in the deadzone, among other things. // in the deadzone, among other things.
func (target *RuleTargetAxis) NormalizeValue(value int32) int32 { func (target *RuleTargetAxis) NormalizeValue(value int32) int32 {
axisStrength := float64(value-target.deadzoneSize) / float64(target.axisSize) axisStrength := float64(value-target.deadzoneSize) / float64(target.axisSize)
if target.Inverted { if target.Inverted {
axisStrength = 1.0 - axisStrength axisStrength = 1.0 - axisStrength
} }
@ -90,7 +91,7 @@ func (target *RuleTargetAxis) NormalizeValue(value int32) int32 {
} }
func (target *RuleTargetAxis) CreateEvent(value int32, mode *string) *evdev.InputEvent { func (target *RuleTargetAxis) CreateEvent(value int32, mode *string) *evdev.InputEvent {
value = ClampInt(value, AxisValueMin, AxisValueMax) value = Clamp(value, AxisValueMin, AxisValueMax)
return &evdev.InputEvent{ return &evdev.InputEvent{
Type: evdev.EV_ABS, Type: evdev.EV_ABS,
Code: target.Axis, Code: target.Axis,

View file

@ -69,8 +69,8 @@ func (t *RuleTargetAxisTests) TestNewRuleTargetAxis() {
// If Absinfo has an error, we should create a device with permissive bounds // If Absinfo has an error, we should create a device with permissive bounds
t.call.Unset() t.call.Unset()
t.mock.On("AbsInfos").Return(nil, errors.New("Test Error")) t.mock.On("AbsInfos").Return(map[evdev.EvCode]evdev.AbsInfo{}, errors.New("Test Error"))
ruleTarget, err = NewRuleTargetAxis("", t.mock, evdev.ABS_Y, false, -500, 500) ruleTarget, err = NewRuleTargetAxis("", t.mock, evdev.ABS_X, false, 0, 0)
t.Nil(err) t.Nil(err)
t.Equal(AxisValueMax-AxisValueMin, ruleTarget.axisSize) t.Equal(AxisValueMax-AxisValueMin, ruleTarget.axisSize)
} }
@ -92,6 +92,11 @@ func (t *RuleTargetAxisTests) TestNormalizeValue() {
ruleTarget, _ = NewRuleTargetAxis("", t.mock, evdev.ABS_X, true, 0, 0) ruleTarget, _ = NewRuleTargetAxis("", t.mock, evdev.ABS_X, true, 0, 0)
t.Equal(AxisValueMax, ruleTarget.NormalizeValue(int32(0))) t.Equal(AxisValueMax, ruleTarget.NormalizeValue(int32(0)))
t.Equal(AxisValueMin, ruleTarget.NormalizeValue(int32(10000))) t.Equal(AxisValueMin, ruleTarget.NormalizeValue(int32(10000)))
// Normalization past the stated axis bounds should clamp
ruleTarget, _ = NewRuleTargetAxis("", t.mock, evdev.ABS_X, false, 0, 0)
t.Equal(AxisValueMin, ruleTarget.NormalizeValue(int32(-30000)))
t.Equal(AxisValueMax, ruleTarget.NormalizeValue(int32(30000)))
} }
func (t *RuleTargetAxisTests) TestMatchEvent() { func (t *RuleTargetAxisTests) TestMatchEvent() {