# HG changeset patch # User Michael Pavone # Date 1532306926 25200 # Node ID 437e80a700aa0f84c2f12a080cadc5241c190294 # Parent 360d5bab199f3cadec473f8755ae3706941a2ddf Initial heuristics for detecting controller types and showing different labels in UI. Modified controller settings view to first display a list of controllers, only showing mapping after selecting controller diff -r 360d5bab199f -r 437e80a700aa Makefile --- a/Makefile Fri Jul 06 17:39:59 2018 -0700 +++ b/Makefile Sun Jul 22 17:48:46 2018 -0700 @@ -136,7 +136,7 @@ Z80OBJS=z80inst.o z80_to_x86.o AUDIOOBJS=ym2612.o psg.o wave.o CONFIGOBJS=config.o tern.o util.o paths.o -NUKLEAROBJS=$(FONT) nuklear_ui/blastem_nuklear.o nuklear_ui/sfnt.o +NUKLEAROBJS=$(FONT) nuklear_ui/blastem_nuklear.o nuklear_ui/sfnt.o controller_info.o RENDEROBJS=render_sdl.o ppm.o LIBZOBJS=zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/deflate.o zlib/gzclose.o zlib/gzlib.o zlib/gzread.o\ zlib/gzwrite.o zlib/infback.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o zlib/uncompr.o zlib/zutil.o diff -r 360d5bab199f -r 437e80a700aa controller_info.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controller_info.c Sun Jul 22 17:48:46 2018 -0700 @@ -0,0 +1,125 @@ +#include +#include "render_sdl.h" +#include "controller_info.h" + +typedef struct { + char const *name; + controller_info info; +} heuristic; + +heuristic heuristics[] = { + //TODO: Add more heuristic rules + {"DualShock 4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}}, + {"PS4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}}, + {"PS3", {.type = TYPE_PSX, .subtype = SUBTYPE_PS3}}, + {"X360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}}, + {"Xbox 360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}}, + {"X-box 360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}}, + {"Xbox One", {.type = TYPE_XBOX, .subtype = SUBTYPE_XBONE}}, + {"X-box One", {.type = TYPE_XBOX, .subtype = SUBTYPE_XBONE}}, + {"WiiU", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_WIIU}}, + {"Wii U", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_WIIU}}, + {"Nintendo Switch", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_SWITCH}}, + {"Saturn", {.type = TYPE_SEGA, .subtype = SUBTYPE_SATURN}} +}; +const uint32_t num_heuristics = sizeof(heuristics)/sizeof(*heuristics); + +controller_info get_controller_info(int joystick) +{ + SDL_GameController *control = render_get_controller(joystick); + if (!control) { + return (controller_info) { + .type = TYPE_UNKNOWN, + .subtype = SUBTYPE_UNKNOWN, + .variant = VARIANT_NORMAL, + .name = SDL_JoystickName(render_get_joystick(joystick)) + }; + } + const char *name = SDL_GameControllerName(control); + SDL_GameControllerClose(control); + for (uint32_t i = 0; i < num_heuristics; i++) + { + if (strstr(name, heuristics[i].name)) { + controller_info res = heuristics[i].info; + res.name = name; + return res; + } + } + //default to a 360 + return (controller_info){ + .type = TYPE_GENERIC_MAPPING, + .subtype = SUBTYPE_UNKNOWN, + .variant = VARIANT_NORMAL, + .name = name + }; +} + +char const *labels_xbox[] = { + "A", "B", "X", "Y", "Back", NULL, "Start", "Click", "Click", "White", "Black", "LT", "RT" +}; +char const *labels_360[] = { + "A", "B", "X", "Y", "Back", "Guide", "Start", "Click", "Click", "LB", "RB", "LT", "RT" +}; +static char const *labels_xbone[] = { + "A", "B", "X", "Y", "View", "Guide", "Menu", "Click", "Click", "LB", "RB", "LT", "RT" +}; +static char const *labels_ps3[] = { + "cross", "circle", "square", "triangle", "Select", "Guide", "Start", "L3", "R3", "L1", "R1", "L2", "R2" +}; +static char const *labels_ps4[] = { + "cross", "circle", "square", "triangle", "Share", "Guide", "Options", "L3", "R3", "L1", "R1", "L2", "R2" +}; +static char const *labels_nintendo[] = { + "B", "A", "Y", "X", "-", "Home", "+", "Click", "Click", "L", "R", "ZL", "ZR" +}; +static char const *labels_genesis[] = { + "A", "B", "X", "Y", NULL, NULL, "Start", NULL, NULL, "Z", "C", NULL, "Mode" +}; +static char const *labels_saturn[] = { + "A", "B", "X", "Y", NULL, NULL, "Start", NULL, NULL, "Z", "C", "LT", "RT" +}; + +static const char** label_source(controller_info *info) +{ + if (info->type == TYPE_UNKNOWN || info->type == TYPE_GENERIC_MAPPING || info->subtype ==SUBTYPE_X360) { + return labels_360; + } else if (info->type == TYPE_NINTENDO) { + return labels_nintendo; + } else if (info->type == TYPE_PSX) { + if (info->subtype == SUBTYPE_PS4) { + return labels_ps4; + } else { + return labels_ps3; + } + } else if (info->type == TYPE_XBOX) { + if (info->subtype == SUBTYPE_XBONE) { + return labels_xbone; + } else { + return labels_xbox; + } + } else { + if (info->subtype == SUBTYPE_GENESIS) { + return labels_genesis; + } else { + return labels_saturn; + } + } +} + +const char *get_button_label(controller_info *info, int button) +{ + return label_source(info)[button]; +} + +static char const *axis_labels[] = { + "Left X", "Left Y", "Right X", "Right Y" +}; +const char *get_axis_label(controller_info *info, int axis) +{ + if (axis < SDL_CONTROLLER_AXIS_TRIGGERLEFT) { + return axis_labels[axis]; + } else { + return label_source(info)[axis - SDL_CONTROLLER_AXIS_TRIGGERLEFT + SDL_CONTROLLER_BUTTON_RIGHTSHOULDER + 1]; + } +} + diff -r 360d5bab199f -r 437e80a700aa controller_info.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controller_info.h Sun Jul 22 17:48:46 2018 -0700 @@ -0,0 +1,45 @@ +#ifndef CONTROLLER_INFO_H_ +#define CONTROLLER_INFO_H_ +#include + +enum { + TYPE_UNKNOWN, + TYPE_GENERIC_MAPPING, + TYPE_XBOX, + TYPE_PSX, + TYPE_NINTENDO, + TYPE_SEGA +}; + +enum { + SUBTYPE_UNKNOWN, + SUBTYPE_XBOX, + SUBTYPE_X360, + SUBTYPE_XBONE, + SUBTYPE_PS2, + SUBTYPE_PS3, + SUBTYPE_PS4, + SUBTYPE_WIIU, + SUBTYPE_SWITCH, + SUBTYPE_GENESIS, + SUBTYPE_SATURN +}; + +enum { + VARIANT_NORMAL, + VARIANT_6B_BUMPERS, //C and Z positions are RB and LB respectively + VARIANT_6B_RIGHT //C and Z positions are RT and RB respectively +}; + +typedef struct { + char const *name; + uint8_t type; + uint8_t subtype; + uint8_t variant; +} controller_info; + +controller_info get_controller_info(int index); +const char *get_button_label(controller_info *info, int button); +const char *get_axis_label(controller_info *info, int axis); + +#endif //CONTROLLER_INFO_H_ \ No newline at end of file diff -r 360d5bab199f -r 437e80a700aa nuklear_ui/blastem_nuklear.c --- a/nuklear_ui/blastem_nuklear.c Fri Jul 06 17:39:59 2018 -0700 +++ b/nuklear_ui/blastem_nuklear.c Sun Jul 22 17:48:46 2018 -0700 @@ -14,6 +14,7 @@ #include "../config.h" #include "../io.h" #include "../png.h" +#include "../controller_info.h" static struct nk_context *context; @@ -500,11 +501,14 @@ nk_end(context); } } + +static int selected_controller; +static controller_info selected_controller_info; static struct nk_image controller_360_image; static uint32_t controller_360_width, controller_360_height; //#define MIN_BIND_BOX_WIDTH 140 #define MAX_BIND_BOX_WIDTH 350 -void view_controllers(struct nk_context *context) +void view_controller_bindings(struct nk_context *context) { if (nk_begin(context, "Controller Bindings", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) { float orig_height = def_font->handle.height; @@ -554,13 +558,13 @@ nk_group_begin(context, "Action Buttons", NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR); float widths[] = {34, bind_box_width - 60}; nk_layout_row(context, NK_STATIC, 34, 2, widths); - nk_label(context, "A", NK_TEXT_LEFT); + nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_A), NK_TEXT_LEFT); nk_button_label(context, "A"); - nk_label(context, "B", NK_TEXT_LEFT); + nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_B), NK_TEXT_LEFT); nk_button_label(context, "B"); - nk_label(context, "X", NK_TEXT_LEFT); + nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_X), NK_TEXT_LEFT); nk_button_label(context, "X"); - nk_label(context, "Y", NK_TEXT_LEFT); + nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_Y), NK_TEXT_LEFT); nk_button_label(context, "Internal Screenshot"); nk_group_end(context); @@ -578,7 +582,7 @@ nk_button_label(context, "Left"); nk_label(context, "Right", NK_TEXT_LEFT); nk_button_label(context, "Right"); - nk_label(context, "Click", NK_TEXT_LEFT); + nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_LEFTSTICK), NK_TEXT_LEFT); nk_button_label(context, "None"); nk_group_end(context); @@ -594,6 +598,37 @@ } } +void view_controllers(struct nk_context *context) +{ + if (nk_begin(context, "Controllers", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) { + int height = (render_width() - 2*context->style.font->height) / MAX_JOYSTICKS; + int image_width = height * controller_360_width / controller_360_height; + for (int i = 0; i < MAX_JOYSTICKS; i++) + { + SDL_Joystick *joy = render_get_joystick(i); + if (joy) { + controller_info info = get_controller_info(i); + nk_layout_row_begin(context, NK_STATIC, height, 2); + nk_layout_row_push(context, image_width); + nk_image(context, controller_360_image); + nk_layout_row_push(context, render_width() - image_width - 2 * context->style.font->height); + if (nk_button_label(context, info.name)) { + selected_controller = i; + selected_controller_info = info; + push_view(view_controller_bindings); + } + nk_layout_row_end(context); + } + } + nk_layout_row_static(context, context->style.font->height, (render_width() - 2 * context->style.font->height) / 2, 2); + nk_label(context, "", NK_TEXT_LEFT); + if (nk_button_label(context, "Back")) { + pop_view(); + } + nk_end(context); + } +} + void settings_toggle(struct nk_context *context, char *label, char *path, uint8_t def) { uint8_t curval = !strcmp("on", tern_find_path_default(config, path, (tern_val){.ptrval = def ? "on": "off"}, TVAL_PTR).ptrval); diff -r 360d5bab199f -r 437e80a700aa render_sdl.c --- a/render_sdl.c Fri Jul 06 17:39:59 2018 -0700 +++ b/render_sdl.c Sun Jul 22 17:48:46 2018 -0700 @@ -805,6 +805,22 @@ return -1; } +SDL_Joystick *render_get_joystick(int index) +{ + if (index >= MAX_JOYSTICKS) { + return NULL; + } + return joysticks[index]; +} + +SDL_GameController *render_get_controller(int index) +{ + if (index >= MAX_JOYSTICKS) { + return NULL; + } + return SDL_GameControllerOpen(joystick_sdl_index[index]); +} + static uint32_t overscan_top[NUM_VID_STD] = {2, 21}; static uint32_t overscan_bot[NUM_VID_STD] = {1, 17}; static uint32_t overscan_left[NUM_VID_STD] = {13, 13}; diff -r 360d5bab199f -r 437e80a700aa render_sdl.h --- a/render_sdl.h Fri Jul 06 17:39:59 2018 -0700 +++ b/render_sdl.h Sun Jul 22 17:48:46 2018 -0700 @@ -10,5 +10,8 @@ void render_set_ui_render_fun(ui_render_fun); void render_set_event_handler(event_handler handler); 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); + #endif //RENDER_SDL_H_