diff render_sdl.c @ 1187:6a4503fad67e

Initial support for using SDL2 game controller mapping functionality
author Michael Pavone <pavone@retrodev.com>
date Sun, 22 Jan 2017 16:23:59 -0800
parents b1147418254a
children 1ad0ec7e3939
line wrap: on
line diff
--- a/render_sdl.c	Sun Jan 22 16:13:02 2017 -0800
+++ b/render_sdl.c	Sun Jan 22 16:23:59 2017 -0800
@@ -111,6 +111,7 @@
 }
 
 static SDL_Joystick * joysticks[MAX_JOYSTICKS];
+static int joystick_sdl_index[MAX_JOYSTICKS];
 
 int render_width()
 {
@@ -271,7 +272,7 @@
 static char *vid_std_names[NUM_VID_STD] = {"ntsc", "pal"};
 void render_init(int width, int height, char * title, uint8_t fullscreen)
 {
-	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) {
+	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
 		fatal_error("Unable to init SDL: %s\n", SDL_GetError());
 	}
 	atexit(SDL_Quit);
@@ -626,6 +627,66 @@
 	return -1;
 }
 
+int32_t render_translate_input_name(int32_t controller, char *name)
+{
+	static tern_node *button_lookup;
+	if (controller > MAX_JOYSTICKS || !joysticks[controller]) {
+		return RENDER_NOT_PLUGGED_IN;
+	}
+	
+	if (!SDL_IsGameController(joystick_sdl_index[controller])) {
+		return RENDER_NOT_MAPPED;
+	}
+	
+	if (!button_lookup) {
+		for (int i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++)
+		{
+			button_lookup = tern_insert_int(button_lookup, SDL_GameControllerGetStringForButton(i), i);
+		}
+		//alternative Playstation-style names
+		button_lookup = tern_insert_int(button_lookup, "cross", SDL_CONTROLLER_BUTTON_A);
+		button_lookup = tern_insert_int(button_lookup, "circle", SDL_CONTROLLER_BUTTON_B);
+		button_lookup = tern_insert_int(button_lookup, "square", SDL_CONTROLLER_BUTTON_X);
+		button_lookup = tern_insert_int(button_lookup, "triangle", SDL_CONTROLLER_BUTTON_Y);
+		button_lookup = tern_insert_int(button_lookup, "share", SDL_CONTROLLER_BUTTON_BACK);
+		button_lookup = tern_insert_int(button_lookup, "select", SDL_CONTROLLER_BUTTON_BACK);
+		button_lookup = tern_insert_int(button_lookup, "options", SDL_CONTROLLER_BUTTON_START);
+		button_lookup = tern_insert_int(button_lookup, "l1", SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
+		button_lookup = tern_insert_int(button_lookup, "r1", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
+	}
+	intptr_t sdl_button = tern_find_int(button_lookup, name, SDL_CONTROLLER_BUTTON_INVALID);
+	if (sdl_button == SDL_CONTROLLER_BUTTON_INVALID) {
+		return RENDER_INVALID_NAME;
+	}
+	SDL_GameController *control = SDL_GameControllerOpen(joystick_sdl_index[controller]);
+	if (!control) {
+		warning("Failed to open game controller %d: %s\n", controller, SDL_GetError());
+		return RENDER_NOT_PLUGGED_IN;
+	}
+	SDL_GameControllerButtonBind cbind = SDL_GameControllerGetBindForButton(control, sdl_button);
+	SDL_GameControllerClose(control);
+	switch (cbind.bindType)
+	{
+	case SDL_CONTROLLER_BINDTYPE_BUTTON:
+		return cbind.value.button;
+	case SDL_CONTROLLER_BINDTYPE_AXIS:
+		return RENDER_AXIS_BIT | cbind.value.axis;
+	case SDL_CONTROLLER_BINDTYPE_HAT:
+		return RENDER_DPAD_BIT | (cbind.value.hat.hat << 4) | cbind.value.hat.hat_mask;
+	}
+	return RENDER_NOT_MAPPED;
+}
+
+int32_t render_dpad_part(int32_t input)
+{
+	return input >> 4 & 0x7FFFFF;
+}
+
+uint8_t render_direction_part(int32_t input)
+{
+	return input & 0xF;
+}
+
 static uint8_t scancode_map[SDL_NUM_SCANCODES] = {
 	[SDL_SCANCODE_A] = 0x1C,
 	[SDL_SCANCODE_B] = 0x32,
@@ -753,6 +814,7 @@
 			int index = lowest_unused_joystick_index();
 			if (index >= 0) {
 				SDL_Joystick * joy = joysticks[index] = SDL_JoystickOpen(event->jdevice.which);
+				joystick_sdl_index[index] = event->jdevice.which;
 				if (joy) {
 					printf("Joystick %d added: %s\n", index, SDL_JoystickName(joy));
 					printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy));