Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

Fixing gamepad for Wine game

I finally got fed up with Wine's malfunction quite a few months ago about it passing my gamepads to Jazz Jackrabbit 2. For some reason, after a software update, the controllers did not work correctly.

Today, I spent a bunch of time researching how to adjust the mapping of the gamepads. I found a great tool which helped write custom SDL gamepad mapping strings, SDL2 Gamepad Tool by General Arcade. It is an interactive mapping tool where it guides you to press each button on your controller and it generates the right string.

Solution

I never got that string to work correctly with Wine, but I ended up solving my problem by adjusting the Wine registry. I ended up merely setting the key

HKLM\System\CurrentControlSet\Services\WineBus\Map Controllers (REG_DWORD) = 0x0

The relevant snippet from that link.

+->Map Controllers [DWORD value (REG_DWORD): Enable (0x1, default) or disable (0x0) conversion from SDL controllers to XInput-compatible gamepads. Only applies to SDL backend.]

And then, all my buttons worked, and my two-axis dpad worked!

Additional research

I spent quite a while trying to customize the mappings, which didn't seem to stick when I tried them in the Wine registry in a few places.

HKCU\Software\Wine\DirectInput\"Tomee USB SNES Controller" = "X,Y"


HKLM\System\CurrentControlSet\Services\WineBus\Map\"auniquename" = "03000000bd12000015d0000010010000,Tomee SNES USB Controller,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,"

I'm pretty sure Wine doesn't honor the environment variable SDL_GAMECONTROLLERCONFIG, because it wants to use the Registry key above, which actually I never got it to work.

I wrote a little C program by adapting a large number of examples, mostly from the SDL2 documentation.

// File: js1.c
// Startdate: 2022-06-29
// Purpose: Test my C skills, while trying to test SDL2 game controller stuff
// References:
// http://www.libsdl.org/release/SDL-1.2.15/docs/html/guideinput.html
// https://wiki.libsdl.org/SDL_GameControllerMapping
// https://stackoverflow.com/q/29589982
// https://generalarcade.com/gamepadtool/
// https://wiki.winehq.org/Useful_Registry_Keys
// https://wiki.archlinux.org/title/Gamepad
// https://stackoverflow.com/questions/29589982/does-sdl-on-linux-support-more-than-one-gamepad-joystick
// Dependencies:
//    sudo apt-get install libsdl2-dev
// Documentation:
// try SDL_GAMECONTROLLERCONFIG env var.
#include "SDL2/SDL.h"
SDL_Joystick *joy;
SDL_GameController *ctrl;
char *guid[33];
char *mapping;
const char *newmapping = "03000000bd12000015d0000010010000,Tomee SNES USB Controller,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,";
int main () {
   if (SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0)
   {
      fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
      exit(1);
   }
   SDL_InitSubSystem(SDL_INIT_JOYSTICK);
   SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
   printf("%i joysticks were found.\n\n", SDL_NumJoysticks() );
   printf("The names of the joysticks are:\n");
   for( int i=0; i < SDL_NumJoysticks(); i++ )
   {
      joy = SDL_JoystickOpen(i);
        if (joy) {
            printf("Opened joystick #%d \"%s\"\n", i, SDL_JoystickNameForIndex(i));
            printf("Axes count: %d\n", SDL_JoystickNumAxes(joy));
            printf("Button count: %d\n", SDL_JoystickNumButtons(joy));
            printf("Ball count: %d\n", SDL_JoystickNumBalls(joy));
            SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joy),*guid,sizeof(guid));
            printf("GUID string: \"%s\"\n",guid);
            if (SDL_IsGameController(i)) {
                ctrl = SDL_GameControllerOpen(i);
                mapping = SDL_GameControllerMapping(ctrl);
                printf("Mapping: \"%s\"\n", mapping);
                SDL_free(mapping);
                printf("Trying new mapping.\n");
                int r = SDL_GameControllerAddMapping(newmapping);
                printf("Result: %d.\n", r);
            }
        }
   }
   return 0;
}

And a makefile to make it faster to build.

CC=gcc
SRC = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRC))
NAME = js1

all: $(NAME)
.PHONY: clean

$(NAME): $(OBJS)
    $(CC) $(shell pkg-config --cflags sdl2 ) $< $(shell pkg-config --libs sdl2 ) -o $@

clean:
    rm -f $(OBJS) $(NAME)

Comments