Opening a game controller

2014-08-06 21:15 GMT-03:00, Robotic-Brain :

Maybe my knowledge there is a bit outdated (I’ve been digging too much
trough the X protocol, which maintains a lot of the old stuff for
compatibility)

Oh, yeah I get it. Remember that X was created in a time where
computers weren’t exactly standarized in any form (PCs were just
starting to appear, and mainframes wouldn’t use PC hardware for a
looooong time). Of course it supports all sort of weird stuff,
practically nothing could be guaranteed.

On modern hardware this is never going to happen, so yeah, it’s safe
to assume scancodes are stable these days.

The point of the API is to provide a layer of abstraction to the raw
events so you can simply remap them!
The fact that it recognizes some “standard” devices is only an extra bit
of sugar - not the whole purpose :wink:

But if I had to read the joystick values to get those mappings anyway,
why not just use the joystick API? :S

I don’t find it surprising at all…
In fact I also have/had some cheap no-name controller

The branded ones from Microsoft are simply too expensive and I like the
playstation layout better anyways :wink:

Playstation controllers are pretty much the same as the 360 one
layout-wise, though (mappings are completely different, but the same
buttons and such are there). You can use them with the game controller
API without much problem. Many cheap controllers are modelled after
those too.

Generally controllers with a different layout are designed with
specific purposes, e.g. retro-styled controllers being made to be used
with retro-styled games, or controllers made specifically for things
like flight simulators, etc.

Well you’re breaking the opacity of SDL_JoystickGUID with your code

hm… maybe that’s your issue?
The GUID of a XInput device seems to be “xinput” but your code expects
some raw numerical data

Do you violate the opacity somewhere else?
Maybe the presence of a XInput device causes some malicious buffer
overflow or other non deterministic havoc

Well, SDL isn’t doing a very good job of making it opaque either (the
function returns the structure directly, not a pointer or something
like that). Also if the idea was to make it opaque, it would have
probably made more sense to just return the string directly.

The GUID value seems to be pretty much just those 16 bytes the code is
retrieving, so unless the function that turns it into a string
considers it a special case and outputs “XInput” (which wouldn’t be a
valid GUID value, honestly), I don’t see how it could be wrong. And
anyway, this is just for debugging what’s going on.

But if I had to read the joystick values to get those mappings anyway,
why not just use the joystick API? :S

No one “forces” you to use the API. I guess it seemed to be a good idea
to include it in SDL since it reduces code duplication. You can write
your own input abstraction layer if you want though.

Well, SDL isn’t doing a very good job of making it opaque either (the
function returns the structure directly, not a pointer or something
like that). Also if the idea was to make it opaque, it would have
probably made more sense to just return the string directly.

if you return the string directly, it isn’t opaque anymore :wink:
you got a good point about it not being a pointer though…
I guess this is an oversight (The controller API seems to be pretty new
and WIP - if you believe the “Draft” notice on the wiki)

The GUID value seems to be pretty much just those 16 bytes the code is
retrieving, so unless the function that turns it into a string
considers it a special case and outputs “XInput” (which wouldn’t be a
valid GUID value, honestly), I don’t see how it could be wrong. And
anyway, this is just for debugging what’s going on.

“xinput” actually is a magic value for all XInput devices. I don’t know
how this is implemented though. From SDL_gamecontroller.h:

  • Where GUID is the string value from SDL_JoystickGetGUIDString(),
    name is the human readable string for the device and mappings are
    controller mappings to joystick ones.
  • Under Windows there is a reserved GUID of “xinput” that covers any
    XInput devices.

Well, SDL isn’t doing a very good job of making it opaque either (the
function returns the structure directly, not a pointer or something
like that). Also if the idea was to make it opaque, it would have
probably made more sense to just return the string directly.

if you return the string directly, it isn’t opaque anymore :wink:
you got a good point about it not being a pointer though…
I guess this is an oversight (The controller API seems to be pretty
new and WIP - if you believe the “Draft” notice on the wiki)

On an after thought…
It being a pointer would mean SDL must handle its memory!
That would just get really messy for a temporary type like that.
So I think non ABI-compatible opaqueness is fine here :wink:

OK, looked up my MinGW-w64 install to be sure, and there’s this:

/usr/i686-w32-mingw64/include/xinput.h
/usr/i686-w32-mingw64/lib/libxinput1_1.a
/usr/i686-w32-mingw64/lib/libxinput1_2.a
/usr/i686-w32-mingw64/lib/libxinput1_3.a
/usr/i686-w32-mingw64/lib/libxinput1_4.a
/usr/i686-w32-mingw64/lib/libxinput9_1_0.a
/usr/i686-w32-mingw64/lib/libxinput.a

So yeah, XInput definitely is there. I reran configure just to see
what it’s detecting and apparently it doesn’t even mention XInput. As
in, it isn’t even trying to detect it. Huh? Is that normal?

2014-08-06 22:14 GMT-03:00, Robotic-Brain :

if you return the string directly, it isn’t opaque anymore :wink:

I meant something like SDL_JoystickGetGUIDString, which writes to a
buffer the program provides :stuck_out_tongue:

you got a good point about it not being a pointer though…
I guess this is an oversight (The controller API seems to be pretty new
and WIP - if you believe the “Draft” notice on the wiki)

The GUID function is part of the joystick API though, which is
inherited from SDL 1.2 (it’s the API that saw the least amount of
changes). No idea how new is that specific function, though.

“xinput” actually is a magic value for all XInput devices. I don’t know
how this is implemented though. From SDL_gamecontroller.h:

  • Where GUID is the string value from SDL_JoystickGetGUIDString(),
    name is the human readable string for the device and mappings are
    controller mappings to joystick ones.
  • Under Windows there is a reserved GUID of “xinput” that covers any
    XInput devices.

I looked up and there’s code that indeed sets “XInput” as a GUID
(followed by a byte indicating the device). That same code seems to
also clear the GUID to zeroes on a certain condition, so maybe
that’s what’s going on?

AddXInputDevice
src/joystick/windows/SDL_xinputjoystick.c------------------------------------------------------------
pNewJoystick->bXInputDevice = SDL_TRUE;
if (SDL_XInputUseOldJoystickMapping()) {
SDL_zero(pNewJoystick->guid);
} else {
pNewJoystick->guid.data[0] = ‘x’;
pNewJoystick->guid.data[1] = ‘i’;
pNewJoystick->guid.data[2] = ‘n’;
pNewJoystick->guid.data[3] = ‘p’;
pNewJoystick->guid.data[4] = ‘u’;
pNewJoystick->guid.data[5] = ‘t’;
pNewJoystick->guid.data[6] = SubType;
}
pNewJoystick->SubType = SubType;
pNewJoystick->XInputUserId = userid;
SDL_SYS_AddJoystickDevice(pNewJoystick);

Where SDL_XInputUseOldJoystickMapping seems to rely on, um… a hint?


static SDL_bool
SDL_XInputUseOldJoystickMapping()
{
static int s_XInputUseOldJoystickMapping = -1;
if (s_XInputUseOldJoystickMapping < 0) {
const char *hint =
SDL_GetHint(SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING);
s_XInputUseOldJoystickMapping = (hint && *hint == ‘1’) ? 1 : 0;
}
return (s_XInputUseOldJoystickMapping > 0);
}

I’ll try seeing what happens if I override the hint but that seems odd.

2014-08-06 22:29 GMT-03:00, Robotic-Brain :

On an after thought…
It being a pointer would mean SDL must handle its memory!
That would just get really messy for a temporary type like that.
So I think non ABI-compatible opaqueness is fine here :wink:

There’s always the “write data to a buffer” idea like
SDL_JoystickGetGUIDString is doing currently :stuck_out_tongue:

Welp, the hint does nothing in either setting…

Tried to retrieve SDL_XINPUT_ENABLED and
SDL_XINPUT_USE_OLD_JOYSTICK_MAPPING with SDL_GetHint (after
initialization, of course) and both give me null. Huh? Isn’t SDL
supposed to give them default values? Or does this mean XInput code is
not working? (and even if it wasn’t, why is the GUID lost?)

Triple posting but oh well.

It just hit me: what happens if you try to retrieve the GUID of a 360
controller with DirectInput under Windows 8? Ideally both from a
32-bit and a 64-bit program. Starting to think that maybe Microsoft
broke something (and this would mean that SDL would need to find
another way to detect XInput joysticks if it’s true).

I have no Windows dev-environment setup (or any experience with windows
at all for that matter xD)

Your code looks to be correct…
maybe this test program shows, what’s going on…
If you plug in your device, you should see some diagnostics printed
This program does not open any devices and does the maximum amount of
error checking/reporting

Warning: code might be ugly :stuck_out_tongue:

???

/*

  • main.c*
  • Created on: 07.08.2014
  •  Author: Robotic-Brain
    

*/

#include <stdlib.h>
#include <stdio.h>

#include <SDL.h>

void quit(int code) attribute((noreturn));
void quit(int code) {
SDL_Quit();
exit(code);
}

int initSDL() {
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
printf(“SDL_Init Error: %s\n”, SDL_GetError());
return 0;
}

if (SDL_VideoInit(SDL_GetVideoDriver(0)) != 0) {
	printf("SDL_VideoInit Error: %s\n", SDL_GetError());
	return 0;
}

return 1;

}

void printVideoDrivers() {
int num = SDL_GetNumVideoDrivers();
if (num <= 0) {
printf(“SDL_GetNumVideoDrivers Error: %s\n”, SDL_GetError());
} else {
printf(“Video Driver List:\n”);
for (int i = 0; i < num; ++i) {
printf("%d/%d\t%s\n", i + 1, num, SDL_GetVideoDriver(i));
}
}

const char* tmp = SDL_GetCurrentVideoDriver();
if (!tmp) {
	tmp = "NULL";
}
printf("Active Video Driver: %s\n", tmp);

}

void enableEvents() {
if (SDL_JoystickEventState(SDL_ENABLE) < 0) {
printf(“SDL_JoystickEventState Error: %s\n”, SDL_GetError());
}

SDL_GameControllerEventState(SDL_ENABLE);

}

/****************************************************************************************/
/**

  • Pulled in from src/test/SDL_test_common.c
    */
    static const char *
    ControllerAxisName(const SDL_GameControllerAxis axis)
    {
    switch (axis)
    {
    #define AXIS_CASE(ax) case SDL_CONTROLLER_AXIS_##ax: return #ax
    AXIS_CASE(INVALID);
    AXIS_CASE(LEFTX);
    AXIS_CASE(LEFTY);
    AXIS_CASE(RIGHTX);
    AXIS_CASE(RIGHTY);
    AXIS_CASE(TRIGGERLEFT);
    AXIS_CASE(TRIGGERRIGHT);
    #undef AXIS_CASE
    default: return “???”;
    }
    }

static const char *
ControllerButtonName(const SDL_GameControllerButton button)
{
switch (button)
{
#define BUTTON_CASE(btn) case SDL_CONTROLLER_BUTTON_##btn: return #btn
BUTTON_CASE(INVALID);
BUTTON_CASE(A);
BUTTON_CASE(B);
BUTTON_CASE(X);
BUTTON_CASE(Y);
BUTTON_CASE(BACK);
BUTTON_CASE(GUIDE);
BUTTON_CASE(START);
BUTTON_CASE(LEFTSTICK);
BUTTON_CASE(RIGHTSTICK);
BUTTON_CASE(LEFTSHOULDER);
BUTTON_CASE(RIGHTSHOULDER);
BUTTON_CASE(DPAD_UP);
BUTTON_CASE(DPAD_DOWN);
BUTTON_CASE(DPAD_LEFT);
BUTTON_CASE(DPAD_RIGHT);
#undef BUTTON_CASE
default: return “???”;
}
}

static void SDLTest_PrintEvent(SDL_Event * event) {
if ((event->type == SDL_MOUSEMOTION) || (event->type ==
SDL_FINGERMOTION)) {
/* Mouse and finger motion are really spammy */
return;
}

switch (event->type) {
	case SDL_WINDOWEVENT:
		switch (event->window.event) {
			case SDL_WINDOWEVENT_SHOWN:
				SDL_Log("SDL EVENT: Window %d shown",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_HIDDEN:
				SDL_Log("SDL EVENT: Window %d hidden",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_EXPOSED:
				SDL_Log("SDL EVENT: Window %d exposed",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_MOVED:
				SDL_Log("SDL EVENT: Window %d moved to %d,%d",
						event->window.windowID, event->window.data1,
						event->window.data2);
				break;
			case SDL_WINDOWEVENT_RESIZED:
				SDL_Log("SDL EVENT: Window %d resized to %dx%d",
						event->window.windowID, event->window.data1,
						event->window.data2);
				break;
			case SDL_WINDOWEVENT_SIZE_CHANGED:
				SDL_Log("SDL EVENT: Window %d changed size to %dx%d",
						event->window.windowID, event->window.data1,
						event->window.data2);
				break;
			case SDL_WINDOWEVENT_MINIMIZED:
				SDL_Log("SDL EVENT: Window %d minimized",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_MAXIMIZED:
				SDL_Log("SDL EVENT: Window %d maximized",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_RESTORED:
				SDL_Log("SDL EVENT: Window %d restored",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_ENTER:
				SDL_Log("SDL EVENT: Mouse entered window %d",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_LEAVE:
				SDL_Log("SDL EVENT: Mouse left window %d",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_FOCUS_GAINED:
				SDL_Log("SDL EVENT: Window %d gained keyboard focus",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_FOCUS_LOST:
				SDL_Log("SDL EVENT: Window %d lost keyboard focus",
						event->window.windowID);
				break;
			case SDL_WINDOWEVENT_CLOSE:
				SDL_Log("SDL EVENT: Window %d closed",
						event->window.windowID);
				break;
			default:
				SDL_Log("SDL EVENT: Window %d got unknown event %d",
						event->window.windowID, event->window.event);
				break;
		}
		break;
	case SDL_KEYDOWN:
		SDL_Log(
				"SDL EVENT: Keyboard: key pressed  in window %d: scancode 0x%08X = 

%s, keycode 0x%08X = %s",
event->key.windowID, event->key.keysym.scancode,
SDL_GetScancodeName(event->key.keysym.scancode),
event->key.keysym.sym,
SDL_GetKeyName(event->key.keysym.sym));
break;
case SDL_KEYUP:
SDL_Log(
“SDL EVENT: Keyboard: key released in window %d: scancode 0x%08X =
%s, keycode 0x%08X = %s”,
event->key.windowID, event->key.keysym.scancode,
SDL_GetScancodeName(event->key.keysym.scancode),
event->key.keysym.sym,
SDL_GetKeyName(event->key.keysym.sym));
break;
case SDL_TEXTINPUT:
SDL_Log(“SDL EVENT: Keyboard: text input “%s” in window %d”,
event->text.text, event->text.windowID);
break;

		/* MOUSE EVENTS REMOVED */

	case SDL_JOYDEVICEADDED:
		SDL_Log("SDL EVENT: Joystick index %d attached",
				event->jdevice.which);
		break;
	case SDL_JOYDEVICEREMOVED:
		SDL_Log("SDL EVENT: Joystick %d removed", event->jdevice.which);
		break;
	case SDL_JOYBALLMOTION:
		SDL_Log("SDL EVENT: Joystick %d: ball %d moved by %d,%d",
				event->jball.which, event->jball.ball, event->jball.xrel,
				event->jball.yrel);
		break;
	case SDL_JOYHATMOTION: {
		const char *position = "UNKNOWN";
		switch (event->jhat.value) {
			case SDL_HAT_CENTERED:
				position = "CENTER";
				break;
			case SDL_HAT_UP:
				position = "UP";
				break;
			case SDL_HAT_RIGHTUP:
				position = "RIGHTUP";
				break;
			case SDL_HAT_RIGHT:
				position = "RIGHT";
				break;
			case SDL_HAT_RIGHTDOWN:
				position = "RIGHTDOWN";
				break;
			case SDL_HAT_DOWN:
				position = "DOWN";
				break;
			case SDL_HAT_LEFTDOWN:
				position = "LEFTDOWN";
				break;
			case SDL_HAT_LEFT:
				position = "LEFT";
				break;
			case SDL_HAT_LEFTUP:
				position = "LEFTUP";
				break;
		}
		SDL_Log("SDL EVENT: Joystick %d: hat %d moved to %s",
				event->jhat.which, event->jhat.hat, position);
	}
		break;
	case SDL_JOYBUTTONDOWN:
		SDL_Log("SDL EVENT: Joystick %d: button %d pressed",
				event->jbutton.which, event->jbutton.button);
		break;
	case SDL_JOYBUTTONUP:
		SDL_Log("SDL EVENT: Joystick %d: button %d released",
				event->jbutton.which, event->jbutton.button);
		break;
	case SDL_CONTROLLERDEVICEADDED:
		SDL_Log("SDL EVENT: Controller index %d attached",
				event->cdevice.which);
		break;
	case SDL_CONTROLLERDEVICEREMOVED:
		SDL_Log("SDL EVENT: Controller %d removed", event->cdevice.which);
		break;
	case SDL_CONTROLLERAXISMOTION:
		SDL_Log("SDL EVENT: Controller %d axis %d ('%s') value: %d",
				event->caxis.which, event->caxis.axis,
				ControllerAxisName(
						(SDL_GameControllerAxis) event->caxis.axis),
				event->caxis.value);
		break;
	case SDL_CONTROLLERBUTTONDOWN:
		SDL_Log("SDL EVENT: Controller %d button %d ('%s') down",
				event->cbutton.which, event->cbutton.button,
				ControllerButtonName(
						(SDL_GameControllerButton) event->cbutton.button));
		break;
	case SDL_CONTROLLERBUTTONUP:
		SDL_Log("SDL EVENT: Controller %d button %d ('%s') up",
				event->cbutton.which, event->cbutton.button,
				ControllerButtonName(
						(SDL_GameControllerButton) event->cbutton.button));
		break;
	case SDL_CLIPBOARDUPDATE:
		SDL_Log("SDL EVENT: Clipboard updated");
		break;

	case SDL_FINGERDOWN:
	case SDL_FINGERUP:
		SDL_Log(
				"SDL EVENT: Finger: %s touch=%ld, finger=%ld, x=%f, y=%f, dx=%f, 

dy=%f, pressure=%f",
(event->type == SDL_FINGERDOWN) ? “down” : “up”,
(long) event->tfinger.touchId,
(long) event->tfinger.fingerId, event->tfinger.x,
event->tfinger.y, event->tfinger.dx, event->tfinger.dy,
event->tfinger.pressure);
break;

		/* CODE REMOVED */

	case SDL_QUIT:
		SDL_Log("SDL EVENT: Quit requested");
		break;
	case SDL_USEREVENT:
		SDL_Log("SDL EVENT: User event %d", event->user.code);
		break;
	default:
		SDL_Log("Unknown event %d", event->type);
		break;
}

}

/****************************************************************************************/

#define BUFF_LEN 128
void diagnoseJoyDevice(Sint32 index) {
int numj = SDL_NumJoysticks();
printf(“Diagnosing JoyDevice with index: %d Num: %d:\n”, index, numj);
if (numj < 0) {
printf("\t\tSDL_NumJoysticks Error: %s\n", SDL_GetError());
}

{
	/* DeviceGUID */
	char buff[BUFF_LEN];
	SDL_memset(buff, 0, BUFF_LEN);
	SDL_ClearError();
	SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(index), buff, 

BUFF_LEN);
printf("\tGUID: %s\n\t\tError?: %s\n", buff, SDL_GetError());
}

{
	/* Device Name */
	const char* tmp = SDL_JoystickNameForIndex(index);
	printf("\tJoystick Name: ");
	if (!tmp) {
		printf("\n\t\tERROR: %s\n", SDL_GetError());
	} else {
		printf("%s\n", tmp);
	}
}

{
	/* GameController supported? */
	printf("\tIsGameController?: %s\n", (SDL_IsGameController(index) ? 

“TRUE” : “FALSE”));
if (SDL_IsGameController(index)) {
/* GameController Name /
const char
tmp = SDL_GameControllerNameForIndex(index);
printf("\tController Name: %s\n", (tmp ? tmp : “NULL”));
}
}
}

void doLoop() {
int done = 0;

SDL_Event e;
while (!done) {
	if (SDL_WaitEvent(&e)) {
		SDLTest_PrintEvent(&e);
		switch (e.type) {
			case SDL_QUIT:
				done = 1;
				break;

			case SDL_JOYDEVICEADDED:
				printf("-> SDL_JOYDEVICEADDED\n");
				diagnoseJoyDevice(e.jdevice.which);
				break;

			case SDL_CONTROLLERDEVICEADDED:
				printf("-> SDL_CONTROLLERDEVICEADDED\n");
				diagnoseJoyDevice(e.cdevice.which);
				break;

			case SDL_CONTROLLERDEVICEREMAPPED:
				printf("<-> SDL_CONTROLLERDEVICEREMAPPED\n");
				diagnoseJoyDevice(e.cdevice.which);
				break;

			case SDL_JOYDEVICEREMOVED:
				printf("<- SDL_JOYDEVICEREMOVED\n");
				break;

			case SDL_CONTROLLERDEVICEREMOVED:
				printf("<- SDL_CONTROLLERDEVICEREMOVED\n");
				break;
		}
	} else {
		printf("SDL_WaitEvent Error: %s\n", SDL_GetError());
	}
}

}

int main(int argc, char** argv) {

if (!initSDL()) {
	quit(EXIT_FAILURE);
}

//SDL_LogSetAllPriority(SDL_LOG_PRIORITY_WARN);
SDL_Window* wnd = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED,
		SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL);
if (!wnd) {
	printf("Window creation failed: %s", SDL_GetError());
	quit(EXIT_FAILURE);
}

printVideoDrivers();
enableEvents();

doLoop();

SDL_DestroyWindow(wnd);
quit(EXIT_SUCCESS);

}

2014-08-07 17:56 GMT-03:00, Robotic-Brain :

I have no Windows dev-environment setup (or any experience with windows
at all for that matter xD)

Your code looks to be correct…
maybe this test program shows, what’s going on…
If you plug in your device, you should see some diagnostics printed
This program does not open any devices and does the maximum amount of
error checking/reporting

Warning: code might be ugly :stuck_out_tongue:

This happened:

Doesn’t seem to react to the controller at all. Also event 770
happened when clicking the console window (no, not the test window),
huh. That’s a first.

Anyway, this is what I found out so far:

  • Forget what I said about Windows 8, it also happens on Windows 7 :confused:

  • I checked all the inputs from the controller, and it turns out that
    LT and RT are separate axes, which implies XInput is indeed working
    (otherwise they’d get mapped to the same axis, thanks to a tactic from
    Microsoft to discourage developers from using DirectInput).

The implication seems to be that everything is working fine except for
the GUID getting zeroed out (which as a side effect results in the
game controller API being unable to get the mappings because it relies
on the GUID). So it seems that what we need to look for is why SDL is
not filling in the GUID field properly.

For the record, I have been trying to come up with a workaround by
creating a mapping for the zeroed out GUID (and then ignoring the
mappings if the joystick name doesn’t match the XInput controller).
Now it seems to be opening the game controller but I’m not getting any
game controller events :frowning: Am I missing anything?

This is how I’m adding the mapping btw (check if there’s some syntax
error or something):------------------------------------------------------------
SDL_GameControllerAddMapping(
“00000000000000000000000000000000,”
“XInput Controller,”
“dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,”
“a:b10,b:b11,x:b12,y:b13,”
“leftshoulder:b8,rightshoulder:b9,”
“lefttrigger:a4,righttrigger:a5,”
“leftx:a0,lefty:a1,rightx:a2,righty:a3,”
“leftstick:b6,rightstick:b7,”
“start:b4,back:b5”
);

And this is how I do the name-based filtering:

const uint8_t zero_guid[16] = { 0 };
if (memcmp(guid.data, zero_guid, 16) == 0 &&
strncmp(SDL_JoystickName(joysticks[id].joystick), “XInput”, 6) != 0) {
joysticks[id].controller = NULL;
return;
}

// Get controller mappings, if they’re available
joysticks[id].controller = SDL_GameControllerOpen(index);
if (joysticks[id].controller != NULL) {

This happened:
http://i.imgur.com/kJ46XP6.png

Doesn’t seem to react to the controller at all.

So it works… kind of…
The code doesn’t open the controller so it can’t react to events.
It detects it as a valid controller though (so it has to have a mapping
for it)

only the GUID of NULL confuses me since it’s not reporting any error
Maybe that is the magic value for XInput?

Also event 770 happened when clicking the console window (no, not the
test window),
huh. That’s a first.

No idea what that means, but it shouldn’t affect anything - I hope

Let’s check the mapping…
Open the controller in the SDL_CONTROLLERDEVICEADDED case block of
doLoop() like that:Am 07.08.2014 23:32, schrieb Sik the hedgehog:


case SDL_CONTROLLERDEVICEADDED:
printf("-> SDL_CONTROLLERDEVICEADDED\n");
diagnoseJoyDevice(e.cdevice.which);

  •   			if (!SDL_GameControllerOpen(e.cdevice.which)) {
    
  •   				printf("\tSDL_GameControllerOpen Error: %s\n", SDL_GetError());
    
  •   			}
      			break;
    

Now it should print the events in the Log

770 is 0x302, which is SDL_TEXTEDITING.On Aug 7, 2014, at 6:32 PM, Sik the hedgehog <sik.the.hedgehog at gmail.com> wrote:

Doesn’t seem to react to the controller at all. Also event 770
happened when clicking the console window (no, not the test window),
huh. That’s a first.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Well, tester is gone now so unless I can find another suitable tester
this will have to wait until tomorrow :confused:

2014-08-07 18:51 GMT-03:00, Robotic-Brain :

It detects it as a valid controller though (so it has to have a mapping
for it)

Yep, I noticed that and it caught my attention too. How come it has a
mapping yet it can’t open it? Huh.

only the GUID of NULL confuses me since it’s not reporting any error
Maybe that is the magic value for XInput?

It is for the case where the legacy method is used (which I mentioned
earlier in this thread). However changing the value of that hint seems
to be doing nothing, so either it’s completely ignoring it for
whatever reason, or it’s something else that’s zeroing out the GUID.

For the record: when I try to retrieve the GUID of the joystick I get
00000000-00000000-00000000-00000000, which definitely doesn’t seem to
be valid. The name is “XInput Controller #1” though, which seems to
imply SDL2 detected it as a 360 controller. Huh?

This code has changed recently, so maybe there’s a bug, but if you’re on
2.0.3 or earlier, X360 controllers will be detected and used through
XInput, but have a zeroed-out GUID like this.

There is some magic that happens elsewhere with a guid of “xinput” …
when you register a mapping with that GUID (which SDL does by default),
it notes that this is the “XInput” mapping, and then, when asked for the
mapping for any guid, it’ll first check with the lower level if this
is in fact an XInput device and use that mapping for it (all of this is
#ifdef’d for Windows, of course).

This is a little messy. Sam has cleaned up most of this recently; in
2.0.4, XInput devices will report that “xinput” GUID to the app, along
with a better mapping, unless you set a hint to force the old zeroed out
GUID and the old mapping.

SO…

If you got a zero GUID, you definitely are talking to the device through
XInput, but perhaps SDL_JOYSTICK_XINPUT isn’t defined in
SDL_gamecontroller.c, where the magic happens? (maybe we screwed this up
at the configure/cmake level and the Visual Studio projects got it right?).

Things to check:

  • Make sure you called SDL_Init(SDL_INIT_GAMECONTROLLER) and not just
    SDL_INIT_JOYSTICK, or this will absolutely not work.
  • Set a breakpoint or printf() or whatever in
    SDL_GameControllerAddMapping() and see if there is one added for a GUID
    of “xinput” … these come from SDL_gamecontrollerdb.h.
  • Set a breakpoint (etc) on SDL_PrivateGetControllerMapping() and see if
    it’s returning s_pXInputMapping in that funky #ifdef.

One of those three things will likely expose the culprit.

–ryan.

–ryan.

2014-08-08 1:15 GMT-03:00, Ryan C. Gordon :

This code has changed recently, so maybe there’s a bug, but if you’re on
2.0.3 or earlier, X360 controllers will be detected and used through
XInput, but have a zeroed-out GUID like this.

…thanks for pointing that out, I just realized I had accidentally
built 2.0.3-8628 (the one from the site) instead of 2.0.3-9008 (the
one from the bug wrap thread). ??? Surprise, now it works perfectly
(though it does imply that the legacy method may be broken, maybe it
should be just outright removed?)

That said:

(maybe we screwed this up
at the configure/cmake level and the Visual Studio projects got it right?).

While this is working, I noticed another issue when rebuilding SDL2:
normally --disable-shared is used to tell configure to not link
against the dynamic libgcc (this is MinGW-w64), but in this case it
tells configure to not build the DLL. Caught me off guard with my
crosscompiler script x_x;