Skip to content

kcms/gamecontroller: Replace SDL Game Controller API with Joystick API

This MR replaces usage of higher-level "Game Controller" API with lower-level "Joystick" API in Game Controller KCM. This fixes the following issues:

This should also fix the following bugs, although I don't have a steering wheel or handbrake to actually test the changes:

Current issues

SDL2 provides two distinct APIs:

  • Joystick API. It basically reports raw values from buttons, axes, POV hats and trackballs. It tells nothing about actual meaning of these values, say that axis 0 is a left analog stick. This kind of API is most suitable for the current implementation of KCM.
  • Game Controller API. This is a higher-level API that automatically recognizes popular gamepads and remaps controls to actual analog sticks, triggers, buttons etc.

For now the KCM uses a mix of Game Controller API and Joystick API. Unfortunately, this results in several bugs:

  1. Non-gamepad devices, such as classic joysticks, steering wheels or handbrakes, are not detected at all. The Game Controller API seems to be limited to standard gamepads only.
  2. The state of some buttons/axes, such as D-pad or right trigger, is not displayed correctly. This happens due to the mismatch between APIs. We grab indices of buttons/axes from Game Controller API but then pass them to Joystick API. This inevitably leads to bugs since different APIs use different numbering of buttons/axes.
  3. D-pad presses are not displayed correctly. Similar to the issue above. Joystick API often exposes D-pad as a joystick POV hat whereas Game Controller API typically remaps D-pad to four regular buttons. Again, this results in bugs due to different number of buttons reported by different APIs.

What does this MR do

The MR tries to sort out all issues by replacing most of usages of Game Controller API with Joystick API. It basically introduces new class Device that encapsulates SDL_Joystick object. Both ButtonModel and AxesModel now use Device object to report raw values from buttons and axes. DeviceModel now manages Device objects and shows them in the combo box. This ensures SDL Joystick API is used consistently across all code and avoids API mismatch issues. This should also properly detect classic joysticks, wheels and handbrakes. Unfortunately I don't have any of these devices and can't really test them. Technically the KCM should properly handle them similar to sdl-jstest app.

The MR also handles the case when D-pad is exposed as a joystick POV hat instead of four regular buttons. It adds a new class HatModel that provides raw position data from POV hats. Each POV hat is mapped to a pair of X/Y model rows. Both axes values and hat positions are now displayed under Axes table using new class AxesProxyModel. Let me know if you want to display POV hats under Buttons table instead.

The purpose of Gamepad class has been changed a bit. Instead of being the central device class, now it only encapsulates SDL_GameController object and provides higher-level access to gamepads. For now it is only used to display the position of left stick in PositionWidget. This is something that cannot be done with plain Joystick API.

Future work

It was proposed to implement two different user interfaces:

  • A "simple" mode which is the default, which shows a symbolic generic game controller (360-style) with buttons that change on controller state changes.
  • An "advanced" mode similar to the current interface (but less reliant on tables), which gives more of a proper info dump including all buttons for users testing more obscure controllers.

This MR is implemented with this proposal in mind. It provides two different classes Gamepad and Device for two different modes. The "Simple" mode should always use Gamepad class (i.e. Game Controller API) while "Advanced" mode should always use Device class (i.e. Joystick API). This way, both modes will operate fully independently and won't conflict with each other.

Edited by Arthur Kasimov

Merge request reports

Loading