main bindings.c
   1#include <string.h>
   2#include <stdlib.h>
   3#include "render.h"
   4#include "system.h"
   5#include "io.h"
   6#include "blastem.h"
   7#include "saves.h"
   8#include "util.h"
   9#include "genesis.h"
  10#include "sms.h"
  11#include "menu.h"
  12#include "bindings.h"
  13#include "controller_info.h"
  14enum {
  15	BIND_NONE,
  16	BIND_UI,
  17	BIND_GAMEPAD,
  18	BIND_MOUSE
  19};
  20
  21typedef enum {
  22	UI_DEBUG_MODE_INC,
  23	UI_ENTER_DEBUGGER,
  24	UI_SAVE_STATE,
  25	UI_SET_SPEED,
  26	UI_NEXT_SPEED,
  27	UI_PREV_SPEED,
  28	UI_RELEASE_MOUSE,
  29	UI_TOGGLE_KEYBOARD_CAPTURE,
  30	UI_SOFT_RESET,
  31	UI_RELOAD,
  32	UI_SMS_PAUSE,
  33	UI_SCREENSHOT,
  34	UI_EXIT,
  35	UI_PLANE_DEBUG,
  36	UI_VRAM_DEBUG,
  37	UI_CRAM_DEBUG,
  38	UI_COMPOSITE_DEBUG
  39} ui_action;
  40
  41typedef struct {
  42	uint8_t bind_type;
  43	uint8_t subtype_a;
  44	uint8_t subtype_b;
  45} keybinding;
  46
  47typedef struct {
  48	keybinding bindings[4];
  49	uint8_t    state;
  50} joydpad;
  51
  52typedef struct {
  53	keybinding positive;
  54	keybinding negative;
  55	int16_t    value;
  56} joyaxis;
  57
  58typedef struct {
  59	keybinding *buttons;
  60	joydpad    *dpads;
  61	joyaxis    *axes;
  62	uint32_t   num_buttons; //number of entries in the buttons array, not necessarily the number of buttons on the device
  63	uint32_t   num_dpads;   //number of entries in the dpads array, not necessarily the number of dpads on the device
  64	uint32_t   num_axes;    //number of entries in the axes array, not necessarily the number of dpads on the device
  65} joystick;
  66
  67typedef struct {
  68	keybinding buttons[MAX_MOUSE_BUTTONS];
  69	keybinding motion;
  70} mousebinding;
  71
  72#define DEFAULT_JOYBUTTON_ALLOC 12
  73static keybinding *bindings[0x10000];
  74static joystick joysticks[MAX_JOYSTICKS];
  75static mousebinding mice[MAX_MICE];
  76const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
  77
  78static void do_bind(keybinding *binding, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
  79{
  80	binding->bind_type = bind_type;
  81	binding->subtype_a = subtype_a;
  82	binding->subtype_b = subtype_b;
  83}
  84
  85void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
  86{
  87	int bucket = keycode >> 15 & 0xFFFF;
  88	if (!bindings[bucket]) {
  89		bindings[bucket] = malloc(sizeof(keybinding) * 0x8000);
  90		memset(bindings[bucket], 0, sizeof(keybinding) * 0x8000);
  91	}
  92	int idx = keycode & 0x7FFF;
  93	do_bind(bindings[bucket] + idx, bind_type, subtype_a, subtype_b);
  94}
  95
  96void bind_button(int joystick, int button, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
  97{
  98	if (joystick >= MAX_JOYSTICKS) {
  99		return;
 100	}
 101	if (!joysticks[joystick].buttons) {
 102		joysticks[joystick].num_buttons = button < DEFAULT_JOYBUTTON_ALLOC ? DEFAULT_JOYBUTTON_ALLOC : button + 1;
 103		joysticks[joystick].buttons = calloc(joysticks[joystick].num_buttons, sizeof(keybinding));
 104	} else if (joysticks[joystick].num_buttons <= button) {
 105		uint32_t old_capacity = joysticks[joystick].num_buttons;
 106		joysticks[joystick].num_buttons *= 2;
 107		joysticks[joystick].buttons = realloc(joysticks[joystick].buttons, sizeof(keybinding) * joysticks[joystick].num_buttons);
 108		memset(joysticks[joystick].buttons + old_capacity, 0, joysticks[joystick].num_buttons - old_capacity);
 109	}
 110	do_bind(joysticks[joystick].buttons + button, bind_type, subtype_a, subtype_b);
 111}
 112
 113void bind_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
 114{
 115	if (joystick >= MAX_JOYSTICKS) {
 116		return;
 117	}
 118	if (!joysticks[joystick].dpads) {
 119		//multiple D-pads/hats are not common, so don't allocate any extra space
 120		joysticks[joystick].dpads = calloc(dpad+1, sizeof(joydpad));
 121		joysticks[joystick].num_dpads = dpad+1;
 122	} else if (joysticks[joystick].num_dpads <= dpad) {
 123		uint32_t old_capacity = joysticks[joystick].num_dpads;
 124		joysticks[joystick].num_dpads *= 2;
 125		joysticks[joystick].dpads = realloc(joysticks[joystick].dpads, sizeof(joydpad) * joysticks[joystick].num_dpads);
 126		memset(joysticks[joystick].dpads + old_capacity, 0, (joysticks[joystick].num_dpads - old_capacity) * sizeof(joydpad));
 127	}
 128	for (int i = 0; i < 4; i ++) {
 129		if (dpadbits[i] & direction) {
 130			do_bind(joysticks[joystick].dpads[dpad].bindings + i, bind_type, subtype_a, subtype_b);
 131			break;
 132		}
 133	}
 134}
 135
 136void bind_axis(int joystick, int axis, int positive, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
 137{
 138	if (joystick >= MAX_JOYSTICKS) {
 139		return;
 140	}
 141	if (!joysticks[joystick].axes) {
 142		//typical gamepad has 4 axes
 143		joysticks[joystick].num_axes = axis+1 > 4 ? axis+1 : 4;
 144		joysticks[joystick].axes = calloc(joysticks[joystick].num_axes, sizeof(joyaxis));
 145	} else if (joysticks[joystick].num_axes <= axis) {
 146		uint32_t old_capacity = joysticks[joystick].num_axes;
 147		joysticks[joystick].num_axes *= 2;
 148		joysticks[joystick].axes = realloc(joysticks[joystick].axes, sizeof(joyaxis) * joysticks[joystick].num_axes);
 149		memset(joysticks[joystick].axes + old_capacity, 0, (joysticks[joystick].num_axes - old_capacity) * sizeof(joyaxis));
 150	}
 151	if (positive) {
 152		do_bind(&joysticks[joystick].axes[axis].positive, bind_type, subtype_a, subtype_b);
 153	} else {
 154		do_bind(&joysticks[joystick].axes[axis].negative, bind_type, subtype_a, subtype_b);
 155	}
 156}
 157
 158void reset_joystick_bindings(int joystick)
 159{
 160	if (joystick >= MAX_JOYSTICKS) {
 161		return;
 162	}
 163	if (joysticks[joystick].buttons) {
 164		for (int i = 0; i < joysticks[joystick].num_buttons; i++)
 165		{
 166			joysticks[joystick].buttons[i].bind_type = BIND_NONE;
 167		}
 168	}
 169	if (joysticks[joystick].dpads) {
 170		for (int i = 0; i < joysticks[joystick].num_dpads; i++)
 171		{
 172			for (int dir = 0; dir < 4; dir++)
 173			{
 174				joysticks[joystick].dpads[i].bindings[dir].bind_type = BIND_NONE;
 175			}
 176		}
 177	}
 178	if (joysticks[joystick].axes) {
 179		for (int i = 0; i < joysticks[joystick].num_axes; i++)
 180		{
 181			joysticks[joystick].axes[i].positive.bind_type = BIND_NONE;
 182			joysticks[joystick].axes[i].negative.bind_type = BIND_NONE;
 183		}
 184	}
 185}
 186
 187static uint8_t content_binds_enabled = 1;
 188void set_content_binding_state(uint8_t enabled)
 189{
 190	content_binds_enabled = enabled;
 191}
 192
 193void handle_binding_down(keybinding * binding)
 194{
 195	if (!current_system) {
 196		return;
 197	}
 198	if (binding->bind_type == BIND_GAMEPAD && current_system && current_system->gamepad_down)
 199	{
 200		current_system->gamepad_down(current_system, binding->subtype_a, binding->subtype_b);
 201	}
 202	else if (binding->bind_type == BIND_MOUSE && current_system && current_system->mouse_down)
 203	{
 204		current_system->mouse_down(current_system, binding->subtype_a, binding->subtype_b);
 205	}
 206}
 207
 208static uint8_t keyboard_captured;
 209void handle_keydown(int keycode, uint8_t scancode)
 210{
 211	int bucket = keycode >> 15 & 0xFFFF;
 212	int idx = keycode & 0x7FFF;
 213	keybinding * binding = bindings[bucket] ? bindings[bucket] + idx : NULL;
 214	if (binding && (!keyboard_captured || (binding->bind_type == BIND_UI && binding->subtype_a == UI_TOGGLE_KEYBOARD_CAPTURE))) {
 215		handle_binding_down(binding);
 216	} else if (keyboard_captured && current_system && current_system->keyboard_down) {
 217		current_system->keyboard_down(current_system, scancode);
 218	}
 219}
 220
 221void handle_joydown(int joystick, int button)
 222{
 223	if (joystick >= MAX_JOYSTICKS || button >= joysticks[joystick].num_buttons) {
 224		return;
 225	}
 226	keybinding * binding = joysticks[joystick].buttons + button;
 227	handle_binding_down(binding);
 228}
 229
 230static uint8_t mouse_mode = MOUSE_NONE;
 231static uint8_t mouse_captured;
 232void handle_mousedown(int mouse, int button)
 233{
 234	if (mouse_mode == MOUSE_CAPTURE && !mouse_captured) {
 235		mouse_captured = 1;
 236		render_relative_mouse(1);
 237		return;
 238	}
 239	if (mouse >= MAX_MICE || button > MAX_MOUSE_BUTTONS || button <= 0) {
 240		return;
 241	}
 242	keybinding * binding = mice[mouse].buttons + button - 1;
 243	handle_binding_down(binding);
 244}
 245
 246static int current_speed = 0;
 247static int num_speeds = 1;
 248static uint32_t * speeds = NULL;
 249
 250static uint8_t mouse_captured;
 251
 252void handle_binding_up(keybinding * binding)
 253{
 254	uint8_t allow_content_binds = content_binds_enabled && current_system;
 255	switch(binding->bind_type)
 256	{
 257	case BIND_GAMEPAD:
 258		if (allow_content_binds && current_system->gamepad_up) {
 259			current_system->gamepad_up(current_system, binding->subtype_a, binding->subtype_b);
 260		}
 261		break;
 262	case BIND_MOUSE:
 263		if (allow_content_binds && current_system->mouse_up) {
 264			current_system->mouse_up(current_system, binding->subtype_a, binding->subtype_b);
 265		}
 266		break;
 267	case BIND_UI:
 268		switch (binding->subtype_a)
 269		{
 270		case UI_DEBUG_MODE_INC:
 271			if (allow_content_binds) {
 272				current_system->inc_debug_mode(current_system);
 273			}
 274			break;
 275		case UI_ENTER_DEBUGGER:
 276			if (allow_content_binds) {
 277				current_system->enter_debugger = 1;
 278			}
 279			break;
 280		case UI_SAVE_STATE:
 281			if (allow_content_binds) {
 282				current_system->save_state = QUICK_SAVE_SLOT+1;
 283			}
 284			break;
 285		case UI_NEXT_SPEED:
 286			if (allow_content_binds) {
 287				current_speed++;
 288				if (current_speed >= num_speeds) {
 289					current_speed = 0;
 290				}
 291				printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
 292				current_system->set_speed_percent(current_system, speeds[current_speed]);
 293			}
 294			break;
 295		case UI_PREV_SPEED:
 296			if (allow_content_binds) {
 297				current_speed--;
 298				if (current_speed < 0) {
 299					current_speed = num_speeds - 1;
 300				}
 301				printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
 302				current_system->set_speed_percent(current_system, speeds[current_speed]);
 303			}
 304			break;
 305		case UI_SET_SPEED:
 306			if (allow_content_binds) {
 307				if (binding->subtype_b < num_speeds) {
 308					current_speed = binding->subtype_b;
 309					printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
 310					current_system->set_speed_percent(current_system, speeds[current_speed]);
 311				} else {
 312					printf("Setting speed to %d\n", speeds[current_speed]);
 313					current_system->set_speed_percent(current_system, speeds[current_speed]);
 314				}
 315			}
 316			break;
 317		case UI_RELEASE_MOUSE:
 318			if (mouse_captured) {
 319				mouse_captured = 0;
 320				render_relative_mouse(0);
 321			}
 322			break;
 323		case UI_TOGGLE_KEYBOARD_CAPTURE:
 324			if (allow_content_binds && current_system->has_keyboard) {
 325				keyboard_captured = !keyboard_captured;
 326			}
 327			break;
 328		case UI_SOFT_RESET:
 329			if (allow_content_binds) {
 330				current_system->soft_reset(current_system);
 331			}
 332			break;
 333		case UI_RELOAD:
 334			if (allow_content_binds) {
 335				reload_media();
 336			}
 337			break;
 338		case UI_SMS_PAUSE:
 339			if (allow_content_binds && current_system->gamepad_down) {
 340				current_system->gamepad_down(current_system, GAMEPAD_MAIN_UNIT, MAIN_UNIT_PAUSE);
 341			}
 342			break;
 343		case UI_SCREENSHOT: {
 344			if (allow_content_binds) {
 345				char *screenshot_base = tern_find_path(config, "ui\0screenshot_path\0", TVAL_PTR).ptrval;
 346				if (!screenshot_base) {
 347					screenshot_base = "$HOME";
 348				}
 349				tern_node *vars = tern_insert_ptr(NULL, "HOME", get_home_dir());
 350				vars = tern_insert_ptr(vars, "EXEDIR", get_exe_dir());
 351				screenshot_base = replace_vars(screenshot_base, vars, 1);
 352				tern_free(vars);
 353				time_t now = time(NULL);
 354				struct tm local_store;
 355				char fname_part[256];
 356				char *template = tern_find_path(config, "ui\0screenshot_template\0", TVAL_PTR).ptrval;
 357				if (!template) {
 358					template = "blastem_%c.ppm";
 359				}
 360				strftime(fname_part, sizeof(fname_part), template, localtime_r(&now, &local_store));
 361				char const *parts[] = {screenshot_base, PATH_SEP, fname_part};
 362				char *path = alloc_concat_m(3, parts);
 363				free(screenshot_base);
 364				render_save_screenshot(path);
 365			}
 366			break;
 367		}
 368			case UI_EXIT:
 369				current_system->request_exit(current_system);
 370			if (current_system->type == SYSTEM_GENESIS) {
 371				genesis_context *gen = (genesis_context *)current_system;
 372				if (gen->extra) {
 373					//TODO: More robust mechanism for detecting menu
 374					menu_context *menu = gen->extra;
 375					menu->external_game_load = 1;
 376				}
 377			}
 378				break;
 379		case UI_PLANE_DEBUG: 
 380		case UI_VRAM_DEBUG: 
 381		case UI_CRAM_DEBUG:
 382		case UI_COMPOSITE_DEBUG:
 383			if (allow_content_binds) {
 384				vdp_context *vdp = NULL;
 385				if (current_system->type == SYSTEM_GENESIS) {
 386					genesis_context *gen = (genesis_context *)current_system;
 387					vdp = gen->vdp;
 388				} else if (current_system->type == SYSTEM_SMS) {
 389					sms_context *sms = (sms_context *)current_system;
 390					vdp = sms->vdp;
 391				}
 392				if (vdp) {
 393					uint8_t debug_type;
 394					switch(binding->subtype_a)
 395					{
 396					case UI_PLANE_DEBUG: debug_type = VDP_DEBUG_PLANE; break;
 397					case UI_VRAM_DEBUG: debug_type = VDP_DEBUG_VRAM; break;
 398					case UI_CRAM_DEBUG: debug_type = VDP_DEBUG_CRAM; break;
 399					case UI_COMPOSITE_DEBUG: debug_type = VDP_DEBUG_COMPOSITE; break;
 400					default: return;
 401					}
 402					vdp_toggle_debug_view(vdp, debug_type);
 403				}
 404				break;
 405			}
 406		}
 407		break;
 408	}
 409}
 410
 411void handle_keyup(int keycode, uint8_t scancode)
 412{
 413	int bucket = keycode >> 15 & 0xFFFF;
 414	int idx = keycode & 0x7FFF;
 415	keybinding * binding = bindings[bucket] ? bindings[bucket] + idx : NULL;
 416	if (binding && (!keyboard_captured || (binding->bind_type == BIND_UI && binding->subtype_a == UI_TOGGLE_KEYBOARD_CAPTURE))) {
 417		handle_binding_up(binding);
 418	} else if (keyboard_captured && current_system && current_system->keyboard_up) {
 419		current_system->keyboard_up(current_system, scancode);
 420	}
 421}
 422
 423void handle_joyup(int joystick, int button)
 424{
 425	if (joystick >= MAX_JOYSTICKS  || button >= joysticks[joystick].num_buttons) {
 426		return;
 427	}
 428	keybinding * binding = joysticks[joystick].buttons + button;
 429	handle_binding_up(binding);
 430}
 431
 432void handle_joy_dpad(int joystick, int dpadnum, uint8_t value)
 433{
 434	if (joystick >= MAX_JOYSTICKS  || dpadnum >= joysticks[joystick].num_dpads) {
 435		return;
 436	}
 437	joydpad * dpad = joysticks[joystick].dpads + dpadnum;
 438	uint8_t newdown = (value ^ dpad->state) & value;
 439	uint8_t newup = ((~value) ^ (~dpad->state)) & (~value);
 440	dpad->state = value;
 441	for (int i = 0; i < 4; i++) {
 442		if (newdown & dpadbits[i]) {
 443			handle_binding_down(dpad->bindings + i);
 444		} else if(newup & dpadbits[i]) {
 445			handle_binding_up(dpad->bindings + i);
 446		}
 447	}
 448}
 449
 450#define JOY_AXIS_THRESHOLD 2000
 451
 452void handle_joy_axis(int joystick, int axis, int16_t value)
 453{
 454	if (joystick >= MAX_JOYSTICKS  || axis >= joysticks[joystick].num_axes) {
 455		return;
 456	}
 457	joyaxis *jaxis = joysticks[joystick].axes + axis;
 458	int old_active = abs(jaxis->value) > JOY_AXIS_THRESHOLD;
 459	int new_active = abs(value) > JOY_AXIS_THRESHOLD;
 460	int old_pos = jaxis->value > 0;
 461	int new_pos = value > 0;
 462	jaxis->value = value;
 463	if (old_active && (!new_active || old_pos != new_pos)) {
 464		//previously activated direction is no longer active
 465		handle_binding_up(old_pos ? &jaxis->positive : &jaxis->negative);
 466	}
 467	if (new_active && (!old_active || old_pos != new_pos)) {
 468		//previously unactivated direction is now active
 469		handle_binding_down(new_pos ? &jaxis->positive : &jaxis->negative);
 470	}
 471}
 472
 473void handle_mouse_moved(int mouse, uint16_t x, uint16_t y, int16_t deltax, int16_t deltay)
 474{
 475	if (mouse >= MAX_MICE || !current_system) {
 476		return;
 477	}
 478	if (mice[mouse].motion.bind_type == BIND_MOUSE && mice[mouse].motion.subtype_b == PSEUDO_BUTTON_MOTION) {
 479		uint8_t target_mouse = mice[mouse].motion.subtype_a;
 480		switch(mouse_mode)
 481		{
 482		case MOUSE_NONE:
 483			break;
 484		case MOUSE_ABSOLUTE: {
 485			if (current_system->mouse_motion_absolute) {
 486				float scale_x = (render_emulated_width() * 2.0f) / ((float)render_width());
 487				float scale_y = (render_emulated_height() * 2.0f) / ((float)render_height());
 488				int32_t adj_x = x * scale_x + 2 * render_overscan_left() - 2 * BORDER_LEFT;
 489				int32_t adj_y = y * scale_y + 2 * render_overscan_top() - 4;
 490				
 491				current_system->mouse_motion_absolute(current_system, target_mouse, adj_x, adj_y);
 492			}
 493			break;
 494		}
 495		case MOUSE_RELATIVE: {
 496			if (current_system->mouse_motion_relative) {
 497				current_system->mouse_motion_relative(current_system, target_mouse, deltax, deltay);
 498			}
 499			break;
 500		}
 501		case MOUSE_CAPTURE: {
 502			if (mouse_captured && current_system->mouse_motion_relative) {
 503				current_system->mouse_motion_relative(current_system, target_mouse, deltax, deltay);
 504			}
 505			break;
 506		}
 507		}
 508	} else {
 509		handle_binding_up(&mice[mouse].motion);
 510	}
 511}
 512
 513void handle_mouseup(int mouse, int button)
 514{
 515	if (mouse >= MAX_MICE || button > MAX_MOUSE_BUTTONS || button <= 0) {
 516		return;
 517	}
 518	keybinding * binding = mice[mouse].buttons + button - 1;
 519	handle_binding_up(binding);
 520}
 521
 522void bindings_release_capture(void)
 523{
 524	if (mouse_mode == MOUSE_RELATIVE || (mouse_mode == MOUSE_CAPTURE && mouse_captured)) {
 525		render_relative_mouse(0);
 526	}
 527	keyboard_captured = 0;
 528}
 529
 530void bindings_reacquire_capture(void)
 531{
 532	if (mouse_mode == MOUSE_RELATIVE || (mouse_mode == MOUSE_CAPTURE && mouse_captured)) {
 533		render_relative_mouse(1);
 534	}
 535}
 536
 537int parse_binding_target(int device_num, char * target, tern_node * padbuttons, tern_node *mousebuttons, uint8_t * subtype_a, uint8_t * subtype_b)
 538{
 539	const int gpadslen = strlen("gamepads.");
 540	const int mouselen = strlen("mouse.");
 541	if (startswith(target, "gamepads.")) {
 542		int padnum = target[gpadslen] == 'n' ? device_num + 1 : target[gpadslen] - '0';
 543		if (padnum >= 1 && padnum <= 8) {
 544			int button = tern_find_int(padbuttons, target + gpadslen + 1, 0);
 545			if (button) {
 546				*subtype_a = padnum;
 547				*subtype_b = button;
 548				return BIND_GAMEPAD;
 549			} else {
 550				if (target[gpadslen+1]) {
 551					warning("Gamepad mapping string '%s' refers to an invalid button '%s'\n", target, target + gpadslen + 1);
 552				} else {
 553					warning("Gamepad mapping string '%s' has no button component\n", target);
 554				}
 555			}
 556		} else {
 557			warning("Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]);
 558		}
 559	} else if(startswith(target, "mouse.")) {
 560		int mousenum = target[mouselen] == 'n' ? device_num + 1 : target[mouselen] - '0';
 561		if (mousenum >= 1 && mousenum <= 8) {
 562			int button = tern_find_int(mousebuttons, target + mouselen + 1, 0);
 563			if (button) {
 564				*subtype_a = mousenum;
 565				*subtype_b = button;
 566				return BIND_MOUSE;
 567			} else {
 568				if (target[mouselen+1]) {
 569					warning("Mouse mapping string '%s' refers to an invalid button '%s'\n", target, target + mouselen + 1);
 570				} else {
 571					warning("Mouse mapping string '%s' has no button component\n", target);
 572				}
 573			}
 574		} else {
 575			warning("Gamepad mapping string '%s' refers to an invalid mouse number %c\n", target, target[mouselen]);
 576		}
 577	} else if(startswith(target, "ui.")) {
 578		if (!strcmp(target + 3, "vdp_debug_mode")) {
 579			*subtype_a = UI_DEBUG_MODE_INC;
 580		} else if(!strcmp(target + 3, "vdp_debug_pal")) {
 581			//legacy binding, ignore
 582			return 0;
 583		} else if(!strcmp(target + 3, "enter_debugger")) {
 584			*subtype_a = UI_ENTER_DEBUGGER;
 585		} else if(!strcmp(target + 3, "save_state")) {
 586			*subtype_a = UI_SAVE_STATE;
 587		} else if(startswith(target + 3, "set_speed.")) {
 588			*subtype_a = UI_SET_SPEED;
 589			*subtype_b = atoi(target + 3 + strlen("set_speed."));
 590		} else if(!strcmp(target + 3, "next_speed")) {
 591			*subtype_a = UI_NEXT_SPEED;
 592		} else if(!strcmp(target + 3, "prev_speed")) {
 593			*subtype_a = UI_PREV_SPEED;
 594		} else if(!strcmp(target + 3, "release_mouse")) {
 595			*subtype_a = UI_RELEASE_MOUSE;
 596		} else if(!strcmp(target + 3, "toggle_keyboard_captured")) {
 597			*subtype_a = UI_TOGGLE_KEYBOARD_CAPTURE;
 598		} else if (!strcmp(target + 3, "soft_reset")) {
 599			*subtype_a = UI_SOFT_RESET;
 600		} else if (!strcmp(target + 3, "reload")) {
 601			*subtype_a = UI_RELOAD;
 602		} else if (!strcmp(target + 3, "sms_pause")) {
 603			*subtype_a = UI_SMS_PAUSE;
 604		} else if (!strcmp(target + 3, "screenshot")) {
 605			*subtype_a = UI_SCREENSHOT;
 606		} else if(!strcmp(target + 3, "exit")) {
 607			*subtype_a = UI_EXIT;
 608		} else if (!strcmp(target + 3, "plane_debug")) {
 609			*subtype_a = UI_PLANE_DEBUG;
 610		} else if (!strcmp(target + 3, "vram_debug")) {
 611			*subtype_a = UI_VRAM_DEBUG;
 612		} else if (!strcmp(target + 3, "cram_debug")) {
 613			*subtype_a = UI_CRAM_DEBUG;
 614		} else if (!strcmp(target + 3, "compositing_debug")) {
 615			*subtype_a = UI_COMPOSITE_DEBUG;
 616		} else {
 617			warning("Unreconized UI binding type %s\n", target);
 618			return 0;
 619		}
 620		return BIND_UI;
 621	} else {
 622		warning("Unrecognized binding type %s\n", target);
 623	}
 624	return 0;
 625}
 626
 627void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, tern_node *mousebuttons, char * prefix)
 628{
 629	char * curstr = NULL;
 630	int len;
 631	if (!cur) {
 632		return;
 633	}
 634	char onec[2];
 635	if (prefix) {
 636		len = strlen(prefix);
 637		curstr = malloc(len + 2);
 638		memcpy(curstr, prefix, len);
 639	} else {
 640		curstr = onec;
 641		len = 0;
 642	}
 643	curstr[len] = cur->el;
 644	curstr[len+1] = 0;
 645	if (cur->el) {
 646		process_keys(cur->straight.next, special, padbuttons, mousebuttons, curstr);
 647	} else {
 648		int keycode = tern_find_int(special, curstr, 0);
 649		if (!keycode) {
 650			keycode = curstr[0];
 651			if (curstr[1] != 0) {
 652				warning("%s is not recognized as a key identifier, truncating to %c\n", curstr, curstr[0]);
 653			}
 654		}
 655		char * target = cur->straight.value.ptrval;
 656		uint8_t subtype_a = 0, subtype_b = 0;
 657		int bindtype = parse_binding_target(0, target, padbuttons, mousebuttons, &subtype_a, &subtype_b);
 658		bind_key(keycode, bindtype, subtype_a, subtype_b);
 659	}
 660	process_keys(cur->left, special, padbuttons, mousebuttons, prefix);
 661	process_keys(cur->right, special, padbuttons, mousebuttons, prefix);
 662	if (curstr && len) {
 663		free(curstr);
 664	}
 665}
 666
 667void process_speeds(tern_node * cur, char * prefix)
 668{
 669	char * curstr = NULL;
 670	int len;
 671	if (!cur) {
 672		return;
 673	}
 674	char onec[2];
 675	if (prefix) {
 676		len = strlen(prefix);
 677		curstr = malloc(len + 2);
 678		memcpy(curstr, prefix, len);
 679	} else {
 680		curstr = onec;
 681		len = 0;
 682	}
 683	curstr[len] = cur->el;
 684	curstr[len+1] = 0;
 685	if (cur->el) {
 686		process_speeds(cur->straight.next, curstr);
 687	} else {
 688		char *end;
 689		long speed_index = strtol(curstr, &end, 10);
 690		if (speed_index < 0 || end == curstr || *end) {
 691			warning("%s is not a valid speed index", curstr);
 692		} else {
 693			if (speed_index >= num_speeds) {
 694				speeds = realloc(speeds, sizeof(uint32_t) * (speed_index+1));
 695				for(; num_speeds < speed_index + 1; num_speeds++) {
 696					speeds[num_speeds] = 0;
 697				}
 698			}
 699			speeds[speed_index] = atoi(cur->straight.value.ptrval);
 700			if (speeds[speed_index] < 1) {
 701				warning("%s is not a valid speed percentage, setting speed %d to 100", cur->straight.value.ptrval, speed_index);
 702				speeds[speed_index] = 100;
 703			}
 704		}
 705	}
 706	process_speeds(cur->left, prefix);
 707	process_speeds(cur->right, prefix);
 708	if (curstr && len) {
 709		free(curstr);
 710	}
 711}
 712
 713typedef struct {
 714	tern_node *padbuttons;
 715	tern_node *mousebuttons;
 716	int       mouseidx;
 717} pmb_state;
 718
 719void process_mouse_button(char *buttonstr, tern_val value, uint8_t valtype, void *data)
 720{
 721	pmb_state *state = data;
 722	int buttonnum = atoi(buttonstr);
 723	if (buttonnum < 1 || buttonnum > MAX_MOUSE_BUTTONS) {
 724		warning("Mouse button %s is out of the supported range of 1-8\n", buttonstr);
 725		return;
 726	}
 727	if (valtype != TVAL_PTR) {
 728		warning("Mouse button %s is not a scalar value!\n", buttonstr);
 729		return;
 730	}
 731	buttonnum--;
 732	uint8_t subtype_a = 0, subtype_b = 0;
 733	int bindtype = parse_binding_target(state->mouseidx, value.ptrval, state->padbuttons, state->mousebuttons, &subtype_a, &subtype_b);
 734	mice[state->mouseidx].buttons[buttonnum].bind_type = bindtype;
 735	mice[state->mouseidx].buttons[buttonnum].subtype_a = subtype_a;
 736	mice[state->mouseidx].buttons[buttonnum].subtype_b = subtype_b;
 737}
 738
 739void process_mouse(char *mousenum, tern_val value, uint8_t valtype, void *data)
 740{
 741	tern_node **buttonmaps = data;
 742	if (valtype != TVAL_NODE) {
 743		warning("Binding for mouse %s is a scalar!\n", mousenum);
 744		return;
 745	}
 746	tern_node *mousedef = value.ptrval;
 747	tern_node *padbuttons = buttonmaps[0];
 748	tern_node *mousebuttons = buttonmaps[1];
 749
 750	int mouseidx = atoi(mousenum);
 751	if (mouseidx < 0 || mouseidx >= MAX_MICE) {
 752		warning("Mouse numbers must be between 0 and %d, but %d is not\n", MAX_MICE, mouseidx);
 753		return;
 754	}
 755	char *motion = tern_find_ptr(mousedef, "motion");
 756	if (motion) {
 757		uint8_t subtype_a = 0, subtype_b = 0;
 758		int bindtype = parse_binding_target(mouseidx, motion, padbuttons, mousebuttons, &subtype_a, &subtype_b);
 759		mice[mouseidx].motion.bind_type = bindtype;
 760		mice[mouseidx].motion.subtype_a = subtype_a;
 761		mice[mouseidx].motion.subtype_b = subtype_b;
 762	}
 763	tern_node *buttons = tern_find_path(mousedef, "buttons\0\0", TVAL_NODE).ptrval;
 764	if (buttons) {
 765		pmb_state state = {padbuttons, mousebuttons, mouseidx};
 766		tern_foreach(buttons, process_mouse_button, &state);
 767	}
 768}
 769
 770typedef struct {
 771	int       padnum;
 772	tern_node *padbuttons;
 773	tern_node *mousebuttons;
 774} pad_button_state;
 775
 776
 777static long map_warning_pad = -1;
 778void process_pad_button(char *key, tern_val val, uint8_t valtype, void *data)
 779{
 780	pad_button_state *state = data;
 781	int hostpadnum = state->padnum;
 782	if (valtype != TVAL_PTR) {
 783		warning("Pad button %s has a non-scalar value\n", key);
 784		return;
 785	}
 786	uint8_t subtype_a = 0, subtype_b = 0;
 787	int bindtype = parse_binding_target(hostpadnum, val.ptrval, state->padbuttons, state->mousebuttons, &subtype_a, &subtype_b);
 788	char *end;
 789	long hostbutton = strtol(key, &end, 10);
 790	if (*end) {
 791		//key is not a valid base 10 integer
 792		hostbutton = render_translate_input_name(hostpadnum, key, 0);
 793		if (hostbutton < 0) {
 794			if (hostbutton == RENDER_INVALID_NAME) {
 795				warning("%s is not a valid gamepad input name\n", key);
 796			} else if (hostbutton == RENDER_NOT_MAPPED && hostpadnum != map_warning_pad) {
 797				warning("No mapping exists for input %s on gamepad %d\n", key, hostpadnum);
 798				map_warning_pad = hostpadnum;
 799			}
 800			return;
 801		}
 802		if (hostbutton & RENDER_DPAD_BIT) {
 803			bind_dpad(hostpadnum, render_dpad_part(hostbutton), render_direction_part(hostbutton), bindtype, subtype_a, subtype_b);
 804			return;
 805		} else if (hostbutton & RENDER_AXIS_BIT) {
 806			bind_axis(hostpadnum, render_axis_part(hostbutton), hostbutton & RENDER_AXIS_POS, bindtype, subtype_a, subtype_b);
 807			return;
 808		}
 809	}
 810	bind_button(hostpadnum, hostbutton, bindtype, subtype_a, subtype_b);
 811}
 812
 813void process_pad_axis(char *key, tern_val val, uint8_t valtype, void *data)
 814{
 815	key = strdup(key);
 816	pad_button_state *state = data;
 817	int hostpadnum = state->padnum;
 818	if (valtype != TVAL_PTR) {
 819		warning("Mapping for axis %s has a non-scalar value", key);
 820		return;
 821	}
 822	uint8_t subtype_a = 0, subtype_b = 0;
 823	int bindtype = parse_binding_target(hostpadnum, val.ptrval, state->padbuttons, state->mousebuttons, &subtype_a, &subtype_b);
 824	char *modifier = strchr(key, '.');
 825	int positive = 1;
 826	if (modifier) {
 827		*modifier = 0;
 828		modifier++;
 829		if (!strcmp("negative", modifier)) {
 830			positive = 0;
 831		} else if(strcmp("positive", modifier)) {
 832			warning("Invalid axis modifier %s for axis %s on pad %d\n", modifier, key, hostpadnum);
 833		}
 834	}
 835	char *end;
 836	long axis = strtol(key, &end, 10);
 837	if (*end) {
 838		//key is not a valid base 10 integer
 839		axis = render_translate_input_name(hostpadnum, key, 1);
 840		if (axis < 0) {
 841			if (axis == RENDER_INVALID_NAME) {
 842				warning("%s is not a valid gamepad input name\n", key);
 843			} else if (axis == RENDER_NOT_MAPPED && hostpadnum != map_warning_pad) {
 844				warning("No mapping exists for input %s on gamepad %d\n", key, hostpadnum);
 845				map_warning_pad = hostpadnum;
 846			}
 847			goto done;
 848		}
 849		if (axis & RENDER_DPAD_BIT) {
 850			bind_dpad(hostpadnum, render_dpad_part(axis), render_direction_part(axis), bindtype, subtype_a, subtype_b);
 851			goto done;
 852		} else if (axis & RENDER_AXIS_BIT) {
 853			axis = render_axis_part(axis);
 854		} else {
 855			bind_button(hostpadnum, axis, bindtype, subtype_a, subtype_b);
 856			goto done;
 857		}
 858	}
 859	bind_axis(hostpadnum, axis, positive, bindtype, subtype_a, subtype_b);
 860done:
 861	free(key);
 862	return;
 863}
 864
 865static tern_node *get_pad_buttons()
 866{
 867	static tern_node *padbuttons;
 868	if (!padbuttons) {
 869		padbuttons = tern_insert_int(NULL, ".up", DPAD_UP);
 870		padbuttons = tern_insert_int(padbuttons, ".down", DPAD_DOWN);
 871		padbuttons = tern_insert_int(padbuttons, ".left", DPAD_LEFT);
 872		padbuttons = tern_insert_int(padbuttons, ".right", DPAD_RIGHT);
 873		padbuttons = tern_insert_int(padbuttons, ".a", BUTTON_A);
 874		padbuttons = tern_insert_int(padbuttons, ".b", BUTTON_B);
 875		padbuttons = tern_insert_int(padbuttons, ".c", BUTTON_C);
 876		padbuttons = tern_insert_int(padbuttons, ".x", BUTTON_X);
 877		padbuttons = tern_insert_int(padbuttons, ".y", BUTTON_Y);
 878		padbuttons = tern_insert_int(padbuttons, ".z", BUTTON_Z);
 879		padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START);
 880		padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE);
 881	}
 882	return padbuttons;
 883}
 884
 885static tern_node *get_mouse_buttons()
 886{
 887	static tern_node *mousebuttons;
 888	if (!mousebuttons) {
 889		mousebuttons = tern_insert_int(NULL, ".left", MOUSE_LEFT);
 890		mousebuttons = tern_insert_int(mousebuttons, ".middle", MOUSE_MIDDLE);
 891		mousebuttons = tern_insert_int(mousebuttons, ".right", MOUSE_RIGHT);
 892		mousebuttons = tern_insert_int(mousebuttons, ".start", MOUSE_START);
 893		mousebuttons = tern_insert_int(mousebuttons, ".motion", PSEUDO_BUTTON_MOTION);
 894	}
 895	return mousebuttons;
 896}
 897
 898tern_node *get_binding_node_for_pad(int padnum)
 899{
 900	if (padnum > MAX_JOYSTICKS) {
 901		return NULL;
 902	}
 903	tern_node * pads = tern_find_path(config, "bindings\0pads\0", TVAL_NODE).ptrval;
 904	if (!pads) {
 905		return NULL;
 906	}
 907	char numstr[11];
 908	sprintf(numstr, "%d", padnum);
 909	tern_node * pad = tern_find_node(pads, numstr);
 910	if (!pad) {
 911		char *type_id = render_joystick_type_id(padnum);
 912		pad = tern_find_node(pads, type_id);
 913		free(type_id);
 914	}
 915	if (!pad) {
 916		controller_info info = get_controller_info(padnum);
 917		char *key = make_controller_type_key(&info);
 918		pad = tern_find_node(pads, key);
 919		free(key);
 920	}
 921	if (!pad) {
 922		pad = tern_find_node(pads, "default");
 923	}
 924	return pad;
 925}
 926
 927void handle_joy_added(int joystick)
 928{
 929	tern_node *pad = get_binding_node_for_pad(joystick);
 930	if (!pad) {
 931		return;
 932	}
 933	tern_node * dpad_node = tern_find_node(pad, "dpads");
 934	if (dpad_node) {
 935		for (int dpad = 0; dpad < 10; dpad++)
 936		{
 937			char numstr[2] = {dpad + '0', 0};
 938			tern_node * pad_dpad = tern_find_node(dpad_node, numstr);
 939			char * dirs[] = {"up", "down", "left", "right"};
 940			char *render_dirs[] = {"dpup", "dpdown", "dpleft", "dpright"};
 941			int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
 942			for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) {
 943				char * target = tern_find_ptr(pad_dpad, dirs[dir]);
 944				if (target) {
 945					uint8_t subtype_a = 0, subtype_b = 0;
 946					int bindtype = parse_binding_target(joystick, target, get_pad_buttons(), get_mouse_buttons(), &subtype_a, &subtype_b);
 947					int32_t hostbutton = dpad >0 ? -1 : render_translate_input_name(joystick, render_dirs[dir], 0);
 948					if (hostbutton < 0) {
 949						//assume this is a raw dpad mapping
 950						bind_dpad(joystick, dpad, dirnums[dir], bindtype, subtype_a, subtype_b);
 951					} else if (hostbutton & RENDER_DPAD_BIT) {
 952						bind_dpad(joystick, render_dpad_part(hostbutton), render_direction_part(hostbutton), bindtype, subtype_a, subtype_b);
 953					} else if (hostbutton & RENDER_AXIS_BIT) {
 954						//Assume controllers with axes for a d-pad use the conventional directions.
 955						bind_axis(joystick, render_axis_part(hostbutton), dir == 1 || dir == 3 ? 1 : 0, bindtype, subtype_a, subtype_b);
 956					} else {
 957						bind_button(joystick, hostbutton, bindtype, subtype_a, subtype_b);
 958					}
 959				}
 960			}
 961		}
 962	}
 963	tern_node *button_node = tern_find_node(pad, "buttons");
 964	if (button_node) {
 965		pad_button_state state = {
 966			.padnum = joystick,
 967			.padbuttons = get_pad_buttons(),
 968			.mousebuttons = get_mouse_buttons()
 969		};
 970		tern_foreach(button_node, process_pad_button, &state);
 971	}
 972	tern_node *axes_node = tern_find_node(pad, "axes");
 973	if (axes_node) {
 974		pad_button_state state = {
 975			.padnum = joystick,
 976			.padbuttons = get_pad_buttons(),
 977			.mousebuttons = get_mouse_buttons()
 978		};
 979		tern_foreach(axes_node, process_pad_axis, &state);
 980	}
 981}
 982
 983//only handles keyboards and mice as gamepads are handled on hotplug events
 984void set_bindings(void)
 985{
 986	tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP);
 987	special = tern_insert_int(special, "down", RENDERKEY_DOWN);
 988	special = tern_insert_int(special, "left", RENDERKEY_LEFT);
 989	special = tern_insert_int(special, "right", RENDERKEY_RIGHT);
 990	special = tern_insert_int(special, "enter", '\r');
 991	special = tern_insert_int(special, "space", ' ');
 992	special = tern_insert_int(special, "tab", '\t');
 993	special = tern_insert_int(special, "backspace", '\b');
 994	special = tern_insert_int(special, "esc", RENDERKEY_ESC);
 995	special = tern_insert_int(special, "delete", RENDERKEY_DEL);
 996	special = tern_insert_int(special, "lshift", RENDERKEY_LSHIFT);
 997	special = tern_insert_int(special, "rshift", RENDERKEY_RSHIFT);
 998	special = tern_insert_int(special, "lctrl", RENDERKEY_LCTRL);
 999	special = tern_insert_int(special, "rctrl", RENDERKEY_RCTRL);
1000	special = tern_insert_int(special, "lalt", RENDERKEY_LALT);
1001	special = tern_insert_int(special, "ralt", RENDERKEY_RALT);
1002	special = tern_insert_int(special, "home", RENDERKEY_HOME);
1003	special = tern_insert_int(special, "end", RENDERKEY_END);
1004	special = tern_insert_int(special, "pageup", RENDERKEY_PAGEUP);
1005	special = tern_insert_int(special, "pagedown", RENDERKEY_PAGEDOWN);
1006	special = tern_insert_int(special, "f1", RENDERKEY_F1);
1007	special = tern_insert_int(special, "f2", RENDERKEY_F2);
1008	special = tern_insert_int(special, "f3", RENDERKEY_F3);
1009	special = tern_insert_int(special, "f4", RENDERKEY_F4);
1010	special = tern_insert_int(special, "f5", RENDERKEY_F5);
1011	special = tern_insert_int(special, "f6", RENDERKEY_F6);
1012	special = tern_insert_int(special, "f7", RENDERKEY_F7);
1013	special = tern_insert_int(special, "f8", RENDERKEY_F8);
1014	special = tern_insert_int(special, "f9", RENDERKEY_F9);
1015	special = tern_insert_int(special, "f10", RENDERKEY_F10);
1016	special = tern_insert_int(special, "f11", RENDERKEY_F11);
1017	special = tern_insert_int(special, "f12", RENDERKEY_F12);
1018	special = tern_insert_int(special, "select", RENDERKEY_SELECT);
1019	special = tern_insert_int(special, "play", RENDERKEY_PLAY);
1020	special = tern_insert_int(special, "search", RENDERKEY_SEARCH);
1021	special = tern_insert_int(special, "back", RENDERKEY_BACK);
1022	special = tern_insert_int(special, "np0", RENDERKEY_NP0);
1023	special = tern_insert_int(special, "np1", RENDERKEY_NP1);
1024	special = tern_insert_int(special, "np2", RENDERKEY_NP2);
1025	special = tern_insert_int(special, "np3", RENDERKEY_NP3);
1026	special = tern_insert_int(special, "np4", RENDERKEY_NP4);
1027	special = tern_insert_int(special, "np5", RENDERKEY_NP5);
1028	special = tern_insert_int(special, "np6", RENDERKEY_NP6);
1029	special = tern_insert_int(special, "np7", RENDERKEY_NP7);
1030	special = tern_insert_int(special, "np8", RENDERKEY_NP8);
1031	special = tern_insert_int(special, "np9", RENDERKEY_NP9);
1032	special = tern_insert_int(special, "np/", RENDERKEY_NP_DIV);
1033	special = tern_insert_int(special, "np*", RENDERKEY_NP_MUL);
1034	special = tern_insert_int(special, "np-", RENDERKEY_NP_MIN);
1035	special = tern_insert_int(special, "np+", RENDERKEY_NP_PLUS);
1036	special = tern_insert_int(special, "npenter", RENDERKEY_NP_ENTER);
1037	special = tern_insert_int(special, "np.", RENDERKEY_NP_STOP);
1038
1039	tern_node *padbuttons = get_pad_buttons();
1040
1041	tern_node *mousebuttons = get_mouse_buttons();
1042	
1043	tern_node * keys = tern_find_path(config, "bindings\0keys\0", TVAL_NODE).ptrval;
1044	process_keys(keys, special, padbuttons, mousebuttons, NULL);
1045	tern_free(special);
1046	
1047	memset(mice, 0, sizeof(mice));
1048	tern_node * mice = tern_find_path(config, "bindings\0mice\0", TVAL_NODE).ptrval;
1049	if (mice) {
1050		tern_node *buttonmaps[2] = {padbuttons, mousebuttons};
1051		tern_foreach(mice, process_mouse, buttonmaps);
1052	}
1053	tern_node * speed_nodes = tern_find_path(config, "clocks\0speeds\0", TVAL_NODE).ptrval;
1054	speeds = malloc(sizeof(uint32_t));
1055	speeds[0] = 100;
1056	process_speeds(speed_nodes, NULL);
1057	for (int i = 0; i < num_speeds; i++)
1058	{
1059		if (!speeds[i]) {
1060			warning("Speed index %d was not set to a valid percentage!", i);
1061			speeds[i] = 100;
1062		}
1063	}
1064}
1065
1066void bindings_set_mouse_mode(uint8_t mode)
1067{
1068	mouse_mode = mode;
1069	if (mode == MOUSE_RELATIVE) {
1070		render_relative_mouse(1);
1071	}
1072}