libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
9.97k stars 1.84k forks source link

SDL3 joystick axis values sometimes not scaled correctly #11471

Open jtbourke opened 5 hours ago

jtbourke commented 5 hours ago

I'm working on joystick code for a flight simulator. I am testing many joysticks.

Expectations:

What I see is:

Whenever I file bug reports I'm worried I missed something...I did look at the hint defines to see if I could be missing a flag and I browsed through the code but didn't see anything obvious.

slouken commented 4 hours ago

What controllers are giving you which results?

jtbourke commented 4 hours ago

First column is the raw value. Second column is the difference between the current reading and the previous reading.

Logitech Extreme Pro 3D:

This is a 10 bit controller so there are 1024 possible values. I expect each value to be separated by 64 units. Most of the values are spaced out just as expected.

However, you can see that I get a value of 0 and then the next tick I get a value of 1.

-320   128
-256   64
-128   128
-64   64
0   64
1   1
-896   897
-1024   128
-1088   64
-1216   128
-1280   64
-1408   128
-1472   64

SuperSimX:

Now here is output from a SuperSimX controller I found on Amazon, which is honestly a terrible controller, but it better illustrates the other problem, where the values are at odd spacings:

This is an 8-bit controller so I expect the values to be separated by 256 units. instead, they are separated by 260ish.

8583   260
8062   521
7802   260
7542   260
6502   1040
5722   780
5982   260
5722   260
5462   260
4942   520
4682   260
4422   260
4162   260
3902   260
4162   260
3382   780
2862   520
slouken commented 4 hours ago

It looks like for these controllers we are using DirectInput, setting DIPROP_RANGE to the expected axis range, and relying on DirectInput to convert it correctly.

Out of curiosity, what values do you get if you comment out this code to expand the axis range?

        result =
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
                                            DIPROP_RANGE, &diprg.diph);
        if (FAILED(result)) {
            return DIENUM_CONTINUE; // don't use this axis
        }
jtbourke commented 3 hours ago

I commented that code out.

What I saw before was when I moved the stick left, I saw negative values and when I moved the stick right I saw positive values. At the center I saw 0 or 1.

After deleting those lines, the center value bounces between 32767 and -32768. Moving the stick left reduces the value from +32k to 0, and moving the stick right changes the value from -32k to -1 on the rightmost side.

In both cases, all of the values are separated by 64 units as expected, except at the center where the separation is just 1 bit (I assume there is unsigned data being interpreted as signed data in the output where I deleted those lines).

I tried the other controller as well and the separation is still the same at around 260 units.

jtbourke commented 2 hours ago

After further testing, the issue with only 1 unit spacing between values seems present on all controllers. It just isn't obvious with some of them because the values with only 1 unit spacing are not always at center.

With the Turtle Beach VelocityOne Flightstick, I see roughly 32 unit spacing in most of the range except that the values 32 and 33 are both possible:

Current val / diff from previous
-12256   2528
-10112   2144
-7648   2464
-5184   2464
-2816   2368
-576   2240
-1   575
33   34
32   1
1024   992
1440   416
1472   32
1504   32
1536   32
1568   32
1600   32
1632   32
1280   352
480   800
33   447
32   1
-1   33
33   34
65   32
97   32
320   223
352   32

I've tested with a few other controllers and have found the same results with there being exactly one spot in the travel where the spacing is 1 unit. Between all other positions the spacing is roughly dependent on axis resolution.