Receive Joystick events when window is unfocused

Hi

I’m writing an application that needs to react to button inputs from a controller (which presents as a joystick via SDL2), while it is also being used by another (third-party) application. This works in principle, however as soon as I open a window, my application only receives events while that window is in focus. I suspect they are being filtered by SDL2 internally somehow. Is there any way to change this behaviour and always receive all joystick events? I only need this to work on Linux.

For reference, I’ll paste my test code below. The program opens all connected joysticks, prints a line whenever a button is pressed or depressed, and quits when the last joystick is disconnected. When compiled and run with argument “window”, it opens a window, and only receives joystick button events while the window is in focus. Otherwise, it doesn’t open a window and always receives events.

#include <stdio.h>
#include <stdlib.h>
#include <SDL2/SDL.h>

int main(int argc, char *argv[]) {
  atexit(SDL_Quit);
  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) != 0) {
    return EXIT_FAILURE;
  }
  SDL_DisableScreenSaver();
  int open_window = (argc == 2) && (strcmp(argv[1], "window") == 0);
  SDL_Window *window = NULL;
  SDL_Renderer *renderer = NULL;
  if (open_window) {
    window = SDL_CreateWindow("window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 360, 0);
    if (!window) {
      return EXIT_FAILURE;
    }
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
    if (!renderer) {
      return EXIT_FAILURE;
    }
  }

  int done = 0;
  while (!done) {
    if (open_window) {
      SDL_RenderClear(renderer);
      SDL_RenderPresent(renderer);
    }
    else {
      SDL_Delay(16); // ms
    }
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
      switch (event.type) {
      case SDL_JOYDEVICEADDED:
        SDL_Joystick *controller = SDL_JoystickOpen(event.jdevice.which);
        if (!controller) {
          fprintf(stderr, "Couldn't open controller: %s\n", SDL_GetError());
          return EXIT_FAILURE;
        }
        printf("Controller %d added\n", SDL_JoystickInstanceID(controller));
        break;
      case SDL_JOYDEVICEREMOVED:
        printf("Controller %d removed\n", event.jdevice.which);
        if (SDL_NumJoysticks() == 0) {
          done = 1;
        }
        break;
      case SDL_JOYBUTTONDOWN:
        printf("controller %d button %d down\n", event.jbutton.which, event.jbutton.button);
        break;
      case SDL_JOYBUTTONUP:
        printf("controller %d button %d up\n", event.jbutton.which, event.jbutton.button);
        break;
      case SDL_KEYDOWN:
        printf("key down event\n");
        if (event.key.keysym.sym == SDLK_ESCAPE) {
          done = 1;
        }
        break;
      default:
        break;
      }
    }
  }
}

https://wiki.libsdl.org/SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS should help
use it like: SDL_SetHint( SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1" );

1 Like

That works. Thank you!