98 lines
2.6 KiB
Go
98 lines
2.6 KiB
Go
package mappingrules
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/holoplot/go-evdev"
|
|
)
|
|
|
|
type RuleTargetAxis struct {
|
|
DeviceName string
|
|
Device RuleTargetDevice
|
|
Axis evdev.EvCode
|
|
Inverted bool
|
|
DeadzoneStart int32
|
|
DeadzoneEnd int32
|
|
axisSize int32
|
|
deadzoneSize int32
|
|
}
|
|
|
|
const (
|
|
MinAxisValue = int32(-32768)
|
|
MaxAxisValue = int32(32767)
|
|
)
|
|
|
|
func NewRuleTargetAxis(device_name string,
|
|
device RuleTargetDevice,
|
|
axis evdev.EvCode,
|
|
inverted bool,
|
|
deadzoneStart int32,
|
|
deadzoneEnd int32) (*RuleTargetAxis, error) {
|
|
|
|
info, err := device.AbsInfos()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if _, ok := info[axis]; !ok {
|
|
return nil, fmt.Errorf("device does not support axis %v", axis)
|
|
}
|
|
|
|
if deadzoneStart > deadzoneEnd {
|
|
return nil, errors.New("deadzone_end must be a higher value than deadzone_start")
|
|
}
|
|
|
|
deadzoneSize := AbsInt(deadzoneEnd - deadzoneStart)
|
|
|
|
// 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
|
|
axisSize := info[axis].Maximum - info[axis].Minimum - deadzoneSize
|
|
|
|
if axisSize == 0 {
|
|
return nil, errors.New("axis has size 0")
|
|
}
|
|
|
|
return &RuleTargetAxis{
|
|
DeviceName: device_name,
|
|
Device: device,
|
|
Axis: axis,
|
|
Inverted: inverted,
|
|
DeadzoneStart: deadzoneStart,
|
|
DeadzoneEnd: deadzoneEnd,
|
|
deadzoneSize: deadzoneSize,
|
|
axisSize: axisSize,
|
|
}, nil
|
|
}
|
|
|
|
// NormalizeValue takes a raw input value and converts it to a value suitable for output.
|
|
//
|
|
// Axis inputs are normalized to the full signed int32 range to match the virtual device's axis
|
|
// characteristics.
|
|
//
|
|
// Typically this function is called after RuleTargetAxis.MatchEvent, which checks whether we are
|
|
// in the deadzone, among other things.
|
|
func (target *RuleTargetAxis) NormalizeValue(value int32) int32 {
|
|
axisStrength := float64(value-target.deadzoneSize) / float64(target.axisSize)
|
|
if target.Inverted {
|
|
axisStrength = 1.0 - axisStrength
|
|
}
|
|
normalizedValue := LerpInt(MinAxisValue, MaxAxisValue, axisStrength)
|
|
return normalizedValue
|
|
}
|
|
|
|
func (target *RuleTargetAxis) CreateEvent(value int32, mode *string) *evdev.InputEvent {
|
|
value = ClampInt(value, MinAxisValue, MaxAxisValue)
|
|
return &evdev.InputEvent{
|
|
Type: evdev.EV_ABS,
|
|
Code: target.Axis,
|
|
Value: value,
|
|
}
|
|
}
|
|
|
|
func (target *RuleTargetAxis) MatchEvent(device RuleTargetDevice, event *evdev.InputEvent) bool {
|
|
return device == target.Device &&
|
|
event.Type == evdev.EV_ABS &&
|
|
event.Code == target.Axis &&
|
|
(event.Value < target.DeadzoneStart || event.Value > target.DeadzoneEnd)
|
|
}
|