pj5085
It occurred to me that my simple patch that comments out a few lines of code does not correctly remove the dead zone since the calculation presumably assumes the dead zone has been cut out of the range. Then, while looking into how to make it output the correct range of values, I realized SDL wasn't returning the correct range of values to begin with.
This line of code was already present:
printf("Values = { %d, %d, %d, %d, %d }\n", absinfo.value, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat);
For my joystick this yeilds:
Values = { 0, -127, 127, 0, 15 }
Then this code calculates the coefficients:
In SDL1:
joystick->hwdata->abs_correct[i].coef[0] = (absinfo.maximum + absinfo.minimum) / 2 - absinfo.flat;
joystick->hwdata->abs_correct[i].coef[1] = (absinfo.maximum + absinfo.minimum) / 2 + absinfo.flat;
t = ((absinfo.maximum - absinfo.minimum) / 2 - 2 * absinfo.flat);
if ( t != 0 ) {
joystick->hwdata->abs_correct[i].coef[2] = (1 << 29) / t;
} else {
joystick->hwdata->abs_correct[i].coef[2] = 0;
}
In SDL2:
joystick->hwdata->abs_correct[i].coef[0] = (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
joystick->hwdata->abs_correct[i].coef[1] = (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
if (t != 0) {
joystick->hwdata->abs_correct[i].coef[2] = (1 << 28) / t;
} else {
joystick->hwdata->abs_correct[i].coef[2] = 0;
}
Neither calculates the correct coefficients for the code in the AxisCorrect function.
In SDL1:
if ( value > correct->coef[0] ) {
if ( value < correct->coef[1] ) {
return 0;
}
value -= correct->coef[1];
} else {
value -= correct->coef[0];
}
value *= correct->coef[2];
value >>= 14;
In SDL2:
value *= 2;
if (value > correct->coef[0]) {
if (value < correct->coef[1]) {
return 0;
}
value -= correct->coef[1];
} else {
value -= correct->coef[0];
}
In SDL1, the calculated coefficients are coef[0]=15, coef[1]=-15 and coef[2]=5534751. So with a full-scale input of 127, it calculates an output value of 37835, which is considerably out of range.
In SDL2, the calculated coefficients are coef[0]=30, coef[1]=-30, and coef[2]=1383687. So with a full-scale input of 127, it calculates the same output value of 37835.
I tested it with the 3 joysticks I have, and it produces out-of-range values for all of them.
Anyway, since dead zones are garbage, I just deleted all of that junk and wrote some code that takes the absinfo.minimum and absinfo.maximum values and uses them to scale the axis range to -32767 through +32767.
I also made it detect when a range doesn't have an integer center point, e.g. the center of -128 to + 127 is -0.5. In such cases, if either value to the side of the center is provided, it zeros it, but it otherwise doesn't implement any kind of dead zone. This seemed important with my gamepad which provides only the values of 0, 127, and 255, since without this hack it would never be centered.
Also, the previous minimum output value was -32768, but as that creates an output range that has no true center, I changed the minimum value to -32767.
I tested it with the 3 joystick devices I have and it seems to create correct values for all of them.
Added a hint to control whether a separate thread should be used for joystick events.
This is off by default because dispatching messages in other threads appears to cause problems on some versions of Windows.
Joel Linn
TLDR; https://godbolt.org/z/43fd8G
Let's deduce this from C++ reference code:
https://docs.microsoft.com/en-us/cpp/cppcx/wrl/how-to-activate-and-use-a-windows-runtime-component-using-wrl?view=msvc-160
At the bottom of the page there is this snippet:
```
int wmain()
{
/* ... more code ... */
// Get the domain part of the URI.
HString domainName;
hr = uri->get_Domain(domainName.GetAddressOf());
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Print the domain name and return.
wprintf_s(L"Domain name: %s\n", domainName.GetRawBuffer(nullptr));
// All smart pointers and RAII objects go out of scope here.
}
```
`HString` is defined in `corewrappers.h` and the call chain for the destructor is:
`~HString() -> Release() -> ::WindowsDeleteString()`
QED
Joel Linn
Eliminate additional heap allocation for short-lived HSTRINGs.
Uses `WindowsCreateStringReference()` to disable reference counting and memory management by the Window Runtime.
This can happen if the application has not yet processed SDL_JOYDEVICEADD when
the same joystick is removed. It may also happen if two joysticks are added
and the second joystick is removed before the first joystick's SDL_JOYDEVICEADD
has been processed by the application.
Joel Linn
Currently the rawinput driver always reports a device as "wired". This changes that to "unknown" and updates it once the device is correlated with xinput.
Most of the raw input events are dispatched in the main windows message loop. We only dispatch device change messages separately when we need them to be completely up to date.
src/joystick/windows/SDL_rawinputjoystick.c: In function 'RAWINPUT_HandleStatePacket':
src/joystick/windows/SDL_rawinputjoystick.c:1343:9: warning: suggest explicit braces to avoid ambiguous 'else'