1

I'm using the SDL2 event-based joystick API to obtain the positions of the analog joystick axes, and this is mostly working well.

However, SDL2 fails to reliably deliver those positions when the software is starting up. Even when forcing the generation of axis events using SDL_UpdateJoystick(), the corresponding event reports the default position (0) instead of a value reflecting the actual, physical position of the attached stick.

Aside from calling SDL_UpdateJoystick(), I also tried setting the SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS hint prior to initialization, as well as calling SDL_GetJoystickGetAxis(). Stepping into the source code of the latter function, I discovered that it does not actively query the axis position as I expected, but instead reports a stored value.

Through experimentation, I finally came up with a rather ugly hack that seems to "do the trick":

    // My joystick axis querying function

    SDL_JoystickUpdate();
    for (auto i = 0U; i < 100; i ++) {
        SDL_Delay(1);
        SDL_PumpEvents();
    }

    return SDL_JoystickGetAxis((SDL_Joystick*)handle, axis);

I have no idea why this is working or what is going on behind the scenes. I'd be very thankful for a better solution.

UPDATE 2020-09-03: I still do not have a better solution, but I experimented with SDL's source code, specifically the function SDL_DINPUT_JoystickUpdate() in SDL_dinputjoystick.c. If I inject an artifical delay of 50ms between IDirectInputDevice8_Poll() and the call to UpdateDINPUTJoystickState_Buffered(), which in turn calls IDirectInputDevice8_GetDeviceData() to collect the data, I get the correct values. (Unfortunately this cannot be used as a solution, as SDL_DINPUT_JoystickUpdate() is being called constantly.) This would seem to indicate that there is a delay between a call Poll() and the data becoming available.

UPDATE 2020-09-03 #2: I have submitted a tentative (not very satisfactory) patch proposal to SDL's Bugzilla.

JPNotADragon
  • 2,050
  • 2
  • 25
  • 31
  • Why has this question been voted to close ? – JPNotADragon Sep 02 '20 at 14:55
  • Is your joystick a HID device? If so, I'm not even sure it is possible to query current state. What's your OS? Could you read directly from joystick device to see if it sends any data at fixed interval even if no changes happens? – keltar Sep 02 '20 at 16:30
  • @keltar I believe it is. The tool `DIView.exe` displays the correct values. – JPNotADragon Sep 02 '20 at 18:10
  • (@keltar: the OS is Windows 10) – JPNotADragon Sep 02 '20 at 18:27
  • What's joystick GUID reported via SDL (SDL_JoystickGetGUID & SDL_JoystickGetGUIDString)? Could you step through any SDL joystick function to see which implementation it calls for your joystick (there could be multiple, directinput/xinput, hiddev, etc. - judging by "DIView" name it probably uses directinput)? If it isn't directinput, my last idea for now would be recompiling SDL with directinput support instead of xinput and checking how it'll turn out. – keltar Sep 03 '20 at 06:33
  • @keltar: It's definitely DirectInput. Though I don't have the device with me at the moment, I did step into the code; and also, `DIView.exe` is featured on the board's "Product Downloads" section. – JPNotADragon Sep 03 '20 at 08:15
  • @keltar: the behavior is reproduceable with my own joystick; so if you have any ideas, I'll be happy to try them out. – JPNotADragon Sep 03 '20 at 08:55

1 Answers1

2

The issue here is that the buffer tracks changes. if nothing has been touched since init, there are no changes, so we don't know what the initial state is.

UpdateDINPUTJoystickState_Buffered won't update the initial state until a buffered axis change happens.

UpdateDINPUTJoystickState_Polled never gets called, and without this, the initial value never gets set until the joystick is moved and released.

SDL_DINPUT_JoystickUpdate does call IDirectInputDevice8_Poll, so it DOES wake up the device if it happens to need it, but if the joystick has a buffer, it still won't update the initial state on SDL side until there's an axis change. and of course with a hardware deadzone or a fake analog, there isn't one.

The fault is clearly in SDL here, and i can see no obvious solution besides the suggested patch to call IDirectInputDevice8_Poll during init, and sleep for 50 ms to force the device to output it's current state into the buffer.

Mr. Beeblebrox
  • 186
  • 1
  • 5