diff bindings.c @ 2053:3414a4423de1 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 15 Jan 2022 13:15:21 -0800
parents 81df9aa2de9b
children 372625dd9590
line wrap: on
line diff
--- a/bindings.c	Sat Jan 05 00:58:08 2019 -0800
+++ b/bindings.c	Sat Jan 15 13:15:21 2022 -0800
@@ -1,4 +1,5 @@
 #include <string.h>
+#include <stdlib.h>
 #include "render.h"
 #include "system.h"
 #include "io.h"
@@ -35,6 +36,7 @@
 	UI_RELOAD,
 	UI_SMS_PAUSE,
 	UI_SCREENSHOT,
+	UI_VGM_LOG,
 	UI_EXIT,
 	UI_PLANE_DEBUG,
 	UI_VRAM_DEBUG,
@@ -257,17 +259,51 @@
 #define localtime_r(a,b) localtime(a)
 #endif
 
+char *get_content_config_path(char *config_path, char *config_template, char *default_name)
+{
+	char *base = tern_find_path(config, config_path, TVAL_PTR).ptrval;
+	if (!base) {
+		base = "$HOME";
+	}
+	const system_media *media = current_media();
+	tern_node *vars = tern_insert_ptr(NULL, "HOME", get_home_dir());
+	vars = tern_insert_ptr(vars, "EXEDIR", get_exe_dir());
+	vars = tern_insert_ptr(vars, "USERDATA", (char *)get_userdata_dir());
+	vars = tern_insert_ptr(vars, "ROMNAME", media->name);
+	vars = tern_insert_ptr(vars, "ROMDIR", media->dir);
+	base = replace_vars(base, vars, 1);
+	tern_free(vars);
+	ensure_dir_exists(base);
+	time_t now = time(NULL);
+	struct tm local_store;
+	char fname_part[256];
+	char *template = tern_find_path(config, config_template, TVAL_PTR).ptrval;
+	if (template) {
+		vars = tern_insert_ptr(NULL, "ROMNAME", media->name);
+		template = replace_vars(template, vars, 0);
+	} else {
+		template = strdup(default_name);
+	}
+	strftime(fname_part, sizeof(fname_part), template, localtime_r(&now, &local_store));
+	char const *parts[] = {base, PATH_SEP, fname_part};
+	char *path = alloc_concat_m(3, parts);
+	free(base);
+	free(template);
+	return path;
+}
+
 void handle_binding_up(keybinding * binding)
 {
+	uint8_t allow_content_binds = content_binds_enabled && current_system;
 	switch(binding->bind_type)
 	{
 	case BIND_GAMEPAD:
-		if (content_binds_enabled && current_system->gamepad_up) {
+		if (allow_content_binds && current_system->gamepad_up) {
 			current_system->gamepad_up(current_system, binding->subtype_a, binding->subtype_b);
 		}
 		break;
 	case BIND_MOUSE:
-		if (content_binds_enabled && current_system->mouse_up) {
+		if (allow_content_binds && current_system->mouse_up) {
 			current_system->mouse_up(current_system, binding->subtype_a, binding->subtype_b);
 		}
 		break;
@@ -275,22 +311,22 @@
 		switch (binding->subtype_a)
 		{
 		case UI_DEBUG_MODE_INC:
-			if (content_binds_enabled) {
+			if (allow_content_binds) {
 				current_system->inc_debug_mode(current_system);
 			}
 			break;
 		case UI_ENTER_DEBUGGER:
-			if (content_binds_enabled) {
+			if (allow_content_binds) {
 				current_system->enter_debugger = 1;
 			}
 			break;
 		case UI_SAVE_STATE:
-			if (content_binds_enabled) {
+			if (allow_content_binds) {
 				current_system->save_state = QUICK_SAVE_SLOT+1;
 			}
 			break;
 		case UI_NEXT_SPEED:
-			if (content_binds_enabled) {
+			if (allow_content_binds) {
 				current_speed++;
 				if (current_speed >= num_speeds) {
 					current_speed = 0;
@@ -300,7 +336,7 @@
 			}
 			break;
 		case UI_PREV_SPEED:
-			if (content_binds_enabled) {
+			if (allow_content_binds) {
 				current_speed--;
 				if (current_speed < 0) {
 					current_speed = num_speeds - 1;
@@ -310,7 +346,7 @@
 			}
 			break;
 		case UI_SET_SPEED:
-			if (content_binds_enabled) {
+			if (allow_content_binds) {
 				if (binding->subtype_b < num_speeds) {
 					current_speed = binding->subtype_b;
 					printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
@@ -328,7 +364,7 @@
 			}
 			break;
 		case UI_TOGGLE_KEYBOARD_CAPTURE:
-			if (content_binds_enabled && current_system->has_keyboard) {
+			if (allow_content_binds && current_system->has_keyboard) {
 				keyboard_captured = !keyboard_captured;
 			}
 			break;
@@ -336,52 +372,44 @@
 			render_toggle_fullscreen();
 			break;
 		case UI_SOFT_RESET:
-			if (content_binds_enabled) {
+			if (allow_content_binds) {
 				current_system->soft_reset(current_system);
 			}
 			break;
 		case UI_RELOAD:
-			if (content_binds_enabled) {
+			if (allow_content_binds) {
 				reload_media();
 			}
 			break;
 		case UI_SMS_PAUSE:
-			if (content_binds_enabled && current_system->gamepad_down) {
+			if (allow_content_binds && current_system->gamepad_down) {
 				current_system->gamepad_down(current_system, GAMEPAD_MAIN_UNIT, MAIN_UNIT_PAUSE);
 			}
 			break;
-		case UI_SCREENSHOT: {
-			if (content_binds_enabled) {
-				char *screenshot_base = tern_find_path(config, "ui\0screenshot_path\0", TVAL_PTR).ptrval;
-				if (!screenshot_base) {
-					screenshot_base = "$HOME";
-				}
-				tern_node *vars = tern_insert_ptr(NULL, "HOME", get_home_dir());
-				vars = tern_insert_ptr(vars, "EXEDIR", get_exe_dir());
-				screenshot_base = replace_vars(screenshot_base, vars, 1);
-				tern_free(vars);
-				time_t now = time(NULL);
-				struct tm local_store;
-				char fname_part[256];
-				char *template = tern_find_path(config, "ui\0screenshot_template\0", TVAL_PTR).ptrval;
-				if (!template) {
-					template = "blastem_%c.ppm";
-				}
-				strftime(fname_part, sizeof(fname_part), template, localtime_r(&now, &local_store));
-				char const *parts[] = {screenshot_base, PATH_SEP, fname_part};
-				char *path = alloc_concat_m(3, parts);
-				free(screenshot_base);
+		case UI_SCREENSHOT:
+			if (allow_content_binds) {
+				char *path = get_content_config_path("ui\0screenshot_path\0", "ui\0screenshot_template\0", "blastem_%c.ppm");
 				render_save_screenshot(path);
 			}
 			break;
-		}
+		case UI_VGM_LOG:
+			if (allow_content_binds && current_system->start_vgm_log) {
+				if (current_system->vgm_logging) {
+					current_system->stop_vgm_log(current_system);
+				} else {
+					char *path = get_content_config_path("ui\0vgm_path\0", "ui\0vgm_template\0", "blastem_%c.vgm");
+					current_system->start_vgm_log(current_system, path);
+					free(path);
+				}
+			}
+			break;
 		case UI_EXIT:
 #ifndef DISABLE_NUKLEAR
 			if (is_nuklear_active()) {
 				show_pause_menu();
 			} else {
 #endif
-			current_system->request_exit(current_system);
+			system_request_exit(current_system, 1);
 			if (current_system->type == SYSTEM_GENESIS) {
 				genesis_context *gen = (genesis_context *)current_system;
 				if (gen->extra) {
@@ -398,7 +426,7 @@
 		case UI_VRAM_DEBUG: 
 		case UI_CRAM_DEBUG:
 		case UI_COMPOSITE_DEBUG:
-			if (content_binds_enabled) {
+			if (allow_content_binds) {
 				vdp_context *vdp = NULL;
 				if (current_system->type == SYSTEM_GENESIS) {
 					genesis_context *gen = (genesis_context *)current_system;
@@ -556,7 +584,7 @@
 {
 	const int gpadslen = strlen("gamepads.");
 	const int mouselen = strlen("mouse.");
-	if (!strncmp(target, "gamepads.", gpadslen)) {
+	if (startswith(target, "gamepads.")) {
 		int padnum = target[gpadslen] == 'n' ? device_num + 1 : target[gpadslen] - '0';
 		if (padnum >= 1 && padnum <= 8) {
 			int button = tern_find_int(padbuttons, target + gpadslen + 1, 0);
@@ -574,7 +602,7 @@
 		} else {
 			warning("Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]);
 		}
-	} else if(!strncmp(target, "mouse.", mouselen)) {
+	} else if(startswith(target, "mouse.")) {
 		int mousenum = target[mouselen] == 'n' ? device_num + 1 : target[mouselen] - '0';
 		if (mousenum >= 1 && mousenum <= 8) {
 			int button = tern_find_int(mousebuttons, target + mouselen + 1, 0);
@@ -592,7 +620,7 @@
 		} else {
 			warning("Gamepad mapping string '%s' refers to an invalid mouse number %c\n", target, target[mouselen]);
 		}
-	} else if(!strncmp(target, "ui.", strlen("ui."))) {
+	} else if(startswith(target, "ui.")) {
 		if (!strcmp(target + 3, "vdp_debug_mode")) {
 			*subtype_a = UI_DEBUG_MODE_INC;
 		} else if(!strcmp(target + 3, "vdp_debug_pal")) {
@@ -602,7 +630,7 @@
 			*subtype_a = UI_ENTER_DEBUGGER;
 		} else if(!strcmp(target + 3, "save_state")) {
 			*subtype_a = UI_SAVE_STATE;
-		} else if(!strncmp(target + 3, "set_speed.", strlen("set_speed."))) {
+		} else if(startswith(target + 3, "set_speed.")) {
 			*subtype_a = UI_SET_SPEED;
 			*subtype_b = atoi(target + 3 + strlen("set_speed."));
 		} else if(!strcmp(target + 3, "next_speed")) {
@@ -623,6 +651,8 @@
 			*subtype_a = UI_SMS_PAUSE;
 		} else if (!strcmp(target + 3, "screenshot")) {
 			*subtype_a = UI_SCREENSHOT;
+		} else if (!strcmp(target + 3, "vgm_log")) {
+			*subtype_a = UI_VGM_LOG;
 		} else if(!strcmp(target + 3, "exit")) {
 			*subtype_a = UI_EXIT;
 		} else if (!strcmp(target + 3, "plane_debug")) {
@@ -814,7 +844,7 @@
 			if (hostbutton == RENDER_INVALID_NAME) {
 				warning("%s is not a valid gamepad input name\n", key);
 			} else if (hostbutton == RENDER_NOT_MAPPED && hostpadnum != map_warning_pad) {
-				warning("No SDL 2 mapping exists for input %s on gamepad %d\n", key, hostpadnum);
+				debug_message("No SDL 2 mapping exists for input %s on gamepad %d\n", key, hostpadnum);
 				map_warning_pad = hostpadnum;
 			}
 			return;
@@ -823,7 +853,7 @@
 			bind_dpad(hostpadnum, render_dpad_part(hostbutton), render_direction_part(hostbutton), bindtype, subtype_a, subtype_b);
 			return;
 		} else if (hostbutton & RENDER_AXIS_BIT) {
-			bind_axis(hostpadnum, render_axis_part(hostbutton), 1, bindtype, subtype_a, subtype_b);
+			bind_axis(hostpadnum, render_axis_part(hostbutton), hostbutton & RENDER_AXIS_POS, bindtype, subtype_a, subtype_b);
 			return;
 		}
 	}
@@ -861,7 +891,7 @@
 			if (axis == RENDER_INVALID_NAME) {
 				warning("%s is not a valid gamepad input name\n", key);
 			} else if (axis == RENDER_NOT_MAPPED && hostpadnum != map_warning_pad) {
-				warning("No SDL 2 mapping exists for input %s on gamepad %d\n", key, hostpadnum);
+				debug_message("No SDL 2 mapping exists for input %s on gamepad %d\n", key, hostpadnum);
 				map_warning_pad = hostpadnum;
 			}
 			goto done;
@@ -957,14 +987,26 @@
 			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
+			char *render_dirs[] = {"dpup", "dpdown", "dpleft", "dpright"};
 			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);
+					int32_t hostbutton = dpad >0 ? -1 : render_translate_input_name(joystick, render_dirs[dir], 0);
+					if (hostbutton < 0) {
+						//assume this is a raw dpad mapping
+						bind_dpad(joystick, dpad, dirnums[dir], bindtype, subtype_a, subtype_b);
+					} else if (hostbutton & RENDER_DPAD_BIT) {
+						bind_dpad(joystick, render_dpad_part(hostbutton), render_direction_part(hostbutton), bindtype, subtype_a, subtype_b);
+					} else if (hostbutton & RENDER_AXIS_BIT) {
+						//SDL2 knows internally whether this should be a positive or negative binding, but doesn't expose that externally
+						//for now I'll just assume that any controller with axes for a d-pad has these mapped the "sane" way
+						bind_axis(joystick, render_axis_part(hostbutton), dir == 1 || dir == 3 ? 1 : 0, bindtype, subtype_a, subtype_b);
+					} else {
+						bind_button(joystick, hostbutton, bindtype, subtype_a, subtype_b);
+					}
 				}
 			}
 		}