diff --git a/hid-xpadneo/src/hid-xpadneo.c b/hid-xpadneo/src/hid-xpadneo.c index cd50d6ac..29d25616 100644 --- a/hid-xpadneo/src/hid-xpadneo.c +++ b/hid-xpadneo/src/hid-xpadneo.c @@ -942,10 +942,10 @@ static int xpadneo_input_configured(struct hid_device *hdev, struct hid_input *h if (param_gamepad_compliance) { hid_info(hdev, "enabling compliance with Linux Gamepad Specification\n"); - input_set_abs_params(xdata->idev, ABS_X, -32768, 32767, 7, 4095); - input_set_abs_params(xdata->idev, ABS_Y, -32768, 32767, 7, 4095); - input_set_abs_params(xdata->idev, ABS_RX, -32768, 32767, 7, 4095); - input_set_abs_params(xdata->idev, ABS_RY, -32768, 32767, 7, 4095); + input_set_abs_params(xdata->idev, ABS_X, -32768, 32767, 0, 0); + input_set_abs_params(xdata->idev, ABS_Y, -32768, 32767, 0, 0); + input_set_abs_params(xdata->idev, ABS_RX, -32768, 32767, 0, 0); + input_set_abs_params(xdata->idev, ABS_RY, -32768, 32767, 0, 0); } /* combine triggers to form a rudder, use ABS_MISC to order after dpad */ @@ -954,8 +954,20 @@ static int xpadneo_input_configured(struct hid_device *hdev, struct hid_input *h return 0; } -static void xpadneo_report_abs(struct xpadneo_devdata *xdata, unsigned int code, int value) { - unsigned int offset = 0; +static inline s32 scale_axis(s32 value, s32 zone) { + if (abs(value) < zone) { + value = 0; + } else { + s32 cleaned = (value < 0 ? value + zone : value - zone); + s32 scaled = 32767 * cleaned / (32767 - zone); + value = clamp(scaled, -32768, 32767); + } + return value; +} + +static void xpadneo_report_abs(struct xpadneo_devdata *xdata, unsigned int code, s32 value) { + s32 offset = 0; + static u32 deadzone = 2560; switch (code) { case ABS_X: @@ -972,18 +984,22 @@ static void xpadneo_report_abs(struct xpadneo_devdata *xdata, unsigned int code, switch (code) { case ABS_X: xdata->abs.x = value; + value = scale_axis(value, deadzone); break; case ABS_Y: xdata->abs.y = value; + value = scale_axis(value, deadzone); break; case ABS_Z: xdata->abs.z = value; break; case ABS_RX: xdata->abs.rx = value; + value = scale_axis(value, deadzone); break; case ABS_RY: xdata->abs.ry = value; + value = scale_axis(value, deadzone); break; case ABS_RZ: xdata->abs.rz = value;