changeset 1623:18a946ec74c8

Pull current controller config in binding UI from whatever the actual binding code would end up using
author Michael Pavone <pavone@retrodev.com>
date Wed, 24 Oct 2018 21:10:12 -0700
parents 4bb2c8b78b4a
children 7bbe0bfedb58
files bindings.c bindings.h nuklear_ui/blastem_nuklear.c render_sdl.c render_sdl.h
diffstat 5 files changed, 195 insertions(+), 160 deletions(-) [+]
line wrap: on
line diff
--- a/bindings.c	Tue Oct 09 09:29:28 2018 -0700
+++ b/bindings.c	Wed Oct 24 21:10:12 2018 -0700
@@ -857,72 +857,78 @@
 	return mousebuttons;
 }
 
-void handle_joy_added(int joystick)
+tern_node *get_binding_node_for_pad(int padnum)
 {
-	if (joystick > MAX_JOYSTICKS) {
-		return;
+	if (padnum > MAX_JOYSTICKS) {
+		return NULL;
 	}
 	tern_node * pads = tern_find_path(config, "bindings\0pads\0", TVAL_NODE).ptrval;
-	if (pads) {
-		char numstr[11];
-		sprintf(numstr, "%d", joystick);
-		tern_node * pad = tern_find_node(pads, numstr);
-		if (!pad) {
-			char *type_id = render_joystick_type_id(joystick);
-			pad = tern_find_node(pads, type_id);
-			free(type_id);
-		}
-		if (!pad) {
-			controller_info info = get_controller_info(joystick);
-			char *key = make_controller_type_key(&info);
-			pad = tern_find_node(pads, key);
-			free(key);
-		}
-		if (!pad) {
-			pad = tern_find_node(pads, "default");
-		}
-		if (pad) {
-			tern_node * dpad_node = tern_find_node(pad, "dpads");
-			if (dpad_node) {
-				for (int dpad = 0; dpad < 10; dpad++)
-				{
-					numstr[0] = dpad + '0';
-					numstr[1] = 0;
-					tern_node * pad_dpad = tern_find_node(dpad_node, numstr);
-					char * dirs[] = {"up", "down", "left", "right"};
-					//TODO: Support controllers that have d-pads implemented as analog axes or buttons
-					int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
-					for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) {
-						char * target = tern_find_ptr(pad_dpad, dirs[dir]);
-						if (target) {
-							uint8_t subtype_a = 0, subtype_b = 0;
-							int bindtype = parse_binding_target(joystick, target, get_pad_buttons(), get_mouse_buttons(), &subtype_a, &subtype_b);
-							bind_dpad(joystick, dpad, dirnums[dir], bindtype, subtype_a, subtype_b);
-						}
-					}
+	if (!pads) {
+		return NULL;
+	}
+	char numstr[11];
+	sprintf(numstr, "%d", padnum);
+	tern_node * pad = tern_find_node(pads, numstr);
+	if (!pad) {
+		char *type_id = render_joystick_type_id(padnum);
+		pad = tern_find_node(pads, type_id);
+		free(type_id);
+	}
+	if (!pad) {
+		controller_info info = get_controller_info(padnum);
+		char *key = make_controller_type_key(&info);
+		pad = tern_find_node(pads, key);
+		free(key);
+	}
+	if (!pad) {
+		pad = tern_find_node(pads, "default");
+	}
+	return pad;
+}
+
+void handle_joy_added(int joystick)
+{
+	tern_node *pad = get_binding_node_for_pad(joystick);
+	if (!pad) {
+		return;
+	}
+	tern_node * dpad_node = tern_find_node(pad, "dpads");
+	if (dpad_node) {
+		for (int dpad = 0; dpad < 10; dpad++)
+		{
+			char numstr[2] = {dpad + '0', 0};
+			tern_node * pad_dpad = tern_find_node(dpad_node, numstr);
+			char * dirs[] = {"up", "down", "left", "right"};
+			//TODO: Support controllers that have d-pads implemented as analog axes or buttons
+			int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
+			for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) {
+				char * target = tern_find_ptr(pad_dpad, dirs[dir]);
+				if (target) {
+					uint8_t subtype_a = 0, subtype_b = 0;
+					int bindtype = parse_binding_target(joystick, target, get_pad_buttons(), get_mouse_buttons(), &subtype_a, &subtype_b);
+					bind_dpad(joystick, dpad, dirnums[dir], bindtype, subtype_a, subtype_b);
 				}
 			}
-			tern_node *button_node = tern_find_node(pad, "buttons");
-			if (button_node) {
-				pad_button_state state = {
-					.padnum = joystick,
-					.padbuttons = get_pad_buttons(),
-					.mousebuttons = get_mouse_buttons()
-				};
-				tern_foreach(button_node, process_pad_button, &state);
-			}
-			tern_node *axes_node = tern_find_node(pad, "axes");
-			if (axes_node) {
-				pad_button_state state = {
-					.padnum = joystick,
-					.padbuttons = get_pad_buttons(),
-					.mousebuttons = get_mouse_buttons()
-				};
-				tern_foreach(axes_node, process_pad_axis, &state);
-			}
 		}
 	}
-	
+	tern_node *button_node = tern_find_node(pad, "buttons");
+	if (button_node) {
+		pad_button_state state = {
+			.padnum = joystick,
+			.padbuttons = get_pad_buttons(),
+			.mousebuttons = get_mouse_buttons()
+		};
+		tern_foreach(button_node, process_pad_button, &state);
+	}
+	tern_node *axes_node = tern_find_node(pad, "axes");
+	if (axes_node) {
+		pad_button_state state = {
+			.padnum = joystick,
+			.padbuttons = get_pad_buttons(),
+			.mousebuttons = get_mouse_buttons()
+		};
+		tern_foreach(axes_node, process_pad_axis, &state);
+	}
 }
 
 //only handles keyboards and mice as gamepads are handled on hotplug events
--- a/bindings.h	Tue Oct 09 09:29:28 2018 -0700
+++ b/bindings.h	Wed Oct 24 21:10:12 2018 -0700
@@ -11,6 +11,7 @@
 
 void set_bindings(void);
 void bindings_set_mouse_mode(uint8_t mode);
+tern_node *get_binding_node_for_pad(int padnum);
 void handle_keydown(int keycode, uint8_t scancode);
 void handle_keyup(int keycode, uint8_t scancode);
 void handle_joydown(int joystick, int button);
--- a/nuklear_ui/blastem_nuklear.c	Tue Oct 09 09:29:28 2018 -0700
+++ b/nuklear_ui/blastem_nuklear.c	Wed Oct 24 21:10:12 2018 -0700
@@ -15,6 +15,7 @@
 #include "../io.h"
 #include "../png.h"
 #include "../controller_info.h"
+#include "../bindings.h"
 
 static struct nk_context *context;
 
@@ -514,7 +515,7 @@
 #define LEFTSTICK  0x10000000
 #define RIGHTSTICK 0x20000000
 enum {
-	UP,DOWN,LEFT,RIGHT
+	UP,DOWN,RIGHT,LEFT,NUM_AXIS_DIRS
 };
 
 static char * config_ps_names[] = {
@@ -530,71 +531,35 @@
 	[SDL_CONTROLLER_BUTTON_RIGHTSTICK] = "r3",
 };
 
-static void binding_box(struct nk_context *context, char *name, float x, float y, float width, int num_binds, int *binds)
+typedef struct {	
+	const char *button_binds[SDL_CONTROLLER_BUTTON_MAX];
+	const char *left_stick[NUM_AXIS_DIRS];
+	const char *right_stick[NUM_AXIS_DIRS];
+	const char *triggers[2];
+} pad_bind_config;
+
+static void binding_box(struct nk_context *context, pad_bind_config *bindings, char *name, float x, float y, float width, int num_binds, int *binds)
 {
 	const struct nk_user_font *font = context->style.font;
 	float row_height = font->height * 2;
 	
 	char const **labels = calloc(sizeof(char *), num_binds);
-	char **conf_keys = calloc(sizeof(char *), num_binds);
+	char const **conf_vals = calloc(sizeof(char *), num_binds);
 	float max_width = 0.0f;
 	
-	static const char base_path[] = "bindings\0pads";
-	static const char buttons[] = "buttons";
-	static const char dpads[] = "dpads\00";
-	static const char axes[] = "axes";
-	static const char positive[] = ".positive";
-	static const char negative[] = ".negative";
-	char padkey[] = {'0' + selected_controller, 0};
 	int skipped = 0;
 	for (int i = 0; i < num_binds; i++)
 	{
 		if (binds[i] & AXIS) {
 			labels[i] = get_axis_label(&selected_controller_info, binds[i] & ~AXIS);
-			const char *axname = SDL_GameControllerGetStringForAxis(binds[i] & ~AXIS);
-			size_t namelen = strlen(axname);
-			conf_keys[i] = malloc(sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen + 2);
-			memcpy(conf_keys[i], base_path, sizeof(base_path));
-			memcpy(conf_keys[i] + sizeof(base_path), padkey, sizeof(padkey));
-			memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey), axes, sizeof(axes));
-			memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey) + sizeof(axes), axname, namelen+1);
-			conf_keys[i][sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen + 1] = 0;
+			conf_vals[i] = bindings->triggers[(binds[i] & ~AXIS) - SDL_CONTROLLER_AXIS_TRIGGERLEFT];
 		} else if (binds[i] & STICKDIR) {
-			static char const * dirs[] = {"Up", "Down", "Left", "Right"};
+			static char const * dirs[] = {"Up", "Down", "Right", "Left"};
 			labels[i] = dirs[binds[i] & 3];
-			uint8_t is_pos = (binds[i] & 3) == 3 || !(binds[i] & 3);
-			int sdl_axis = (binds[i] & LEFTSTICK ? SDL_CONTROLLER_AXIS_LEFTX : SDL_CONTROLLER_AXIS_RIGHTX) + !(binds[i] & 2);
-			const char *axname = SDL_GameControllerGetStringForAxis(sdl_axis);
-			size_t namelen = strlen(axname);
-			conf_keys[i] = malloc(sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen + sizeof(positive) + 1);
-			memcpy(conf_keys[i], base_path, sizeof(base_path));
-			memcpy(conf_keys[i] + sizeof(base_path), padkey, sizeof(padkey));
-			memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey), axes, sizeof(axes));
-			memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey) + sizeof(axes), axname, namelen);
-			memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen, is_pos ? positive : negative, sizeof(positive));
-			conf_keys[i][sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen + sizeof(positive)] = 0;
+			conf_vals[i] = (binds[i] & LEFTSTICK ? bindings->left_stick : bindings->right_stick)[binds[i] & 3];
 		} else {
 			labels[i] = get_button_label(&selected_controller_info, binds[i]);
-			static const char* dpdirs[] = {"up", "down", "left", "right"};
-			const char *but_name, *mid;
-			size_t midsz;
-			if (binds[i] < SDL_CONTROLLER_BUTTON_DPAD_UP) {
-				but_name = SDL_GameControllerGetStringForButton(binds[i]);
-				mid = buttons;
-				midsz = sizeof(buttons);
-			} else {
-				but_name = dpdirs[binds[i] - SDL_CONTROLLER_BUTTON_DPAD_UP];
-				mid = dpads;
-				midsz = sizeof(dpads);
-			}
-			size_t namelen = strlen(but_name);
-			conf_keys[i] = malloc(sizeof(base_path) + sizeof(padkey) + midsz + namelen + 2);
-			memcpy(conf_keys[i], base_path, sizeof(base_path));
-			memcpy(conf_keys[i] + sizeof(base_path), padkey, sizeof(padkey));
-			memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey), mid, midsz);
-			
-			memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey) + midsz, but_name, namelen+1);
-			conf_keys[i][sizeof(base_path) + sizeof(padkey) + sizeof(buttons) + namelen + 1] = 0;
+			conf_vals[i] = bindings->button_binds[binds[i]];
 		}
 		if (!labels[i]) {
 			skipped++;
@@ -614,25 +579,74 @@
 			continue;
 		}
 		nk_label(context, labels[i], NK_TEXT_LEFT);
-		if (conf_keys[i]) {
-			char *assigned = tern_find_path(config, conf_keys[i], TVAL_PTR).ptrval;
-			if (!assigned) {
-				assigned = "None";
-			} else if (!memcmp("gamepads.", assigned, strlen("gamepads."))) {
-				assigned += strlen("gamepads.0.");
-			}
-			nk_button_label(context, assigned);
-		} else {
-			nk_button_label(context, i & 1 ? "Internal Screenshot" : "A");
-		}
-		free(conf_keys[i]);
+		nk_button_label(context, conf_vals[i] ? conf_vals[i] : "None");
+	}
+	free(labels);
+	free(conf_vals);
+	nk_group_end(context);
+}
+
+static void button_iter(char *key, tern_val val, uint8_t valtype, void *data)
+{
+	pad_bind_config *bindings = data;
+	if (valtype != TVAL_PTR) {
+		return;
+	}
+	int button = render_lookup_button(key);
+	if (button != SDL_CONTROLLER_BUTTON_INVALID) {
+		bindings->button_binds[button] = val.ptrval;
+	}
+}
+
+static void axis_iter(char *key, tern_val val, uint8_t valtype, void *data)
+{
+	pad_bind_config *bindings = data;
+	if (valtype != TVAL_PTR) {
+		return;
 	}
-	nk_group_end(context);
+	int axis;
+	uint8_t is_negative = 0;
+	char *period = strchr(key, '.');
+	if (period) {
+		char *tmp = malloc(period-key + 1);
+		memcpy(tmp, key, period-key);
+		tmp[period-key] = 0;
+		axis = render_lookup_axis(key);
+		free(tmp);
+		is_negative = strcmp(period+1, "negative") == 0;
+	} else {
+		axis = render_lookup_axis(key);
+	}
+	switch (axis)
+	{
+	case SDL_CONTROLLER_AXIS_LEFTX:
+	case SDL_CONTROLLER_AXIS_LEFTY:
+		bindings->left_stick[(axis - SDL_CONTROLLER_AXIS_LEFTX) * 2 + is_negative] = val.ptrval;
+		break;
+	case SDL_CONTROLLER_AXIS_RIGHTX:
+	case SDL_CONTROLLER_AXIS_RIGHTY:
+		bindings->right_stick[(axis - SDL_CONTROLLER_AXIS_RIGHTX) * 2 + is_negative] = val.ptrval;
+		break;
+	case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
+	case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
+		bindings->triggers[axis-SDL_CONTROLLER_AXIS_TRIGGERLEFT] = val.ptrval;
+		break;
+	}
 }
 
 void view_controller_bindings(struct nk_context *context)
 {
+	static pad_bind_config *bindings;
 	if (nk_begin(context, "Controller Bindings", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) {
+		if (!bindings) {
+			bindings = calloc(1, sizeof(*bindings));
+			tern_node *pad = get_binding_node_for_pad(selected_controller);
+			if (pad) {
+				tern_foreach(tern_find_node(pad, "buttons"), button_iter, bindings);
+				tern_foreach(tern_find_node(pad, "axes"), axis_iter, bindings);
+			}
+		}
+	
 		float orig_height = def_font->handle.height;
 		def_font->handle.height *= 0.5f;
 		
@@ -686,25 +700,25 @@
 			bind_box_left = img_right + (render_width() - img_right) / 2.0f - bind_box_width / 2.0f;
 		}
 		
-		binding_box(context, "Action Buttons", bind_box_left, img_top, bind_box_width, 4, (int[]){
+		binding_box(context, bindings, "Action Buttons", bind_box_left, img_top, bind_box_width, 4, (int[]){
 			SDL_CONTROLLER_BUTTON_A,
 			SDL_CONTROLLER_BUTTON_B,
 			SDL_CONTROLLER_BUTTON_X,
 			SDL_CONTROLLER_BUTTON_Y
 		});
 		
-		binding_box(context, "Right Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){
+		binding_box(context, bindings, "Right Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){
 			SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
 			AXIS | SDL_CONTROLLER_AXIS_TRIGGERRIGHT
 		});
 		
-		binding_box(context, "Misc Buttons", (render_width() - bind_box_width) / 2, font->height/2, bind_box_width, 3, (int[]){
+		binding_box(context, bindings, "Misc Buttons", (render_width() - bind_box_width) / 2, font->height/2, bind_box_width, 3, (int[]){
 			SDL_CONTROLLER_BUTTON_BACK,
 			SDL_CONTROLLER_BUTTON_GUIDE,
 			SDL_CONTROLLER_BUTTON_START
 		});
 		
-		binding_box(context, "Right Stick", img_right - desired_width/3, img_bot, bind_box_width, 5, (int[]){
+		binding_box(context, bindings, "Right Stick", img_right - desired_width/3, img_bot, bind_box_width, 5, (int[]){
 			RIGHTSTICK | UP,
 			RIGHTSTICK | DOWN,
 			RIGHTSTICK | LEFT,
@@ -714,7 +728,7 @@
 		
 		
 		bind_box_left -= img_right;
-		binding_box(context, "Left Stick", bind_box_left, img_top, bind_box_width, 5, (int[]){
+		binding_box(context, bindings, "Left Stick", bind_box_left, img_top, bind_box_width, 5, (int[]){
 			LEFTSTICK | UP,
 			LEFTSTICK | DOWN,
 			LEFTSTICK | LEFT,
@@ -722,12 +736,12 @@
 			SDL_CONTROLLER_BUTTON_LEFTSTICK
 		});
 		
-		binding_box(context, "Left Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){
+		binding_box(context, bindings, "Left Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){
 			SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
 			AXIS | SDL_CONTROLLER_AXIS_TRIGGERLEFT
 		});
 		
-		binding_box(context, "D-pad", img_left - desired_width/6, img_bot + font->height * 1.5, bind_box_width, 4, (int[]){
+		binding_box(context, bindings, "D-pad", img_left - desired_width/6, img_bot + font->height * 1.5, bind_box_width, 4, (int[]){
 			SDL_CONTROLLER_BUTTON_DPAD_UP,
 			SDL_CONTROLLER_BUTTON_DPAD_DOWN,
 			SDL_CONTROLLER_BUTTON_DPAD_LEFT,
--- a/render_sdl.c	Tue Oct 09 09:29:28 2018 -0700
+++ b/render_sdl.c	Wed Oct 24 21:10:12 2018 -0700
@@ -1645,9 +1645,48 @@
 	}
 }
 
+int render_lookup_button(char *name)
+{
+	static tern_node *button_lookup;
+	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);
+		button_lookup = tern_insert_int(button_lookup, "l3", SDL_CONTROLLER_BUTTON_LEFTSTICK);
+		button_lookup = tern_insert_int(button_lookup, "r3", SDL_CONTROLLER_BUTTON_RIGHTSTICK);
+	}
+	return (int)tern_find_int(button_lookup, name, SDL_CONTROLLER_BUTTON_INVALID);
+}
+
+int render_lookup_axis(char *name)
+{
+	static tern_node *axis_lookup;
+	if (!axis_lookup) {
+		for (int i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++)
+		{
+			axis_lookup = tern_insert_int(axis_lookup, SDL_GameControllerGetStringForAxis(i), i);
+		}
+		//alternative Playstation-style names
+		axis_lookup = tern_insert_int(axis_lookup, "l2", SDL_CONTROLLER_AXIS_TRIGGERLEFT);
+		axis_lookup = tern_insert_int(axis_lookup, "r2", SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
+	}
+	return (int)tern_find_int(axis_lookup, name, SDL_CONTROLLER_AXIS_INVALID);
+}
+
 int32_t render_translate_input_name(int32_t controller, char *name, uint8_t is_axis)
 {
-	static tern_node *button_lookup, *axis_lookup;
+	tern_node *button_lookup, *axis_lookup;
 	if (controller > MAX_JOYSTICKS || !joysticks[controller]) {
 		return RENDER_NOT_PLUGGED_IN;
 	}
@@ -1663,41 +1702,15 @@
 	
 	SDL_GameControllerButtonBind cbind;
 	if (is_axis) {
-		if (!axis_lookup) {
-			for (int i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++)
-			{
-				axis_lookup = tern_insert_int(axis_lookup, SDL_GameControllerGetStringForAxis(i), i);
-			}
-			//alternative Playstation-style names
-			axis_lookup = tern_insert_int(axis_lookup, "l2", SDL_CONTROLLER_AXIS_TRIGGERLEFT);
-			axis_lookup = tern_insert_int(axis_lookup, "r2", SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
-		}
-		intptr_t sdl_axis = tern_find_int(axis_lookup, name, SDL_CONTROLLER_AXIS_INVALID);
+		
+		int sdl_axis = render_lookup_axis(name);
 		if (sdl_axis == SDL_CONTROLLER_AXIS_INVALID) {
 			SDL_GameControllerClose(control);
 			return RENDER_INVALID_NAME;
 		}
 		cbind = SDL_GameControllerGetBindForAxis(control, sdl_axis);
 	} else {
-		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);
-			button_lookup = tern_insert_int(button_lookup, "l3", SDL_CONTROLLER_BUTTON_LEFTSTICK);
-			button_lookup = tern_insert_int(button_lookup, "r3", SDL_CONTROLLER_BUTTON_RIGHTSTICK);
-		}
-		intptr_t sdl_button = tern_find_int(button_lookup, name, SDL_CONTROLLER_BUTTON_INVALID);
+		int sdl_button = render_lookup_button(name);
 		if (sdl_button == SDL_CONTROLLER_BUTTON_INVALID) {
 			SDL_GameControllerClose(control);
 			return RENDER_INVALID_NAME;
--- a/render_sdl.h	Tue Oct 09 09:29:28 2018 -0700
+++ b/render_sdl.h	Wed Oct 24 21:10:12 2018 -0700
@@ -12,6 +12,7 @@
 void render_set_gl_context_handlers(ui_render_fun destroy, ui_render_fun create);
 SDL_Joystick *render_get_joystick(int index);
 SDL_GameController *render_get_controller(int index);
-
+int render_lookup_button(char *name);
+int render_lookup_axis(char *name);
 
 #endif //RENDER_SDL_H_