diff --git a/core/input/gamepad_device.cpp b/core/input/gamepad_device.cpp index 717fd616d..1f87c5159 100644 --- a/core/input/gamepad_device.cpp +++ b/core/input/gamepad_device.cpp @@ -55,188 +55,229 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed) _input_detected = nullptr; return true; } - if (!input_mapper || _maple_port < 0 || _maple_port >= (int)ARRAY_SIZE(kcode)) - return false; - DreamcastKey key = input_mapper->get_button_id(code); - if (key == EMU_BTN_NONE) + if (!input_mapper || _maple_port < 0 || _maple_port > (int)ARRAY_SIZE(kcode)) return false; - if (key < 0x10000) + auto handle_key = [&](u32 port, DreamcastKey key) { - if (pressed) + if (key == EMU_BTN_NONE) + return false; + + if (key < 0x10000) { - kcode[_maple_port] &= ~(u16)key; - // Avoid two opposite dpad keys being pressed simultaneously - switch (key) + if (pressed) { - case DC_DPAD_UP: - kcode[_maple_port] |= (u16)DC_DPAD_DOWN; - break; - case DC_DPAD_DOWN: - kcode[_maple_port] |= (u16)DC_DPAD_UP; - break; - case DC_DPAD_LEFT: - kcode[_maple_port] |= (u16)DC_DPAD_RIGHT; - break; - case DC_DPAD_RIGHT: - kcode[_maple_port] |= (u16)DC_DPAD_LEFT; - break; - case DC_DPAD2_UP: - kcode[_maple_port] |= (u16)DC_DPAD2_DOWN; - break; - case DC_DPAD2_DOWN: - kcode[_maple_port] |= (u16)DC_DPAD2_UP; - break; - case DC_DPAD2_LEFT: - kcode[_maple_port] |= (u16)DC_DPAD2_RIGHT; - break; - case DC_DPAD2_RIGHT: - kcode[_maple_port] |= (u16)DC_DPAD2_LEFT; - break; - default: - break; + kcode[port] &= ~(u16)key; + // Avoid two opposite dpad keys being pressed simultaneously + switch (key) + { + case DC_DPAD_UP: + kcode[port] |= (u16)DC_DPAD_DOWN; + break; + case DC_DPAD_DOWN: + kcode[port] |= (u16)DC_DPAD_UP; + break; + case DC_DPAD_LEFT: + kcode[port] |= (u16)DC_DPAD_RIGHT; + break; + case DC_DPAD_RIGHT: + kcode[port] |= (u16)DC_DPAD_LEFT; + break; + case DC_DPAD2_UP: + kcode[port] |= (u16)DC_DPAD2_DOWN; + break; + case DC_DPAD2_DOWN: + kcode[port] |= (u16)DC_DPAD2_UP; + break; + case DC_DPAD2_LEFT: + kcode[port] |= (u16)DC_DPAD2_RIGHT; + break; + case DC_DPAD2_RIGHT: + kcode[port] |= (u16)DC_DPAD2_LEFT; + break; + default: + break; + } } + else + kcode[port] |= (u16)key; +#ifdef TEST_AUTOMATION + if (record_input != NULL) + fprintf(record_input, "%ld button %x %04x\n", sh4_sched_now64(), port, kcode[port]); +#endif } else - kcode[_maple_port] |= (u16)key; -#ifdef TEST_AUTOMATION - if (record_input != NULL) - fprintf(record_input, "%ld button %x %04x\n", sh4_sched_now64(), _maple_port, kcode[_maple_port]); -#endif + { + switch (key) + { + case EMU_BTN_ESCAPE: + if (pressed) + dc_exit(); + break; + case EMU_BTN_MENU: + if (pressed) + gui_open_settings(); + break; + case EMU_BTN_FFORWARD: + if (pressed) + fast_forward_mode = !fast_forward_mode; + break; + case EMU_BTN_TRIGGER_LEFT: + lt[port] = pressed ? 255 : 0; + break; + case EMU_BTN_TRIGGER_RIGHT: + rt[port] = pressed ? 255 : 0; + break; + case EMU_BTN_ANA_UP: + joyy[port] = pressed ? -128 : 0; + break; + case EMU_BTN_ANA_DOWN: + joyy[port] = pressed ? 127 : 0; + break; + case EMU_BTN_ANA_LEFT: + joyx[port] = pressed ? -128 : 0; + break; + case EMU_BTN_ANA_RIGHT: + joyx[port] = pressed ? 127 : 0; + break; + default: + return false; + } + } + + DEBUG_LOG(INPUT, "%d: BUTTON %s %x -> %d. kcode=%x", port, pressed ? "down" : "up", code, key, kcode[port]); + + return true; + }; + + bool rc = false; + if (_maple_port == 4) + { + for (int port = 0; port < 4; port++) + { + DreamcastKey key = input_mapper->get_button_id(port, code); + rc = handle_key(port, key) || rc; + } } else { - switch (key) - { - case EMU_BTN_ESCAPE: - if (pressed) - dc_exit(); - break; - case EMU_BTN_MENU: - if (pressed) - gui_open_settings(); - break; - case EMU_BTN_FFORWARD: - if (pressed) - fast_forward_mode = !fast_forward_mode; - break; - case EMU_BTN_TRIGGER_LEFT: - lt[_maple_port] = pressed ? 255 : 0; - break; - case EMU_BTN_TRIGGER_RIGHT: - rt[_maple_port] = pressed ? 255 : 0; - break; - case EMU_BTN_ANA_UP: - joyy[_maple_port] = pressed ? -128 : 0; - break; - case EMU_BTN_ANA_DOWN: - joyy[_maple_port] = pressed ? 127 : 0; - break; - case EMU_BTN_ANA_LEFT: - joyx[_maple_port] = pressed ? -128 : 0; - break; - case EMU_BTN_ANA_RIGHT: - joyx[_maple_port] = pressed ? 127 : 0; - break; - default: - return false; - } + DreamcastKey key = input_mapper->get_button_id(0, code); + rc = handle_key(_maple_port, key); } - DEBUG_LOG(INPUT, "%d: BUTTON %s %x -> %d. kcode=%x", _maple_port, pressed ? "down" : "up", code, key, kcode[_maple_port]); - return true; + return rc; } bool GamepadDevice::gamepad_axis_input(u32 code, int value) { s32 v; - if (input_mapper->get_axis_inverted(code)) + if (input_mapper->get_axis_inverted(0, code)) v = (get_axis_min_value(code) + get_axis_range(code) - value) * 255 / get_axis_range(code) - 128; else v = (value - get_axis_min_value(code)) * 255 / get_axis_range(code) - 128; //-128 ... +127 range - if (_input_detected != NULL && !_detecting_button + if (_input_detected != NULL && !_detecting_button && os_GetSeconds() >= _detection_start_time && (v >= 64 || v <= -64)) { _input_detected(code); _input_detected = NULL; return true; } - if (!input_mapper || _maple_port < 0 || _maple_port >= (int)ARRAY_SIZE(kcode)) + if (!input_mapper || _maple_port < 0 || _maple_port > 4) return false; - DreamcastKey key = input_mapper->get_axis_id(code); - if ((int)key < 0x10000) + auto handle_axis = [&](u32 port, DreamcastKey key) { - kcode[_maple_port] |= key | (key << 1); - if (v <= -64) - kcode[_maple_port] &= ~key; - else if (v >= 64) - kcode[_maple_port] &= ~(key << 1); - // printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2)); - } - else if (((int)key >> 16) == 1) // Triggers - { - //printf("T-AXIS %d Mapped to %d -> %d\n",key, value, v + 128); - - if (key == DC_AXIS_LT) - lt[_maple_port] = (u8)(v + 128); - else if (key == DC_AXIS_RT) - rt[_maple_port] = (u8)(v + 128); - else - return false; - } - else if (((int)key >> 16) == 2) // Analog axes - { - //printf("AXIS %d Mapped to %d -> %d\n", key, value, v); - s8 *this_axis; - s8 *other_axis; - switch (key) + if ((int)key < 0x10000) { - case DC_AXIS_X: - this_axis = &joyx[_maple_port]; - other_axis = &joyy[_maple_port]; - break; + kcode[port] |= key | (key << 1); + if (v <= -64) + kcode[port] &= ~key; + else if (v >= 64) + kcode[port] &= ~(key << 1); - case DC_AXIS_Y: - this_axis = &joyy[_maple_port]; - other_axis = &joyx[_maple_port]; - break; - - case DC_AXIS_X2: - this_axis = &joyrx[_maple_port]; - other_axis = &joyry[_maple_port]; - break; - - case DC_AXIS_Y2: - this_axis = &joyry[_maple_port]; - other_axis = &joyrx[_maple_port]; - break; - - default: - return false; + // printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2)); } - // Radial dead zone - // FIXME compute both axes at the same time - if ((float)(v * v + *other_axis * *other_axis) < input_mapper->dead_zone * input_mapper->dead_zone * 128.f * 128.f) + else if (((int)key >> 16) == 1) // Triggers { - *this_axis = 0; - *other_axis = 0; + //printf("T-AXIS %d Mapped to %d -> %d\n",key, value, v + 128); + + if (key == DC_AXIS_LT) + lt[port] = (u8)(v + 128); + else if (key == DC_AXIS_RT) + rt[port] = (u8)(v + 128); + else + return false; + } + else if (((int)key >> 16) == 2) // Analog axes + { + //printf("AXIS %d Mapped to %d -> %d\n", key, value, v); + s8 *this_axis; + s8 *other_axis; + switch (key) + { + case DC_AXIS_X: + this_axis = &joyx[port]; + other_axis = &joyy[port]; + break; + + case DC_AXIS_Y: + this_axis = &joyy[port]; + other_axis = &joyx[port]; + break; + + case DC_AXIS_X2: + this_axis = &joyrx[port]; + other_axis = &joyry[port]; + break; + + case DC_AXIS_Y2: + this_axis = &joyry[port]; + other_axis = &joyrx[port]; + break; + + default: + return false; + } + // Radial dead zone + // FIXME compute both axes at the same time + if ((float)(v * v + *other_axis * *other_axis) < input_mapper->dead_zone * input_mapper->dead_zone * 128.f * 128.f) + { + *this_axis = 0; + *other_axis = 0; + } + else + *this_axis = (s8)v; + } + else if (((int)key >> 16) == 4) // Map triggers to digital buttons + { + if (v <= -64) + kcode[port] |= (key & ~0x40000); // button released + else if (v >= 64) + kcode[port] &= ~(key & ~0x40000); // button pressed } else - *this_axis = (s8)v; - } - else if (((int)key >> 16) == 4) // Map triggers to digital buttons + return false; + + return true; + }; + + bool rc = false; + if (_maple_port == 4) { - if (v <= -64) - kcode[_maple_port] |= (key & ~0x40000); // button released - else if (v >= 64) - kcode[_maple_port] &= ~(key & ~0x40000); // button pressed + for (u32 port = 0; port < 4; port++) + { + DreamcastKey key = input_mapper->get_axis_id(port, code); + rc = handle_axis(port, key) || rc; + } } else - return false; + { + DreamcastKey key = input_mapper->get_axis_id(0, code); + rc = handle_axis(_maple_port, key); + } - return true; + return rc; } int GamepadDevice::get_axis_min_value(u32 axis) { diff --git a/core/input/mapping.cpp b/core/input/mapping.cpp index 0cf3f6a75..e5f5a0254 100644 --- a/core/input/mapping.cpp +++ b/core/input/mapping.cpp @@ -96,35 +96,35 @@ axis_list[] = std::map> InputMapping::loaded_mappings; -void InputMapping::set_button(DreamcastKey id, u32 code) +void InputMapping::set_button(u32 port, DreamcastKey id, u32 code) { if (id != EMU_BTN_NONE) { while (true) { - u32 code = get_button_code(id); + u32 code = get_button_code(port, id); if (code == (u32)-1) break; - buttons[code] = EMU_BTN_NONE; + buttons[port][code] = EMU_BTN_NONE; } - buttons[code] = id; + buttons[port][code] = id; dirty = true; } } -void InputMapping::set_axis(DreamcastKey id, u32 code, bool is_inverted) +void InputMapping::set_axis(u32 port, DreamcastKey id, u32 code, bool is_inverted) { if (id != EMU_AXIS_NONE) { while (true) { - u32 code = get_axis_code(id); + u32 code = get_axis_code(port, id); if (code == (u32)-1) break; - axes[code] = EMU_AXIS_NONE; + axes[port][code] = EMU_AXIS_NONE; } - axes[code] = id; - axes_inverted[code] = is_inverted; + axes[port][code] = id; + axes_inverted[port][code] = is_inverted; dirty = true; } } @@ -144,29 +144,44 @@ void InputMapping::load(FILE* fp) this->dead_zone = (float)dz / 100.f; - for (u32 i = 0; i < ARRAY_SIZE(button_list); i++) + for (int port = 0; port < 4; port++) { - int button_code = mf.get_int(button_list[i].section, button_list[i].option, -1); - if (button_code >= 0) + for (u32 i = 0; i < ARRAY_SIZE(button_list); i++) { - this->set_button(button_list[i].id, button_code); + std::string option; + if (port == 0) + option = button_list[i].option; + else + option = button_list[i].option + std::to_string(port); + int button_code = mf.get_int(button_list[i].section, option, -1); + if (button_code >= 0) + this->set_button(port, button_list[i].id, button_code); } - } - for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++) - { - int axis_code = mf.get_int(axis_list[i].section, axis_list[i].option, -1); - if (axis_code >= 0) + for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++) { - this->set_axis(axis_list[i].id, axis_code, mf.get_bool(axis_list[i].section_inverted, axis_list[i].option_inverted, false)); + std::string option; + if (port == 0) + option = axis_list[i].option; + else + option = axis_list[i].option + std::to_string(port); + int axis_code = mf.get_int(axis_list[i].section, option, -1); + if (axis_code >= 0) + { + if (port == 0) + option = axis_list[i].option_inverted; + else + option = axis_list[i].option_inverted + std::to_string(port); + this->set_axis(port, axis_list[i].id, axis_code, mf.get_bool(axis_list[i].section_inverted, option, false)); + } } } dirty = false; } -u32 InputMapping::get_button_code(DreamcastKey key) +u32 InputMapping::get_button_code(u32 port, DreamcastKey key) { - for (auto& it : buttons) + for (auto& it : buttons[port]) { if (it.second == key) return it.first; @@ -174,9 +189,9 @@ u32 InputMapping::get_button_code(DreamcastKey key) return -1; } -u32 InputMapping::get_axis_code(DreamcastKey key) +u32 InputMapping::get_axis_code(u32 port, DreamcastKey key) { - for (auto& it : axes) + for (auto& it : axes[port]) { if (it.second == key) return it.first; @@ -221,23 +236,43 @@ bool InputMapping::save(const char *name) mf.set("emulator", "mapping_name", this->name); mf.set_int("emulator", "dead_zone", (int)std::round(this->dead_zone * 100.f)); - for (u32 i = 0; i < ARRAY_SIZE(button_list); i++) + for (int port = 0; port < 4; port++) { - for (auto& it : buttons) + for (u32 i = 0; i < ARRAY_SIZE(button_list); i++) { - if (it.second == button_list[i].id) - mf.set_int(button_list[i].section, button_list[i].option, (int)it.first); - } - } + std::string option; + if (port == 0) + option = button_list[i].option; + else + option = button_list[i].option + std::to_string(port); - for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++) - { - for (auto& it : axes) - { - if (it.second == axis_list[i].id) + for (auto& it : buttons[port]) { - mf.set_int(axis_list[i].section, axis_list[i].option, (int)it.first); - mf.set_bool(axis_list[i].section_inverted, axis_list[i].option_inverted, axes_inverted[it.first]); + if (it.second == button_list[i].id) + mf.set_int(button_list[i].section, option, (int)it.first); + } + } + + for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++) + { + std::string option; + if (port == 0) + option = axis_list[i].option; + else + option = axis_list[i].option + std::to_string(port); + std::string option_inverted; + if (port == 0) + option_inverted = axis_list[i].option_inverted; + else + option_inverted = axis_list[i].option_inverted + std::to_string(port); + + for (auto& it : axes[port]) + { + if (it.second == axis_list[i].id) + { + mf.set_int(axis_list[i].section, option, (int)it.first); + mf.set_bool(axis_list[i].section_inverted, option_inverted, axes_inverted[port][it.first]); + } } } } diff --git a/core/input/mapping.h b/core/input/mapping.h index a77585705..c68579ab7 100644 --- a/core/input/mapping.h +++ b/core/input/mapping.h @@ -31,43 +31,48 @@ public: InputMapping(const InputMapping& other) { name = other.name; dead_zone = other.dead_zone; - buttons = other.buttons; - axes = other.axes; - axes_inverted = other.axes_inverted; + for (int port = 0; port < 4; port++) + { + buttons[port] = other.buttons[port]; + axes[port] = other.axes[port]; + axes_inverted[port] = other.axes_inverted[port]; + } } std::string name; - float dead_zone; + float dead_zone = 0.1f; - DreamcastKey get_button_id(u32 code) + DreamcastKey get_button_id(u32 port, u32 code) { - auto it = buttons.find(code); - if (it != buttons.end()) + auto it = buttons[port].find(code); + if (it != buttons[port].end()) return it->second; else return EMU_BTN_NONE; } - void set_button(DreamcastKey id, u32 code); - u32 get_button_code(DreamcastKey key); + void set_button(u32 port, DreamcastKey id, u32 code); + void set_button(DreamcastKey id, u32 code) { set_button(0, id, code); } + u32 get_button_code(u32 port, DreamcastKey id); - DreamcastKey get_axis_id(u32 code) + DreamcastKey get_axis_id(u32 port, u32 code) { - auto it = axes.find(code); - if (it != axes.end()) + auto it = axes[port].find(code); + if (it != axes[port].end()) return it->second; else return EMU_AXIS_NONE; } - bool get_axis_inverted(u32 code) + bool get_axis_inverted(u32 port, u32 code) { - auto it = axes_inverted.find(code); - if (it != axes_inverted.end()) + auto it = axes_inverted[port].find(code); + if (it != axes_inverted[port].end()) return it->second; else return false; } - u32 get_axis_code(DreamcastKey key); - void set_axis(DreamcastKey id, u32 code, bool inverted); + u32 get_axis_code(u32 port, DreamcastKey key); + void set_axis(u32 port, DreamcastKey id, u32 code, bool inverted); + void set_axis(DreamcastKey id, u32 code, bool inverted) { set_axis(0, id, code, inverted); } void load(FILE* fp); bool save(const char *name); @@ -81,9 +86,9 @@ protected: bool dirty = false; private: - std::map buttons; - std::map axes; - std::map axes_inverted; + std::map buttons[4]; + std::map axes[4]; + std::map axes_inverted[4]; static std::map> loaded_mappings; }; @@ -96,12 +101,12 @@ public: dead_zone = 0.1f; for (int i = 0; i < 32; i++) - set_button((DreamcastKey)(1 << i), 1 << i); - set_axis(DC_AXIS_X, DC_AXIS_X, false); - set_axis(DC_AXIS_Y, DC_AXIS_Y, false); - set_axis(DC_AXIS_LT, DC_AXIS_LT, false); - set_axis(DC_AXIS_RT, DC_AXIS_RT, false); - set_axis(DC_AXIS_X2, DC_AXIS_X2, false); - set_axis(DC_AXIS_Y2, DC_AXIS_Y2, false); + set_button(0, (DreamcastKey)(1 << i), 1 << i); + set_axis(0, DC_AXIS_X, DC_AXIS_X, false); + set_axis(0, DC_AXIS_Y, DC_AXIS_Y, false); + set_axis(0, DC_AXIS_LT, DC_AXIS_LT, false); + set_axis(0, DC_AXIS_RT, DC_AXIS_RT, false); + set_axis(0, DC_AXIS_X2, DC_AXIS_X2, false); + set_axis(0, DC_AXIS_Y2, DC_AXIS_Y2, false); } }; diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index a952fe6bf..c6d275bdf 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -442,7 +442,7 @@ static const char *maple_expansion_device_name(MapleDeviceType type) } } -const char *maple_ports[] = { "None", "A", "B", "C", "D" }; +const char *maple_ports[] = { "None", "A", "B", "C", "D", "All" }; const DreamcastKey button_keys[] = { DC_BTN_START, DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, DC_DPAD_UP, DC_DPAD_DOWN, DC_DPAD_LEFT, DC_DPAD_RIGHT, EMU_BTN_MENU, EMU_BTN_ESCAPE, EMU_BTN_FFORWARD, EMU_BTN_TRIGGER_LEFT, EMU_BTN_TRIGGER_RIGHT, @@ -500,6 +500,7 @@ static std::shared_ptr mapped_device; static u32 mapped_code; static double map_start_time; static bool arcade_button_mode; +static u32 gamepad_port; static void input_detected(u32 code) { @@ -525,15 +526,15 @@ static void detect_input_popup(int index, bool analog) { if (analog) { - u32 previous_mapping = input_mapping->get_axis_code(axis_keys[index]); + u32 previous_mapping = input_mapping->get_axis_code(gamepad_port, axis_keys[index]); bool inverted = false; if (previous_mapping != (u32)-1) - inverted = input_mapping->get_axis_inverted(previous_mapping); + inverted = input_mapping->get_axis_inverted(gamepad_port, previous_mapping); // FIXME Allow inverted to be set - input_mapping->set_axis(axis_keys[index], mapped_code, inverted); + input_mapping->set_axis(gamepad_port, axis_keys[index], mapped_code, inverted); } else - input_mapping->set_button(button_keys[index], mapped_code); + input_mapping->set_button(gamepad_port, button_keys[index], mapped_code); } mapped_device = NULL; ImGui::CloseCurrentPopup(); @@ -569,6 +570,26 @@ static void controller_mapping_popup(std::shared_ptr gamepad) gamepad->save_mapping(); } ImGui::SetItemDefaultFocus(); + + if (gamepad->maple_port() == MAPLE_PORTS) + { + ImGui::SameLine(); + float w = ImGui::CalcItemWidth(); + ImGui::PushItemWidth(w / 2); + if (ImGui::BeginCombo("Port", maple_ports[gamepad_port + 1])) + { + for (u32 j = 0; j < MAPLE_PORTS; j++) + { + bool is_selected = gamepad_port == j; + if (ImGui::Selectable(maple_ports[j + 1], &is_selected)) + gamepad_port = j; + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + ImGui::PopItemWidth(); + } ImGui::SameLine(ImGui::GetContentRegionAvailWidth() - ImGui::CalcTextSize("Arcade button names").x - ImGui::GetStyle().FramePadding.x * 3.0f - ImGui::GetStyle().ItemSpacing.x); ImGui::Checkbox("Arcade button names", &arcade_button_mode); @@ -587,7 +608,7 @@ static void controller_mapping_popup(std::shared_ptr gamepad) ImGui::PushID(key_id); ImGui::Text("%s", arcade_button_mode ? arcade_button_names[j] : button_names[j]); ImGui::NextColumn(); - u32 code = input_mapping->get_button_code(button_keys[j]); + u32 code = input_mapping->get_button_code(gamepad_port, button_keys[j]); if (code != (u32)-1) { const char *label = gamepad->get_button_name(code); @@ -627,7 +648,7 @@ static void controller_mapping_popup(std::shared_ptr gamepad) ImGui::PushID(key_id); ImGui::Text("%s", arcade_button_mode ? arcade_axis_names[j] : axis_names[j]); ImGui::NextColumn(); - u32 code = input_mapping->get_axis_code(axis_keys[j]); + u32 code = input_mapping->get_axis_code(gamepad_port, axis_keys[j]); if (code != (u32)-1) { const char *label = gamepad->get_axis_name(code); @@ -1015,7 +1036,7 @@ static void gui_display_settings() ImGui::PushID(port_name); if (ImGui::BeginCombo(port_name, maple_ports[gamepad->maple_port() + 1])) { - for (int j = -1; j < MAPLE_PORTS; j++) + for (int j = -1; j < (int)ARRAY_SIZE(maple_ports) - 1; j++) { bool is_selected = gamepad->maple_port() == j; if (ImGui::Selectable(maple_ports[j + 1], &is_selected)) @@ -1028,7 +1049,10 @@ static void gui_display_settings() } ImGui::NextColumn(); if (gamepad->remappable() && ImGui::Button("Map")) + { + gamepad_port = 0; ImGui::OpenPopup("Controller Mapping"); + } controller_mapping_popup(gamepad);