diff --git a/dist/qt_themes/default/icons/256x256/automap_face_buttons.png b/dist/qt_themes/default/icons/256x256/automap_face_buttons.png
new file mode 100644
index 000000000..581192664
Binary files /dev/null and b/dist/qt_themes/default/icons/256x256/automap_face_buttons.png differ
diff --git a/dist/qt_themes/default/theme_default.qrc b/dist/qt_themes/default/theme_default.qrc
index 90ae777aa..4d035c33c 100644
--- a/dist/qt_themes/default/theme_default.qrc
+++ b/dist/qt_themes/default/theme_default.qrc
@@ -15,6 +15,7 @@
icons/48x48/sd_card.png
icons/128x128/cartridge.png
icons/256x256/azahar.png
+ icons/256x256/automap_face_buttons.png
icons/48x48/star.png
icons/256x256/plus_folder.png
diff --git a/src/citra_qt/configuration/configure_input.cpp b/src/citra_qt/configuration/configure_input.cpp
index 196ad8788..6f072a7ad 100644
--- a/src/citra_qt/configuration/configure_input.cpp
+++ b/src/citra_qt/configuration/configure_input.cpp
@@ -531,9 +531,15 @@ void ConfigureInput::MapFromButton(const Common::ParamPackage& params) {
void ConfigureInput::AutoMap() {
ui->buttonAutoMap->setEnabled(false);
- if (QMessageBox::information(this, tr("Information"),
- tr("After pressing OK, press any button on your joystick"),
- QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) {
+ QMessageBox box(this);
+ box.setWindowTitle(tr("Auto map Controller"));
+ box.setText(tr("After pressing OK, press the A (right) button on your gamepad"));
+ box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
+ QPixmap pixmap(QStringLiteral(":/icons/default/256x256/automap_face_buttons.png"));
+ pixmap = pixmap.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ box.setIconPixmap(pixmap);
+ int result = box.exec();
+ if (result == QMessageBox::Cancel) {
ui->buttonAutoMap->setEnabled(true);
return;
}
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 3af010902..3288e6979 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -202,8 +202,8 @@ Common::ParamPackage GetControllerButtonBinds(const Common::ParamPackage& params
const auto native_button{static_cast(button)};
const auto engine{params.Get("engine", "")};
if (engine == "sdl") {
- return dynamic_cast(sdl.get())->GetSDLControllerButtonBind(
- params.Get("guid", "0"), params.Get("port", 0), native_button);
+ return dynamic_cast(sdl.get())->GetSDLControllerButtonBind(params,
+ native_button);
}
#ifdef ENABLE_GCADAPTER
if (engine == "gcpad") {
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 8f246f641..29a972f74 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -169,6 +169,27 @@ constexpr std::array
+ nintendo_to_3ds_mapping = {{
+ SDL_CONTROLLER_BUTTON_A,
+ SDL_CONTROLLER_BUTTON_B,
+ SDL_CONTROLLER_BUTTON_X,
+ SDL_CONTROLLER_BUTTON_Y,
+ SDL_CONTROLLER_BUTTON_DPAD_UP,
+ SDL_CONTROLLER_BUTTON_DPAD_DOWN,
+ SDL_CONTROLLER_BUTTON_DPAD_LEFT,
+ SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
+ SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
+ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
+ SDL_CONTROLLER_BUTTON_START,
+ SDL_CONTROLLER_BUTTON_BACK,
+ SDL_CONTROLLER_BUTTON_INVALID,
+ SDL_CONTROLLER_BUTTON_INVALID,
+ SDL_CONTROLLER_BUTTON_INVALID,
+ SDL_CONTROLLER_BUTTON_INVALID,
+ SDL_CONTROLLER_BUTTON_GUIDE,
+ SDL_CONTROLLER_BUTTON_INVALID,
+ }};
const std::map axis_names = {
{SDL_CONTROLLER_AXIS_LEFTX, "Left Stick X"},
@@ -249,13 +270,31 @@ std::shared_ptr SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
return nullptr;
}
-Common::ParamPackage SDLState::GetSDLControllerButtonBind(const std::string& guid, int port,
- Settings::NativeButton::Values button) {
+/**
+ * Return the button binds param package for the button assuming the params passed in is for the
+ * n3ds "A" button to determine whether this is xbox or nintendo layout. If the passed in button
+ * is neither A nor B, default to xbox layout as the most common on desktop.
+ */
+Common::ParamPackage SDLState::GetSDLControllerButtonBind(
+ const Common::ParamPackage a_button_params, Settings::NativeButton::Values button) {
+ auto guid = a_button_params.Get("guid", 0);
+ auto port = a_button_params.Get("port", 0);
+ auto a_button = a_button_params.Get("button", -1);
+ auto api = a_button_params.Get("api", "joystick");
+ // for xinputs, the "A" or right button would normally register as the B button. But if the
+ // user is either using a nintendo-layout controller or using xinput but would rather the labels
+ // match than the icons, they can press the button that appears as "A" and trigger nintendo
+ // automap
+ bool is_nintendo_layout =
+ api == "controller" && a_button == SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A;
+
Common::ParamPackage params({{"engine", "sdl"}});
params.Set("guid", guid);
params.Set("port", port);
- auto mapped_button = xinput_to_3ds_mapping[static_cast(button)];
+ auto mapped_button = is_nintendo_layout ? nintendo_to_3ds_mapping[static_cast(button)]
+ : xinput_to_3ds_mapping[static_cast(button)];
+
params.Set("api", "controller");
if (button == Settings::NativeButton::Values::ZL) {
params.Set("axis", SDL_CONTROLLER_AXIS_TRIGGERLEFT);
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index 7de96c3f0..3331312ce 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -36,7 +36,7 @@ public:
const std::string& guid);
std::shared_ptr GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
- Common::ParamPackage GetSDLControllerButtonBind(const std::string& guid, int port,
+ Common::ParamPackage GetSDLControllerButtonBind(const Common::ParamPackage a_button_params,
Settings::NativeButton::Values button);
Common::ParamPackage GetSDLControllerAnalogBindByGUID(const std::string& guid, int port,
Settings::NativeAnalog::Values analog);