Focus changes cause gamepad "button up" events

I’m a new sdl user, I’m using it as a replacement for xinput (windows) to support non-xbox controllers on a background autohotkey2 automation script.
I’m using sdl through interop features of ahk, I translate some gamepad chords into keyboards actions to control the shell with a controller. One of the main task I require is switching between programs in the shell (Alt-tabbing), but every time the keyboard action is executed, I receive spurious “button up” events for all buttons pressed at that moment. Other actions which do not affect the window focus work fine.

I’m aware of the many threads around the internet discussing background gamepad/joystick handling, but in my case I receive button events even without the SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS hint, regardless of the window with focus.
The script is ran by an interpreter which has no visible window (just a tray icon), so I’m also using SDL_HINT_JOYSTICK_THREAD; this hint makes no difference either.
I’m calling all SDL_SetHint() before initialization for good measure, and I’m checking actual hint values with SDL_GetHint().

Every action which causes a focus change (switching window, interacting with the shell) has the same effect, the issue is not with “Alt tab” specifically. I’m doing my test with a “XBox series” bluetooth controller.

I’m fairly experienced in C programming (both Windows and Linux), but not with SDL. The documentation “wiki” is very sparse.

I’m trying to keep this question out of the autohotkey realm, because it doesn’t do much other than calling native SDL functions, it’s a pretty basic event polling loop. I’ll post just a small snippet for now:

controllers := Map()
SDL2 := SDL2DLL()
SDL2.SDL_SetHint("SDL_JOYSTICK_THREAD", "1")
SDL2.SDL_SetHint("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1")
;SDL2.SDL_SetHint("SDL_JOYSTICK_RAWINPUT", "1")
SDL2.SDL_Init(SDL_INIT_GAMECONTROLLER := 0x00002000)
joystickTest()
SDL2.SDL_Quit()
return

joystickTest() {
    SDL2.SDL_JoystickEventState(true)

    loop SDL2.SDL_NumJoysticks() {
        openController(A_index - 1)
    }

    ;AHK doesn't support union, need Buffer to receive SDL_Event
    evtBuffer := Buffer(56, 0)
    homeButton := false
    taskSwitching := false
    OutputDebug("JOYSTICK_ALLOW_BACKGROUND_EVENTS=" SDL2.SDL_GetHint("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"))
    OutputDebug("JOYSTICK_THREAD=" SDL2.SDL_GetHint("SDL_JOYSTICK_THREAD"))
    loop {
        PollEvent := SDL2.SDL_PollEvent(evtBuffer)
        evt := SDL2DLL.SDL_Event(evtBuffer)

        if (PollEvent = 0) {
            continue
        }
        switch (evt.type) {
            case SDL_EventType.SDL_CONTROLLERBUTTONDOWN, SDL_EventType.SDL_CONTROLLERBUTTONUP:
                ToolTip(SDL2.SDL_JoystickNameForIndex(controllers[evt.cbutton.which].index) "`nButton: " evt.cbutton.button "`nPressState: " evt.cbutton.state "`nEvent: " evt.type)
                switch (evt.cbutton.button) {
                    case SDL_EventType.SDL_CONTROLLER_BUTTON_BACK:
                        backButton := (evt.type = SDL_EventType.SDL_CONTROLLERBUTTONDOWN)
                        OutputDebug("back " (evt.type = SDL_EventType.SDL_CONTROLLERBUTTONDOWN ? "down" : "up"))

I’m using SDL2 vers. 2.30.1, on Windows. Can anyone reproduce? Is this expected?

Looks like your code is truncated. Could you post a complete example?

Yes, here it is: GitHub - Lucide/ahkSDL.
Contains: an example script, a thin SDL2 ahk wrapper, a SDL2 .dll binary

I could perhaps open a github issue?

Sorry, the gamepad search took me a while :grin:. I have not been able to reproduce your problem, no matter how much I switch between windows I can’t notice that an event button up is being sent.

1 Like

Thank you so much for your report! In the meantime I’ve been able to test a non-xbox wireless controller (a chinese controller acting as a DS4 controller), and indeed, the issue doesn’t occur. I’m aware that new xbox controllers behave strangely when there’s no window involved. (In fact, even AHK documentation mentions this: /docs/v2/misc/RemapController.htm#imp).
The problem is not present when using xinput tho. As I wrote before, the previous implementation of my script used the xinput library.

This should be the reason why SDL_HINT_JOYSTICK_THREAD exists.
The problem is mentioned in this and this issues:

The raw input backend requires a windows message pump active in order to receive input events.

If you’re not using SDL video support, you can enable a standalone joystick message pump with:

SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1");

If you’d rather not use the raw input controller driver, you can disable it with:

SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");

I’m using the SDL_HINT_JOYSTICK_THREAD hint (directly, as the “SDL_JOYSTICK_THREAD” string), but it’s not working.

edit: Focus changes cause gamepad "button up" events - #3

Your post was flagged as spam: the community feels it is an advertisement, something that is overly promotional in nature instead of being useful or relevant to the topic as expected.

This post was hidden due to flags from the community, …

what is going on here ? ?

I solved by disabling the SDL_JOYSTICK_RAWINPUT hint:

SDL2.SDL_SetHint("SDL_JOYSTICK_RAWINPUT", "0")
; SDL2.SDL_SetHint("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1")
SDL2.SDL_Init(SDL_INIT_GAMECONTROLLER := 0x00002000)
/**
 * A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices.
 *
 * The variable can be set to the following values:
 *   "0"       - RAWINPUT drivers are not used.
 *   "1"       - RAWINPUT drivers are used. (default)
 *
 * This hint should be set before SDL is initialized.
 */
#define SDL_HINT_JOYSTICK_RAWINPUT "SDL_JOYSTICK_RAWINPUT"

I do not know what that hint is supposed to do. As I noted before, the SDL_JOYSTICK_RAWINPUT hint doesn’t seem to be required in my case. That might be an effect of how ahk script are executed. I don’t know.

Interestingly enough, the gamepad is indeed working in the background with only that one hint, but not when a “system?” window has the focus. (task manager, event viewer, task scheduler, ecc).

This could be some security feature in ahk, sdl or windows itself.

This is a well-known Windows security feature called “Secure Desktop”.

1 Like

Huh, checks out. thanks.
Running the script as admin was sufficient and acceptable in my use case.