From 9d4edd4e88d291aa4b778b74f6e9daa9dd358d2b Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 13 Sep 2020 09:25:22 -0400
Subject: [PATCH 01/37] ui/themes: Cleanup UI

---
 dist/qt_themes/default/style.qss              |  14 +-
 dist/qt_themes/qdarkstyle/style.qss           |  71 ++----
 .../qdarkstyle_midnight_blue/style.qss        |  81 ++----
 src/yuzu/aboutdialog.ui                       |  20 --
 src/yuzu/applets/controller.ui                |  31 +--
 src/yuzu/configuration/configure.ui           |  20 --
 .../configure_debug_controller.ui             |  20 --
 src/yuzu/configuration/configure_input.ui     |  24 +-
 .../configure_input_advanced.cpp              |   4 +-
 .../configuration/configure_input_advanced.ui | 192 +++++++-------
 .../configuration/configure_input_player.ui   | 241 ++++++++++--------
 .../configuration/configure_motion_touch.ui   |  10 -
 .../configuration/configure_mouse_advanced.ui |  46 +---
 src/yuzu/configuration/configure_per_game.ui  |  20 --
 .../configure_touch_from_button.ui            |  10 -
 .../configure_touchscreen_advanced.ui         |  22 +-
 16 files changed, 326 insertions(+), 500 deletions(-)

diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss
index b6dd2063d..836dd25ca 100644
--- a/dist/qt_themes/default/style.qss
+++ b/dist/qt_themes/default/style.qss
@@ -1,3 +1,7 @@
+QAbstractSpinBox {
+    min-height: 19px;
+}
+
 QPushButton#TogglableStatusBarButton {
     color: #959595;
     border: 1px solid transparent;
@@ -35,10 +39,10 @@ QPushButton#RendererStatusBarButton:!checked {
 }
 
 QPushButton#buttonRefreshDevices {
-    min-width: 20px;
-    min-height: 20px;
-    max-width: 20px;
-    max-height: 20px;
+    min-width: 21px;
+    min-height: 21px;
+    max-width: 21px;
+    max-height: 21px;
 }
 
 QWidget#bottomPerGameInput,
@@ -71,7 +75,7 @@ QWidget#middleControllerApplet {
 
 QWidget#topPerGameInput QComboBox,
 QWidget#middleControllerApplet QComboBox {
-    width: 123px;
+    width: 120px;
 }
 
 QWidget#connectedControllers {
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 66026e8be..aca6531ac 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -99,12 +99,19 @@ QGroupBox::indicator:unchecked:disabled {
 }
 
 QRadioButton {
-    spacing: 5px;
-    outline: none;
     color: #eff0f1;
+    spacing: 3px;
+    padding: 0px;
+    border: none;
+    outline: none;
     margin-bottom: 2px;
 }
 
+QGroupBox QRadioButton {
+    padding-left: 0px;
+    padding-right: 7px;
+}
+
 QRadioButton:disabled {
     color: #76797C;
 }
@@ -522,13 +529,12 @@ QToolButton#qt_toolbar_ext_button {
 
 QPushButton {
     color: #eff0f1;
-    border-width: 1px;
-    border-color: #54575B;
-    border-style: solid;
-    padding: 6px 4px;
+    border: 1px solid #54575B;
     border-radius: 2px;
+    padding: 5px 0px 5px 0px;
     outline: none;
     min-width: 100px;
+    min-height: 13px;
     background-color: #232629;
 }
 
@@ -553,8 +559,9 @@ QComboBox {
     selection-background-color: #3daee9;
     border: 1px solid #54575B;
     border-radius: 2px;
-    padding: 4px 6px;
-    min-width: 75px;
+    padding: 0px 4px 0px 4px;
+    min-width: 60px;
+    min-height: 23px;
     background-color: #232629;
 }
 
@@ -608,26 +615,26 @@ QComboBox::down-arrow:focus {
 }
 
 QAbstractSpinBox {
-    padding: 4px 6px;
     border: 1px solid #54575B;
     background-color: #232629;
     color: #eff0f1;
     border-radius: 2px;
-    min-width: 75px;
+    min-width: 52px;
+    min-height: 23px;
 }
 
 QAbstractSpinBox:up-button {
     background-color: transparent;
     subcontrol-origin: border;
     subcontrol-position: center right;
-    left: -6px;
+    left: -2px;
 }
 
 QAbstractSpinBox:down-button {
     background-color: transparent;
     subcontrol-origin: border;
     subcontrol-position: center left;
-    right: -6px;
+    right: -2px;
 }
 
 QAbstractSpinBox::up-arrow,
@@ -1277,34 +1284,17 @@ QPushButton#RendererStatusBarButton:!checked {
 }
 
 QPushButton#buttonRefreshDevices {
-    min-width: 24px;
-    min-height: 24px;
-    max-width: 24px;
-    max-height: 24px;
+    min-width: 23px;
+    min-height: 23px;
+    max-width: 23px;
+    max-height: 23px;
     padding: 0px 0px;
 }
 
 QSpinBox#spinboxLStickRange,
-QSpinBox#spinboxRStickRange {
-    padding: 4px 0px 5px 0px;
-    min-width: 63px;
-}
-
+QSpinBox#spinboxRStickRange,
 QSpinBox#vibrationSpin {
-    padding: 4px 0px 5px 0px;
-    min-width: 63px;
-}
-
-QSpinBox#spinboxLStickRange:up-button,
-QSpinBox#spinboxRStickRange:up-button,
-QSpinBox#vibrationSpin:up-button {
-    left: -2px;
-}
-
-QSpinBox#spinboxLStickRange:down-button,
-QSpinBox#spinboxRStickRange:down-button,
-QSpinBox#vibrationSpin:down-button {
-    right: -1px;
+    min-width: 68px;
 }
 
 QGroupBox#motionGroup::indicator,
@@ -1340,16 +1330,7 @@ QWidget#middleControllerApplet {
 
 QWidget#topPerGameInput QComboBox,
 QWidget#middleControllerApplet QComboBox {
-    width: 119px;
-}
-
-QRadioButton#radioDocked {
-    margin-left: -3px;
-}
-
-
-QRadioButton#radioUndocked {
-    margin-right: 5px;
+    width: 120px;
 }
 
 QWidget#connectedControllers {
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
index c6318ba4e..ad032a966 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -172,8 +172,8 @@ QCheckBox {
   color: #F0F0F0;
   spacing: 4px;
   outline: none;
-  padding-top: 4px;
-  padding-bottom: 4px;
+  padding-top: 2px;
+  padding-bottom: 2px;
 }
 
 QCheckBox:focus {
@@ -239,7 +239,7 @@ QGroupBox {
   border: 1px solid #32414B;
   border-radius: 4px;
   margin-top: 12px;
-  padding: 4px;
+  padding: 2px;
 }
 
 QGroupBox::title {
@@ -247,7 +247,7 @@ QGroupBox::title {
   subcontrol-position: top left;
   padding-left: 3px;
   padding-right: 5px;
-  padding-top: 4px;
+  padding-top: 2px;
 }
 
 QGroupBox::indicator {
@@ -298,6 +298,11 @@ QRadioButton {
   outline: none;
 }
 
+QGroupBox QRadioButton {
+  padding-left: 0px;
+  padding-right: 7px;
+}
+
 QRadioButton:focus {
   border: none;
 }
@@ -321,7 +326,6 @@ QRadioButton QWidget {
 QRadioButton::indicator {
   border: none;
   outline: none;
-  margin-left: 4px;
   height: 16px;
   width: 16px;
 }
@@ -785,14 +789,8 @@ QAbstractSpinBox {
   background-color: #19232D;
   border: 1px solid #32414B;
   color: #F0F0F0;
-  /* This fixes 103, 111 */
-  padding-top: 2px;
-  /* This fixes 103, 111 */
-  padding-bottom: 2px;
-  padding-left: 4px;
-  padding-right: 4px;
   border-radius: 4px;
-  /* min-width: 5px; removed to fix 109 */
+  min-height: 19px;
 }
 
 QAbstractSpinBox:up-button {
@@ -997,10 +995,11 @@ QPushButton {
   border: 1px solid #32414B;
   color: #F0F0F0;
   border-radius: 4px;
-  padding: 3px;
+  padding: 3px 0px 3px 0px;
   outline: none;
   /* Issue #194 - Special case of QPushButton inside dialogs, for better UI */
   min-width: 80px;
+  min-height: 13px;
 }
 
 QPushButton:disabled {
@@ -1008,14 +1007,14 @@ QPushButton:disabled {
   border: 1px solid #32414B;
   color: #787878;
   border-radius: 4px;
-  padding: 3px;
+  padding: 3px 0px 3px 0px;
 }
 
 QPushButton:checked {
   background-color: #32414B;
   border: 1px solid #32414B;
   border-radius: 4px;
-  padding: 3px;
+  padding: 3px 0px 3px 0px;
   outline: none;
 }
 
@@ -1024,7 +1023,7 @@ QPushButton:checked:disabled {
   border: 1px solid #32414B;
   color: #787878;
   border-radius: 4px;
-  padding: 3px;
+  padding: 3px 0px 3px 0px;
   outline: none;
 }
 
@@ -1197,15 +1196,9 @@ QComboBox {
   border: 1px solid #32414B;
   border-radius: 4px;
   selection-background-color: #1464A0;
-  padding-left: 4px;
-  padding-right: 36px;
-  /* 4 + 16*2 See scrollbar size */
-  /* Fixes #103, #111 */
-  min-height: 1.5em;
-  /* padding-top: 2px;     removed to fix #132 */
-  /* padding-bottom: 2px;  removed to fix #132 */
-  /* min-width: 75px;      removed to fix #109 */
-  /* Needed to remove indicator - fix #132 */
+  padding: 0px 4px 0px 4px;
+  min-width: 60px;
+  min-height: 19px;
 }
 
 QComboBox QAbstractItemView {
@@ -2198,16 +2191,17 @@ QPushButton#RendererStatusBarButton:!checked {
 }
 
 QPushButton#buttonRefreshDevices {
-  min-width: 20px;
-  min-height: 20px;
-  max-width: 20px;
-  max-height: 20px;
+  min-width: 19px;
+  min-height: 19px;
+  max-width: 19px;
+  max-height: 19px;
   padding: 0px 0px;
 }
 
 QSpinBox#spinboxLStickRange,
-QSpinBox#spinboxRStickRange {
-  min-width: 38px;
+QSpinBox#spinboxRStickRange,
+QSpinBox#vibrationSpin {
+  min-width: 68px;
 }
 
 QGroupBox#motionGroup::indicator,
@@ -2260,26 +2254,7 @@ QWidget#middleControllerApplet {
 
 QWidget#topPerGameInput QComboBox,
 QWidget#middleControllerApplet QComboBox {
-  padding-right: 2px;
-  width: 127px;
-}
-
-QGroupBox#handheldGroup {
-  padding-left: 0px;
-}
-
-QRadioButton#radioDocked {
-  margin-left: -1px;
-  padding-left: 0px;
-}
-
-QRadioButton#radioDocked::indicator {
-  margin-left: 0px;
-}
-
-
-QRadioButton#radioUndocked {
-  margin-right: 2px;
+  width: 120px;
 }
 
 QWidget#connectedControllers {
@@ -2352,7 +2327,7 @@ QCheckBox#checkboxPlayer5Connected,
 QCheckBox#checkboxPlayer6Connected,
 QCheckBox#checkboxPlayer7Connected,
 QCheckBox#checkboxPlayer8Connected {
-    spacing: 0px;
+  spacing: 0px;
 }
 
 QWidget#connectedControllers QLabel {
@@ -2427,7 +2402,7 @@ QCheckBox#checkboxPlayer7Connected::indicator,
 QCheckBox#checkboxPlayer8Connected::indicator {
   width: 14px;
   height: 14px;
-  margin-left: 2px;
+  margin-left: 0px;
 }
 
 QWidget#Player1LEDs QCheckBox::indicator:checked,
diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui
index f122ba39d..1b320630c 100644
--- a/src/yuzu/aboutdialog.ui
+++ b/src/yuzu/aboutdialog.ui
@@ -160,32 +160,12 @@ p, li { white-space: pre-wrap; }
    <signal>accepted()</signal>
    <receiver>AboutDialog</receiver>
    <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
   </connection>
   <connection>
    <sender>buttonBox</sender>
    <signal>rejected()</signal>
    <receiver>AboutDialog</receiver>
    <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
   </connection>
  </connections>
 </ui>
diff --git a/src/yuzu/applets/controller.ui b/src/yuzu/applets/controller.ui
index c4108a979..2ab69a2d3 100644
--- a/src/yuzu/applets/controller.ui
+++ b/src/yuzu/applets/controller.ui
@@ -1217,9 +1217,6 @@
               </item>
               <item>
                <widget class="QComboBox" name="comboPlayer3Emulated">
-                <property name="editable">
-                 <bool>false</bool>
-                </property>
                 <item>
                  <property name="text">
                   <string>Pro Controller</string>
@@ -2279,7 +2276,7 @@
              <number>6</number>
             </property>
             <property name="leftMargin">
-             <number>6</number>
+             <number>8</number>
             </property>
             <property name="topMargin">
              <number>6</number>
@@ -2335,13 +2332,13 @@
              <widget class="QSpinBox" name="vibrationSpin">
               <property name="minimumSize">
                <size>
-                <width>65</width>
-                <height>0</height>
+                <width>68</width>
+                <height>21</height>
                </size>
               </property>
               <property name="maximumSize">
                <size>
-                <width>65</width>
+                <width>68</width>
                 <height>16777215</height>
                </size>
               </property>
@@ -2387,18 +2384,18 @@
              <widget class="QPushButton" name="motionButton">
               <property name="minimumSize">
                <size>
-                <width>57</width>
+                <width>68</width>
                 <height>0</height>
                </size>
               </property>
               <property name="maximumSize">
                <size>
-                <width>55</width>
+                <width>68</width>
                 <height>16777215</height>
                </size>
               </property>
               <property name="styleSheet">
-               <string notr="true">min-width: 55px;</string>
+               <string notr="true">min-width: 68px;</string>
               </property>
               <property name="text">
                <string>Configure</string>
@@ -2430,12 +2427,12 @@
              <widget class="QPushButton" name="inputConfigButton">
               <property name="maximumSize">
                <size>
-                <width>65</width>
+                <width>68</width>
                 <height>16777215</height>
                </size>
               </property>
               <property name="styleSheet">
-               <string notr="true">min-width: 55px;</string>
+               <string notr="true">min-width: 68px;</string>
               </property>
               <property name="text">
                <string>Open</string>
@@ -2657,16 +2654,6 @@
    <signal>accepted()</signal>
    <receiver>QtControllerSelectorDialog</receiver>
    <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>20</x>
-     <y>20</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>20</x>
-     <y>20</y>
-    </hint>
-   </hints>
   </connection>
  </connections>
 </ui>
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index fcf42cdcb..f92c3aff3 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -275,32 +275,12 @@
    <signal>accepted()</signal>
    <receiver>ConfigureDialog</receiver>
    <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>220</x>
-     <y>380</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>220</x>
-     <y>200</y>
-    </hint>
-   </hints>
   </connection>
   <connection>
    <sender>buttonBox</sender>
    <signal>rejected()</signal>
    <receiver>ConfigureDialog</receiver>
    <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>220</x>
-     <y>380</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>220</x>
-     <y>200</y>
-    </hint>
-   </hints>
   </connection>
  </connections>
 </ui>
diff --git a/src/yuzu/configuration/configure_debug_controller.ui b/src/yuzu/configuration/configure_debug_controller.ui
index a95ed50ff..7b7e6582c 100644
--- a/src/yuzu/configuration/configure_debug_controller.ui
+++ b/src/yuzu/configuration/configure_debug_controller.ui
@@ -66,32 +66,12 @@
    <signal>accepted()</signal>
    <receiver>ConfigureDebugController</receiver>
    <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>140</x>
-     <y>318</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>140</x>
-     <y>169</y>
-    </hint>
-   </hints>
   </connection>
   <connection>
    <sender>buttonBox</sender>
    <signal>rejected()</signal>
    <receiver>ConfigureDebugController</receiver>
    <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>140</x>
-     <y>318</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>140</x>
-     <y>169</y>
-    </hint>
-   </hints>
   </connection>
  </connections>
 </ui>
diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index 136955224..b74481bda 100644
--- a/src/yuzu/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
@@ -142,7 +142,7 @@
           <number>6</number>
          </property>
          <property name="leftMargin">
-          <number>3</number>
+          <number>8</number>
          </property>
          <property name="topMargin">
           <number>6</number>
@@ -198,13 +198,13 @@
           <widget class="QSpinBox" name="vibrationSpin">
            <property name="minimumSize">
             <size>
-             <width>65</width>
+             <width>68</width>
              <height>21</height>
             </size>
            </property>
            <property name="maximumSize">
             <size>
-             <width>65</width>
+             <width>68</width>
              <height>16777215</height>
             </size>
            </property>
@@ -250,18 +250,18 @@
           <widget class="QPushButton" name="motionButton">
            <property name="minimumSize">
             <size>
-             <width>57</width>
+             <width>68</width>
              <height>0</height>
             </size>
            </property>
            <property name="maximumSize">
             <size>
-             <width>55</width>
+             <width>68</width>
              <height>16777215</height>
             </size>
            </property>
            <property name="styleSheet">
-            <string notr="true">min-width: 55px;</string>
+            <string notr="true">min-width: 68px;</string>
            </property>
            <property name="text">
             <string>Configure</string>
@@ -468,13 +468,13 @@
         </property>
         <property name="minimumSize">
          <size>
-          <width>57</width>
+          <width>68</width>
           <height>0</height>
          </size>
         </property>
         <property name="maximumSize">
          <size>
-          <width>55</width>
+          <width>68</width>
           <height>16777215</height>
          </size>
         </property>
@@ -494,7 +494,7 @@
          <enum>Qt::LeftToRight</enum>
         </property>
         <property name="styleSheet">
-         <string notr="true">min-width: 55px;</string>
+         <string notr="true">min-width: 68px;</string>
         </property>
         <property name="text">
          <string>Defaults</string>
@@ -511,13 +511,13 @@
         </property>
         <property name="minimumSize">
          <size>
-          <width>57</width>
+          <width>68</width>
           <height>0</height>
          </size>
         </property>
         <property name="maximumSize">
          <size>
-          <width>55</width>
+          <width>68</width>
           <height>16777215</height>
          </size>
         </property>
@@ -537,7 +537,7 @@
          <enum>Qt::LeftToRight</enum>
         </property>
         <property name="styleSheet">
-         <string notr="true">min-width: 55px;</string>
+         <string notr="true">min-width: 68px;</string>
         </property>
         <property name="text">
          <string>Clear</string>
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index 81f9dc16c..3715db0ab 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -101,7 +101,7 @@ void ConfigureInputAdvanced::OnControllerButtonClick(int player_idx, int button_
     }
     controllers_colors[player_idx][button_idx] = new_bg_color;
     controllers_color_buttons[player_idx][button_idx]->setStyleSheet(
-        QStringLiteral("background-color: %1; min-width: 55px;")
+        QStringLiteral("background-color: %1; min-width: 60px;")
             .arg(controllers_colors[player_idx][button_idx].name()));
 }
 
@@ -139,7 +139,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {
 
         for (std::size_t button_idx = 0; button_idx < colors.size(); ++button_idx) {
             controllers_color_buttons[player_idx][button_idx]->setStyleSheet(
-                QStringLiteral("background-color: %1; min-width: 55px;")
+                QStringLiteral("background-color: %1; min-width: 60px;")
                     .arg(controllers_colors[player_idx][button_idx].name()));
         }
     }
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui
index 5958435fc..a880a7c68 100644
--- a/src/yuzu/configuration/configure_input_advanced.ui
+++ b/src/yuzu/configuration/configure_input_advanced.ui
@@ -192,18 +192,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -247,18 +247,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -323,18 +323,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -378,18 +378,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -478,18 +478,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -533,18 +533,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -609,18 +609,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -664,18 +664,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -782,18 +782,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -837,18 +837,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -913,18 +913,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -968,18 +968,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1068,18 +1068,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1123,18 +1123,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1199,18 +1199,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1254,18 +1254,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1393,18 +1393,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1448,18 +1448,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1524,18 +1524,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1579,18 +1579,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1679,18 +1679,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1734,18 +1734,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1810,18 +1810,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1865,18 +1865,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -1983,18 +1983,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -2038,18 +2038,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -2114,18 +2114,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -2169,18 +2169,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -2269,18 +2269,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -2324,18 +2324,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -2400,18 +2400,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
@@ -2455,18 +2455,18 @@
                              </property>
                              <property name="minimumSize">
                               <size>
-                               <width>57</width>
+                               <width>68</width>
                                <height>0</height>
                               </size>
                              </property>
                              <property name="maximumSize">
                               <size>
-                               <width>55</width>
+                               <width>68</width>
                                <height>16777215</height>
                               </size>
                              </property>
                              <property name="styleSheet">
-                              <string notr="true">min-width: 55px;</string>
+                              <string notr="true">min-width: 68px;</string>
                              </property>
                              <property name="text">
                               <string/>
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
index e03461d9d..1e78b4c10 100644
--- a/src/yuzu/configuration/configure_input_player.ui
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -83,6 +83,12 @@
           </property>
           <item>
            <widget class="QComboBox" name="comboControllerType">
+            <property name="minimumSize">
+             <size>
+              <width>0</width>
+              <height>21</height>
+             </size>
+            </property>
             <item>
              <property name="text">
               <string>Pro Controller</string>
@@ -136,6 +142,12 @@
           </property>
           <item>
            <widget class="QComboBox" name="comboDevices">
+            <property name="minimumSize">
+             <size>
+              <width>0</width>
+              <height>21</height>
+             </size>
+            </property>
             <item>
              <property name="text">
               <string>Any</string>
@@ -152,14 +164,14 @@
            <widget class="QPushButton" name="buttonRefreshDevices">
             <property name="minimumSize">
              <size>
-              <width>24</width>
-              <height>22</height>
+              <width>21</width>
+              <height>21</height>
              </size>
             </property>
             <property name="maximumSize">
              <size>
-              <width>24</width>
-              <height>22</height>
+              <width>21</width>
+              <height>21</height>
              </size>
             </property>
             <property name="styleSheet">
@@ -198,18 +210,25 @@
            <number>5</number>
           </property>
           <item>
-           <widget class="QComboBox" name="comboProfiles"/>
+           <widget class="QComboBox" name="comboProfiles">
+            <property name="minimumSize">
+             <size>
+              <width>0</width>
+              <height>21</height>
+             </size>
+            </property>
+           </widget>
           </item>
           <item>
            <widget class="QPushButton" name="buttonProfilesSave">
             <property name="maximumSize">
              <size>
-              <width>55</width>
+              <width>68</width>
               <height>16777215</height>
              </size>
             </property>
             <property name="styleSheet">
-             <string notr="true">min-width: 55px;</string>
+             <string notr="true">min-width: 68px;</string>
             </property>
             <property name="text">
              <string>Save</string>
@@ -220,12 +239,12 @@
            <widget class="QPushButton" name="buttonProfilesNew">
             <property name="maximumSize">
              <size>
-              <width>55</width>
+              <width>68</width>
               <height>16777215</height>
              </size>
             </property>
             <property name="styleSheet">
-             <string notr="true">min-width: 55px;</string>
+             <string notr="true">min-width: 68px;</string>
             </property>
             <property name="text">
              <string>New</string>
@@ -236,12 +255,12 @@
            <widget class="QPushButton" name="buttonProfilesDelete">
             <property name="maximumSize">
              <size>
-              <width>55</width>
+              <width>68</width>
               <height>16777215</height>
              </size>
             </property>
             <property name="styleSheet">
-             <string notr="true">min-width: 55px;</string>
+             <string notr="true">min-width: 68px;</string>
             </property>
             <property name="text">
              <string>Delete</string>
@@ -393,18 +412,18 @@
                      <widget class="QPushButton" name="buttonLStickUp">
                       <property name="minimumSize">
                        <size>
-                        <width>57</width>
+                        <width>68</width>
                         <height>0</height>
                        </size>
                       </property>
                       <property name="maximumSize">
                        <size>
-                        <width>55</width>
+                        <width>68</width>
                         <height>16777215</height>
                        </size>
                       </property>
                       <property name="styleSheet">
-                       <string notr="true">min-width: 55px;</string>
+                       <string notr="true">min-width: 68px;</string>
                       </property>
                       <property name="text">
                        <string>Up</string>
@@ -463,18 +482,18 @@
                     <widget class="QPushButton" name="buttonLStickLeft">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Left</string>
@@ -512,18 +531,18 @@
                     <widget class="QPushButton" name="buttonLStickRight">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Right</string>
@@ -594,18 +613,18 @@
                      <widget class="QPushButton" name="buttonLStickDown">
                       <property name="minimumSize">
                        <size>
-                        <width>57</width>
+                        <width>68</width>
                         <height>0</height>
                        </size>
                       </property>
                       <property name="maximumSize">
                        <size>
-                        <width>55</width>
+                        <width>68</width>
                         <height>16777215</height>
                        </size>
                       </property>
                       <property name="styleSheet">
-                       <string notr="true">min-width: 55px;</string>
+                       <string notr="true">min-width: 68px;</string>
                       </property>
                       <property name="text">
                        <string>Down</string>
@@ -664,18 +683,18 @@
                     <widget class="QPushButton" name="buttonLStick">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Pressed</string>
@@ -713,18 +732,18 @@
                     <widget class="QPushButton" name="buttonLStickMod">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Modifier</string>
@@ -759,13 +778,13 @@
                     <widget class="QSpinBox" name="spinboxLStickRange">
                      <property name="minimumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>21</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
@@ -966,18 +985,18 @@
                      <widget class="QPushButton" name="buttonDpadUp">
                       <property name="minimumSize">
                        <size>
-                        <width>57</width>
+                        <width>68</width>
                         <height>0</height>
                        </size>
                       </property>
                       <property name="maximumSize">
                        <size>
-                        <width>55</width>
+                        <width>68</width>
                         <height>16777215</height>
                        </size>
                       </property>
                       <property name="styleSheet">
-                       <string notr="true">min-width: 55px;</string>
+                       <string notr="true">min-width: 68px;</string>
                       </property>
                       <property name="text">
                        <string>Up</string>
@@ -1036,18 +1055,18 @@
                     <widget class="QPushButton" name="buttonDpadLeft">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Left</string>
@@ -1085,18 +1104,18 @@
                     <widget class="QPushButton" name="buttonDpadRight">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Right</string>
@@ -1167,18 +1186,18 @@
                      <widget class="QPushButton" name="buttonDpadDown">
                       <property name="minimumSize">
                        <size>
-                        <width>57</width>
+                        <width>68</width>
                         <height>0</height>
                        </size>
                       </property>
                       <property name="maximumSize">
                        <size>
-                        <width>55</width>
+                        <width>68</width>
                         <height>16777215</height>
                        </size>
                       </property>
                       <property name="styleSheet">
-                       <string notr="true">min-width: 55px;</string>
+                       <string notr="true">min-width: 68px;</string>
                       </property>
                       <property name="text">
                        <string>Down</string>
@@ -1292,18 +1311,18 @@
                     <widget class="QPushButton" name="buttonL">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>L</string>
@@ -1341,18 +1360,18 @@
                     <widget class="QPushButton" name="buttonZL">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>ZL</string>
@@ -1445,18 +1464,18 @@
                     <widget class="QPushButton" name="buttonMinus">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Minus</string>
@@ -1494,18 +1513,18 @@
                     <widget class="QPushButton" name="buttonScreenshot">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Capture</string>
@@ -1564,18 +1583,18 @@
                     <widget class="QPushButton" name="buttonPlus">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Plus</string>
@@ -1613,18 +1632,18 @@
                     <widget class="QPushButton" name="buttonHome">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Home</string>
@@ -1717,18 +1736,18 @@
                     <widget class="QPushButton" name="buttonR">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>R</string>
@@ -1766,18 +1785,18 @@
                     <widget class="QPushButton" name="buttonZR">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>ZR</string>
@@ -1870,18 +1889,18 @@
                     <widget class="QPushButton" name="buttonSL">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>SL</string>
@@ -1919,18 +1938,18 @@
                     <widget class="QPushButton" name="buttonSR">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>SR</string>
@@ -2027,18 +2046,18 @@
                  <widget class="QPushButton" name="buttonMotionLeft">
                   <property name="minimumSize">
                    <size>
-                    <width>57</width>
+                    <width>68</width>
                     <height>0</height>
                    </size>
                   </property>
                   <property name="maximumSize">
                    <size>
-                    <width>55</width>
+                    <width>68</width>
                     <height>16777215</height>
                    </size>
                   </property>
                   <property name="styleSheet">
-                   <string notr="true">min-width: 55px;</string>
+                   <string notr="true">min-width: 68px;</string>
                   </property>
                   <property name="text">
                    <string>Left</string>
@@ -2076,18 +2095,18 @@
                  <widget class="QPushButton" name="buttonMotionRight">
                   <property name="minimumSize">
                    <size>
-                    <width>57</width>
+                    <width>68</width>
                     <height>0</height>
                    </size>
                   </property>
                   <property name="maximumSize">
                    <size>
-                    <width>55</width>
+                    <width>68</width>
                     <height>16777215</height>
                    </size>
                   </property>
                   <property name="styleSheet">
-                   <string notr="true">min-width: 55px;</string>
+                   <string notr="true">min-width: 68px;</string>
                   </property>
                   <property name="text">
                    <string>Right</string>
@@ -2225,18 +2244,18 @@
                      <widget class="QPushButton" name="buttonX">
                       <property name="minimumSize">
                        <size>
-                        <width>57</width>
+                        <width>68</width>
                         <height>0</height>
                        </size>
                       </property>
                       <property name="maximumSize">
                        <size>
-                        <width>55</width>
+                        <width>68</width>
                         <height>16777215</height>
                        </size>
                       </property>
                       <property name="styleSheet">
-                       <string notr="true">min-width: 55px;</string>
+                       <string notr="true">min-width: 68px;</string>
                       </property>
                       <property name="text">
                        <string>X</string>
@@ -2295,18 +2314,18 @@
                     <widget class="QPushButton" name="buttonY">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Y</string>
@@ -2344,18 +2363,18 @@
                     <widget class="QPushButton" name="buttonA">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>A</string>
@@ -2426,18 +2445,18 @@
                      <widget class="QPushButton" name="buttonB">
                       <property name="minimumSize">
                        <size>
-                        <width>57</width>
+                        <width>68</width>
                         <height>0</height>
                        </size>
                       </property>
                       <property name="maximumSize">
                        <size>
-                        <width>55</width>
+                        <width>68</width>
                         <height>16777215</height>
                        </size>
                       </property>
                       <property name="styleSheet">
-                       <string notr="true">min-width: 55px;</string>
+                       <string notr="true">min-width: 68px;</string>
                       </property>
                       <property name="text">
                        <string>B</string>
@@ -2580,18 +2599,18 @@
                      <widget class="QPushButton" name="buttonRStickUp">
                       <property name="minimumSize">
                        <size>
-                        <width>57</width>
+                        <width>68</width>
                         <height>0</height>
                        </size>
                       </property>
                       <property name="maximumSize">
                        <size>
-                        <width>55</width>
+                        <width>68</width>
                         <height>16777215</height>
                        </size>
                       </property>
                       <property name="styleSheet">
-                       <string notr="true">min-width: 55px;</string>
+                       <string notr="true">min-width: 68px;</string>
                       </property>
                       <property name="text">
                        <string>Up</string>
@@ -2650,18 +2669,18 @@
                     <widget class="QPushButton" name="buttonRStickLeft">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Left</string>
@@ -2699,18 +2718,18 @@
                     <widget class="QPushButton" name="buttonRStickRight">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Right</string>
@@ -2781,18 +2800,18 @@
                      <widget class="QPushButton" name="buttonRStickDown">
                       <property name="minimumSize">
                        <size>
-                        <width>57</width>
+                        <width>68</width>
                         <height>0</height>
                        </size>
                       </property>
                       <property name="maximumSize">
                        <size>
-                        <width>55</width>
+                        <width>68</width>
                         <height>16777215</height>
                        </size>
                       </property>
                       <property name="styleSheet">
-                       <string notr="true">min-width: 55px;</string>
+                       <string notr="true">min-width: 68px;</string>
                       </property>
                       <property name="text">
                        <string>Down</string>
@@ -2851,18 +2870,18 @@
                     <widget class="QPushButton" name="buttonRStick">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Pressed</string>
@@ -2900,18 +2919,18 @@
                     <widget class="QPushButton" name="buttonRStickMod">
                      <property name="minimumSize">
                       <size>
-                       <width>57</width>
+                       <width>68</width>
                        <height>0</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
                      <property name="styleSheet">
-                      <string notr="true">min-width: 55px;</string>
+                      <string notr="true">min-width: 68px;</string>
                      </property>
                      <property name="text">
                       <string>Modifier</string>
@@ -2946,13 +2965,13 @@
                     <widget class="QSpinBox" name="spinboxRStickRange">
                      <property name="minimumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>21</height>
                       </size>
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>55</width>
+                       <width>68</width>
                        <height>16777215</height>
                       </size>
                      </property>
diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui
index 602cf8cd8..5b78c5a4b 100644
--- a/src/yuzu/configuration/configure_motion_touch.ui
+++ b/src/yuzu/configuration/configure_motion_touch.ui
@@ -312,16 +312,6 @@
    <signal>accepted()</signal>
    <receiver>ConfigureMotionTouch</receiver>
    <slot>ApplyConfiguration()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>220</x>
-     <y>380</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>220</x>
-     <y>200</y>
-    </hint>
-   </hints>
   </connection>
  </connections>
 </ui>
diff --git a/src/yuzu/configuration/configure_mouse_advanced.ui b/src/yuzu/configuration/configure_mouse_advanced.ui
index 74552fdbd..5b99e1c37 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.ui
+++ b/src/yuzu/configuration/configure_mouse_advanced.ui
@@ -15,7 +15,7 @@
   </property>
   <property name="styleSheet">
    <string notr="true">QPushButton {
-  min-width: 55px;
+  min-width: 60px;
 }</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
@@ -42,13 +42,13 @@
          <widget class="QPushButton" name="forward_button">
           <property name="minimumSize">
            <size>
-            <width>57</width>
+            <width>68</width>
             <height>0</height>
            </size>
           </property>
           <property name="maximumSize">
            <size>
-            <width>16777215</width>
+            <width>68</width>
             <height>16777215</height>
            </size>
           </property>
@@ -82,7 +82,7 @@
          <widget class="QPushButton" name="back_button">
           <property name="minimumSize">
            <size>
-            <width>57</width>
+            <width>68</width>
             <height>0</height>
            </size>
           </property>
@@ -110,7 +110,7 @@
          <widget class="QPushButton" name="left_button">
           <property name="minimumSize">
            <size>
-            <width>57</width>
+            <width>68</width>
             <height>0</height>
            </size>
           </property>
@@ -138,13 +138,13 @@
          <widget class="QPushButton" name="middle_button">
           <property name="minimumSize">
            <size>
-            <width>57</width>
+            <width>68</width>
             <height>0</height>
            </size>
           </property>
           <property name="maximumSize">
            <size>
-            <width>16777215</width>
+            <width>68</width>
             <height>16777215</height>
            </size>
           </property>
@@ -204,13 +204,13 @@
          <widget class="QPushButton" name="right_button">
           <property name="minimumSize">
            <size>
-            <width>57</width>
+            <width>68</width>
             <height>0</height>
            </size>
           </property>
           <property name="maximumSize">
            <size>
-            <width>16777215</width>
+            <width>68</width>
             <height>16777215</height>
            </size>
           </property>
@@ -256,13 +256,13 @@
       <widget class="QPushButton" name="buttonClearAll">
        <property name="minimumSize">
         <size>
-         <width>57</width>
+         <width>68</width>
          <height>0</height>
         </size>
        </property>
        <property name="maximumSize">
         <size>
-         <width>16777215</width>
+         <width>68</width>
          <height>16777215</height>
         </size>
        </property>
@@ -275,13 +275,13 @@
       <widget class="QPushButton" name="buttonRestoreDefaults">
        <property name="minimumSize">
         <size>
-         <width>57</width>
+         <width>68</width>
          <height>0</height>
         </size>
        </property>
        <property name="maximumSize">
         <size>
-         <width>16777215</width>
+         <width>68</width>
          <height>16777215</height>
         </size>
        </property>
@@ -324,32 +324,12 @@
    <signal>accepted()</signal>
    <receiver>ConfigureMouseAdvanced</receiver>
    <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>124</x>
-     <y>266</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>124</x>
-     <y>143</y>
-    </hint>
-   </hints>
   </connection>
   <connection>
    <sender>buttonBox</sender>
    <signal>rejected()</signal>
    <receiver>ConfigureMouseAdvanced</receiver>
    <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>124</x>
-     <y>266</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>124</x>
-     <y>143</y>
-    </hint>
-   </hints>
   </connection>
  </connections>
 </ui>
diff --git a/src/yuzu/configuration/configure_per_game.ui b/src/yuzu/configuration/configure_per_game.ui
index d2057c4ab..25975b3b9 100644
--- a/src/yuzu/configuration/configure_per_game.ui
+++ b/src/yuzu/configuration/configure_per_game.ui
@@ -319,32 +319,12 @@
    <signal>accepted()</signal>
    <receiver>ConfigurePerGame</receiver>
    <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
   </connection>
   <connection>
    <sender>buttonBox</sender>
    <signal>rejected()</signal>
    <receiver>ConfigurePerGame</receiver>
    <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
   </connection>
  </connections>
 </ui>
diff --git a/src/yuzu/configuration/configure_touch_from_button.ui b/src/yuzu/configuration/configure_touch_from_button.ui
index f581e27e0..757219d54 100644
--- a/src/yuzu/configuration/configure_touch_from_button.ui
+++ b/src/yuzu/configuration/configure_touch_from_button.ui
@@ -216,16 +216,6 @@ Drag points to change position, or double-click table cells to edit values.</str
    <signal>rejected()</signal>
    <receiver>ConfigureTouchFromButton</receiver>
    <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>428</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>249</x>
-     <y>224</y>
-    </hint>
-   </hints>
   </connection>
  </connections>
 </ui>
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.ui b/src/yuzu/configuration/configure_touchscreen_advanced.ui
index 1171c2dd1..30ceccddb 100644
--- a/src/yuzu/configuration/configure_touchscreen_advanced.ui
+++ b/src/yuzu/configuration/configure_touchscreen_advanced.ui
@@ -168,32 +168,12 @@
    <signal>accepted()</signal>
    <receiver>ConfigureTouchscreenAdvanced</receiver>
    <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>140</x>
-     <y>318</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>140</x>
-     <y>169</y>
-    </hint>
-   </hints>
   </connection>
   <connection>
    <sender>buttonBox</sender>
    <signal>rejected()</signal>
    <receiver>ConfigureTouchscreenAdvanced</receiver>
    <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>140</x>
-     <y>318</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>140</x>
-     <y>169</y>
-    </hint>
-   </hints>
-  </connection>
+   </connection>
  </connections>
 </ui>

From 75eaab2e0f48eb588c1bfb85f96630e199fbc1da Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Thu, 17 Sep 2020 12:00:29 -0400
Subject: [PATCH 02/37] configure_input_player: Implement input exclusivity and
 persistence

With this, the "Input Devices" combobox should accurately reflect the input device being used and disallows inputs from other input devices unless the input device is set to "Any".
---
 src/input_common/main.cpp                     |   6 +-
 src/yuzu/configuration/configure_input.cpp    |   2 +-
 .../configuration/configure_input_player.cpp  | 318 +++++++++++-------
 .../configuration/configure_input_player.h    |  17 +-
 4 files changed, 205 insertions(+), 138 deletions(-)

diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index d32fd8b81..354c734fe 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -78,7 +78,7 @@ struct InputSubsystem::Impl {
     [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
         std::vector<Common::ParamPackage> devices = {
             Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
-            Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
+            Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}},
         };
 #ifdef HAVE_SDL2
         auto sdl_devices = sdl->GetInputDevices();
@@ -96,7 +96,7 @@ struct InputSubsystem::Impl {
         if (!params.Has("class") || params.Get("class", "") == "any") {
             return {};
         }
-        if (params.Get("class", "") == "key") {
+        if (params.Get("class", "") == "keyboard") {
             // TODO consider returning the SDL key codes for the default keybindings
             return {};
         }
@@ -116,7 +116,7 @@ struct InputSubsystem::Impl {
         if (!params.Has("class") || params.Get("class", "") == "any") {
             return {};
         }
-        if (params.Get("class", "") == "key") {
+        if (params.Get("class", "") == "keyboard") {
             // TODO consider returning the SDL key codes for the default keybindings
             return {};
         }
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 2725fcb2b..f2932aa0b 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -242,6 +242,6 @@ void ConfigureInput::UpdateDockedState(bool is_handheld) {
 
 void ConfigureInput::UpdateAllInputDevices() {
     for (const auto& player : player_controllers) {
-        player->UpdateInputDevices();
+        player->UpdateInputDeviceCombobox();
     }
 }
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index f58ca29d7..0de0c6999 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -477,11 +477,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
         UpdateMotionButtons();
     });
 
-    connect(ui->comboDevices, qOverload<int>(&QComboBox::currentIndexChanged), this,
+    connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this,
             &ConfigureInputPlayer::UpdateMappingWithDefaults);
 
+    ui->comboDevices->setCurrentIndex(-1);
+
     ui->buttonRefreshDevices->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
-    UpdateInputDevices();
     connect(ui->buttonRefreshDevices, &QPushButton::clicked,
             [this] { emit RefreshInputDevices(); });
 
@@ -492,14 +493,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
         Common::ParamPackage params;
         if (input_subsystem->GetGCButtons()->IsPolling()) {
             params = input_subsystem->GetGCButtons()->GetNextInput();
-            if (params.Has("engine")) {
+            if (params.Has("engine") && IsInputAcceptable(params)) {
                 SetPollingResult(params, false);
                 return;
             }
         }
         if (input_subsystem->GetGCAnalogs()->IsPolling()) {
             params = input_subsystem->GetGCAnalogs()->GetNextInput();
-            if (params.Has("engine")) {
+            if (params.Has("engine") && IsInputAcceptable(params)) {
                 SetPollingResult(params, false);
                 return;
             }
@@ -513,7 +514,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
         }
         for (auto& poller : device_pollers) {
             params = poller->GetNextInput();
-            if (params.Has("engine")) {
+            if (params.Has("engine") && IsInputAcceptable(params)) {
                 SetPollingResult(params, false);
                 return;
             }
@@ -572,6 +573,14 @@ void ConfigureInputPlayer::ApplyConfiguration() {
     UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected);
 }
 
+void ConfigureInputPlayer::showEvent(QShowEvent* event) {
+    if (bottom_row == nullptr) {
+        return;
+    }
+    QWidget::showEvent(event);
+    ui->main->addWidget(bottom_row);
+}
+
 void ConfigureInputPlayer::changeEvent(QEvent* event) {
     if (event->type() == QEvent::LanguageChange) {
         RetranslateUI();
@@ -604,6 +613,7 @@ void ConfigureInputPlayer::LoadConfiguration() {
     }
 
     UpdateUI();
+    UpdateInputDeviceCombobox();
 
     if (debug) {
         return;
@@ -615,11 +625,56 @@ void ConfigureInputPlayer::LoadConfiguration() {
         (player_index == 0 && Settings::values.players[HANDHELD_INDEX].connected));
 }
 
-void ConfigureInputPlayer::UpdateInputDevices() {
-    input_devices = input_subsystem->GetInputDevices();
-    ui->comboDevices->clear();
-    for (auto device : input_devices) {
-        ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {});
+void ConfigureInputPlayer::ConnectPlayer(bool connected) {
+    ui->groupConnectedController->setChecked(connected);
+}
+
+void ConfigureInputPlayer::UpdateInputDeviceCombobox() {
+    // Skip input device persistence if "Input Devices" is set to "Any".
+    if (ui->comboDevices->currentIndex() == 0) {
+        UpdateInputDevices();
+        return;
+    }
+
+    // Find the first button that isn't empty.
+    const auto button_param =
+        std::find_if(buttons_param.begin(), buttons_param.end(),
+                     [](const Common::ParamPackage param) { return param.Has("engine"); });
+    const bool buttons_empty = button_param == buttons_param.end();
+
+    const auto current_engine = button_param->Get("engine", "");
+    const auto current_guid = button_param->Get("guid", "");
+    const auto current_port = button_param->Get("port", "");
+
+    UpdateInputDevices();
+
+    if (buttons_empty) {
+        return;
+    }
+
+    const bool all_one_device =
+        std::all_of(buttons_param.begin(), buttons_param.end(),
+                    [current_engine, current_guid, current_port](const Common::ParamPackage param) {
+                        return !param.Has("engine") || (param.Get("engine", "") == current_engine &&
+                                                        param.Get("guid", "") == current_guid &&
+                                                        param.Get("port", "") == current_port);
+                    });
+
+    if (all_one_device) {
+        const auto devices_it = std::find_if(
+            input_devices.begin(), input_devices.end(),
+            [current_engine, current_guid, current_port](const Common::ParamPackage param) {
+                return param.Get("class", "") == current_engine &&
+                       param.Get("guid", "") == current_guid &&
+                       param.Get("port", "") == current_port;
+            });
+        const int device_index =
+            devices_it != input_devices.end()
+                ? static_cast<int>(std::distance(input_devices.begin(), devices_it))
+                : 0;
+        ui->comboDevices->setCurrentIndex(device_index);
+    } else {
+        ui->comboDevices->setCurrentIndex(0);
     }
 }
 
@@ -648,7 +703,7 @@ void ConfigureInputPlayer::RestoreDefaults() {
     }
 
     UpdateUI();
-    UpdateInputDevices();
+    UpdateInputDeviceCombobox();
     ui->comboControllerType->setCurrentIndex(0);
 }
 
@@ -752,117 +807,12 @@ void ConfigureInputPlayer::UpdateUI() {
     }
 }
 
-void ConfigureInputPlayer::UpdateMappingWithDefaults() {
-    if (ui->comboDevices->currentIndex() < 2) {
-        return;
+void ConfigureInputPlayer::UpdateInputDevices() {
+    input_devices = input_subsystem->GetInputDevices();
+    ui->comboDevices->clear();
+    for (auto device : input_devices) {
+        ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {});
     }
-    const auto& device = input_devices[ui->comboDevices->currentIndex()];
-    auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
-    auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
-    for (std::size_t i = 0; i < buttons_param.size(); ++i) {
-        buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
-    }
-    for (std::size_t i = 0; i < analogs_param.size(); ++i) {
-        analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)];
-    }
-
-    UpdateUI();
-}
-
-void ConfigureInputPlayer::HandleClick(
-    QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
-    InputCommon::Polling::DeviceType type) {
-    if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) {
-        button->setText(tr("Shake!"));
-    } else {
-        button->setText(tr("[waiting]"));
-    }
-    button->setFocus();
-
-    // The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a
-    // controller, then they don't want keyboard/mouse input
-    want_keyboard_mouse = ui->comboDevices->currentIndex() < 2;
-
-    input_setter = new_input_setter;
-
-    device_pollers = input_subsystem->GetPollers(type);
-
-    for (auto& poller : device_pollers) {
-        poller->Start();
-    }
-
-    QWidget::grabMouse();
-    QWidget::grabKeyboard();
-
-    if (type == InputCommon::Polling::DeviceType::Button) {
-        input_subsystem->GetGCButtons()->BeginConfiguration();
-    } else {
-        input_subsystem->GetGCAnalogs()->BeginConfiguration();
-    }
-
-    if (type == InputCommon::Polling::DeviceType::Motion) {
-        input_subsystem->GetUDPMotions()->BeginConfiguration();
-    }
-
-    timeout_timer->start(2500); // Cancel after 2.5 seconds
-    poll_timer->start(50);      // Check for new inputs every 50ms
-}
-
-void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) {
-    timeout_timer->stop();
-    poll_timer->stop();
-    for (auto& poller : device_pollers) {
-        poller->Stop();
-    }
-
-    QWidget::releaseMouse();
-    QWidget::releaseKeyboard();
-
-    input_subsystem->GetGCButtons()->EndConfiguration();
-    input_subsystem->GetGCAnalogs()->EndConfiguration();
-
-    input_subsystem->GetUDPMotions()->EndConfiguration();
-
-    if (!abort) {
-        (*input_setter)(params);
-    }
-
-    UpdateUI();
-    input_setter = std::nullopt;
-}
-
-void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
-    if (!input_setter || !event) {
-        return;
-    }
-
-    if (want_keyboard_mouse) {
-        SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
-                         false);
-    } else {
-        // We don't want any mouse buttons, so don't stop polling
-        return;
-    }
-
-    SetPollingResult({}, true);
-}
-
-void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
-    if (!input_setter || !event) {
-        return;
-    }
-
-    if (event->key() != Qt::Key_Escape) {
-        if (want_keyboard_mouse) {
-            SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
-                             false);
-        } else {
-            // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
-            return;
-        }
-    }
-
-    SetPollingResult({}, true);
 }
 
 void ConfigureInputPlayer::UpdateControllerIcon() {
@@ -986,14 +936,128 @@ void ConfigureInputPlayer::UpdateMotionButtons() {
     }
 }
 
-void ConfigureInputPlayer::showEvent(QShowEvent* event) {
-    if (bottom_row == nullptr) {
+void ConfigureInputPlayer::UpdateMappingWithDefaults() {
+    if (ui->comboDevices->currentIndex() < 2) {
         return;
     }
-    QWidget::showEvent(event);
-    ui->main->addWidget(bottom_row);
+    const auto& device = input_devices[ui->comboDevices->currentIndex()];
+    auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
+    auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
+    for (std::size_t i = 0; i < buttons_param.size(); ++i) {
+        buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
+    }
+    for (std::size_t i = 0; i < analogs_param.size(); ++i) {
+        analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)];
+    }
+
+    UpdateUI();
 }
 
-void ConfigureInputPlayer::ConnectPlayer(bool connected) {
-    ui->groupConnectedController->setChecked(connected);
+void ConfigureInputPlayer::HandleClick(
+    QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
+    InputCommon::Polling::DeviceType type) {
+    if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) {
+        button->setText(tr("Shake!"));
+    } else {
+        button->setText(tr("[waiting]"));
+    }
+    button->setFocus();
+
+    // The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a
+    // controller, then they don't want keyboard/mouse input
+    want_keyboard_mouse = ui->comboDevices->currentIndex() < 2;
+
+    input_setter = new_input_setter;
+
+    device_pollers = input_subsystem->GetPollers(type);
+
+    for (auto& poller : device_pollers) {
+        poller->Start();
+    }
+
+    QWidget::grabMouse();
+    QWidget::grabKeyboard();
+
+    if (type == InputCommon::Polling::DeviceType::Button) {
+        input_subsystem->GetGCButtons()->BeginConfiguration();
+    } else {
+        input_subsystem->GetGCAnalogs()->BeginConfiguration();
+    }
+
+    if (type == InputCommon::Polling::DeviceType::Motion) {
+        input_subsystem->GetUDPMotions()->BeginConfiguration();
+    }
+
+    timeout_timer->start(2500); // Cancel after 2.5 seconds
+    poll_timer->start(50);      // Check for new inputs every 50ms
+}
+
+void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) {
+    timeout_timer->stop();
+    poll_timer->stop();
+    for (auto& poller : device_pollers) {
+        poller->Stop();
+    }
+
+    QWidget::releaseMouse();
+    QWidget::releaseKeyboard();
+
+    input_subsystem->GetGCButtons()->EndConfiguration();
+    input_subsystem->GetGCAnalogs()->EndConfiguration();
+
+    input_subsystem->GetUDPMotions()->EndConfiguration();
+
+    if (!abort) {
+        (*input_setter)(params);
+    }
+
+    UpdateUI();
+    UpdateInputDeviceCombobox();
+
+    input_setter = std::nullopt;
+}
+
+bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params) const {
+    if (ui->comboDevices->currentIndex() == 0) {
+        return true;
+    }
+
+    const auto current_input_device = input_devices[ui->comboDevices->currentIndex()];
+    return params.Get("engine", "") == current_input_device.Get("class", "") &&
+           params.Get("guid", "") == current_input_device.Get("guid", "") &&
+           params.Get("port", "") == current_input_device.Get("port", "");
+}
+
+void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
+    if (!input_setter || !event) {
+        return;
+    }
+
+    if (want_keyboard_mouse) {
+        SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
+                         false);
+    } else {
+        // We don't want any mouse buttons, so don't stop polling
+        return;
+    }
+
+    SetPollingResult({}, true);
+}
+
+void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
+    if (!input_setter || !event) {
+        return;
+    }
+
+    if (event->key() != Qt::Key_Escape) {
+        if (want_keyboard_mouse) {
+            SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
+                             false);
+        } else {
+            // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
+            return;
+        }
+    }
+
+    SetPollingResult({}, true);
 }
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index c19aefffa..a5414e624 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -51,8 +51,11 @@ public:
     /// Save all button configurations to settings file.
     void ApplyConfiguration();
 
+    /// Set the connection state checkbox (used to sync state).
+    void ConnectPlayer(bool connected);
+
     /// Update the input devices combobox.
-    void UpdateInputDevices();
+    void UpdateInputDeviceCombobox();
 
     /// Restore all buttons to their default values.
     void RestoreDefaults();
@@ -60,9 +63,6 @@ public:
     /// Clear all input configuration.
     void ClearAll();
 
-    /// Set the connection state checkbox (used to sync state).
-    void ConnectPlayer(bool connected);
-
 signals:
     /// Emitted when this controller is connected by the user.
     void Connected(bool connected);
@@ -89,6 +89,9 @@ private:
     /// Finish polling and configure input using the input_setter.
     void SetPollingResult(const Common::ParamPackage& params, bool abort);
 
+    /// Checks whether a given input can be accepted.
+    bool IsInputAcceptable(const Common::ParamPackage& params) const;
+
     /// Handle mouse button press events.
     void mousePressEvent(QMouseEvent* event) override;
 
@@ -98,8 +101,8 @@ private:
     /// Update UI to reflect current configuration.
     void UpdateUI();
 
-    /// Update the controller selection combobox
-    void UpdateControllerCombobox();
+    /// Update the available input devices.
+    void UpdateInputDevices();
 
     /// Update the current controller icon.
     void UpdateControllerIcon();
@@ -164,7 +167,7 @@ private:
     bool want_keyboard_mouse = false;
 
     /// List of physical devices users can map with. If a SDL backed device is selected, then you
-    /// can usue this device to get a default mapping.
+    /// can use this device to get a default mapping.
     std::vector<Common::ParamPackage> input_devices;
 
     /// Bottom row is where console wide settings are held, and its "owned" by the parent

From 57d89e291de0eacfd368784309a0cbf89d38dcc8 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Wed, 23 Sep 2020 09:52:25 -0400
Subject: [PATCH 03/37] input_profiles: Implement input profiles

---
 src/yuzu/CMakeLists.txt                       |   2 +
 src/yuzu/configuration/config.cpp             | 265 +++++++++++-------
 src/yuzu/configuration/config.h               |  20 +-
 .../configure_debug_controller.cpp            |   6 +-
 .../configure_debug_controller.h              |   6 +-
 src/yuzu/configuration/configure_input.cpp    |  30 +-
 src/yuzu/configuration/configure_input.h      |   4 +
 .../configuration/configure_input_player.cpp  | 111 +++++++-
 .../configuration/configure_input_player.h    |  21 +-
 src/yuzu/configuration/configure_per_game.cpp |   3 +-
 src/yuzu/configuration/input_profiles.cpp     | 131 +++++++++
 src/yuzu/configuration/input_profiles.h       |  32 +++
 src/yuzu/main.cpp                             |   2 +-
 13 files changed, 506 insertions(+), 127 deletions(-)
 create mode 100644 src/yuzu/configuration/input_profiles.cpp
 create mode 100644 src/yuzu/configuration/input_profiles.h

diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 8abb74d56..22fe0a2a6 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -108,6 +108,8 @@ add_executable(yuzu
     configuration/configure_web.cpp
     configuration/configure_web.h
     configuration/configure_web.ui
+    configuration/input_profiles.cpp
+    configuration/input_profiles.h
     debugger/console.cpp
     debugger/console.h
     debugger/profiler.cpp
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 1ce62e4a6..5c8b02fbe 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -5,6 +5,7 @@
 #include <array>
 #include <QKeySequence>
 #include <QSettings>
+#include "common/common_paths.h"
 #include "common/file_util.h"
 #include "core/hle/service/acc/profile_manager.h"
 #include "core/hle/service/hid/controllers/npad.h"
@@ -14,14 +15,27 @@
 
 namespace FS = Common::FS;
 
-Config::Config(const std::string& config_file, bool is_global) {
-    // TODO: Don't hardcode the path; let the frontend decide where to put the config files.
-    qt_config_loc = FS::GetUserPath(FS::UserPath::ConfigDir) + config_file;
-    FS::CreateFullPath(qt_config_loc);
-    qt_config =
-        std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
-    global = is_global;
-    Reload();
+Config::Config(const std::string& config_file, ConfigType config_type) : type(config_type) {
+    global = config_type == ConfigType::GlobalConfig;
+
+    switch (config_type) {
+    case ConfigType::GlobalConfig:
+    case ConfigType::PerGameConfig:
+        qt_config_loc = fmt::format("{}" DIR_SEP "{}.ini", FS::GetUserPath(FS::UserPath::ConfigDir),
+                                    config_file);
+        FS::CreateFullPath(qt_config_loc);
+        qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
+                                                QSettings::IniFormat);
+        Reload();
+        break;
+    case ConfigType::InputProfile:
+        qt_config_loc = fmt::format("{}input" DIR_SEP "{}.ini",
+                                    FS::GetUserPath(FS::UserPath::ConfigDir), config_file);
+        FS::CreateFullPath(qt_config_loc);
+        qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
+                                                QSettings::IniFormat);
+        break;
+    }
 }
 
 Config::~Config() {
@@ -242,84 +256,103 @@ const std::array<UISettings::Shortcut, 16> Config::default_hotkeys{{
 }};
 // clang-format on
 
-void Config::ReadPlayerValues() {
-    for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
-        auto& player = Settings::values.players[p];
+void Config::ReadPlayerValue(std::size_t player_index) {
+    const QString player_prefix = [this, player_index] {
+        if (type == ConfigType::InputProfile) {
+            return QString{};
+        } else {
+            return QStringLiteral("player_%1_").arg(player_index);
+        }
+    }();
 
+    auto& player = Settings::values.players[player_index];
+
+    if (player_prefix.isEmpty()) {
+        const auto controller = static_cast<Settings::ControllerType>(
+            qt_config
+                ->value(QStringLiteral("%1type").arg(player_prefix),
+                        static_cast<u8>(Settings::ControllerType::ProController))
+                .toUInt());
+
+        if (controller == Settings::ControllerType::LeftJoycon ||
+            controller == Settings::ControllerType::RightJoycon) {
+            player.controller_type = controller;
+        }
+    } else {
         player.connected =
-            ReadSetting(QStringLiteral("player_%1_connected").arg(p), false).toBool();
+            ReadSetting(QStringLiteral("%1connected").arg(player_prefix), false).toBool();
 
         player.controller_type = static_cast<Settings::ControllerType>(
             qt_config
-                ->value(QStringLiteral("player_%1_type").arg(p),
+                ->value(QStringLiteral("%1type").arg(player_prefix),
                         static_cast<u8>(Settings::ControllerType::ProController))
                 .toUInt());
 
         player.body_color_left = qt_config
-                                     ->value(QStringLiteral("player_%1_body_color_left").arg(p),
+                                     ->value(QStringLiteral("%1body_color_left").arg(player_prefix),
                                              Settings::JOYCON_BODY_NEON_BLUE)
                                      .toUInt();
-        player.body_color_right = qt_config
-                                      ->value(QStringLiteral("player_%1_body_color_right").arg(p),
-                                              Settings::JOYCON_BODY_NEON_RED)
-                                      .toUInt();
-        player.button_color_left = qt_config
-                                       ->value(QStringLiteral("player_%1_button_color_left").arg(p),
-                                               Settings::JOYCON_BUTTONS_NEON_BLUE)
-                                       .toUInt();
+        player.body_color_right =
+            qt_config
+                ->value(QStringLiteral("%1body_color_right").arg(player_prefix),
+                        Settings::JOYCON_BODY_NEON_RED)
+                .toUInt();
+        player.button_color_left =
+            qt_config
+                ->value(QStringLiteral("%1button_color_left").arg(player_prefix),
+                        Settings::JOYCON_BUTTONS_NEON_BLUE)
+                .toUInt();
         player.button_color_right =
             qt_config
-                ->value(QStringLiteral("player_%1_button_color_right").arg(p),
+                ->value(QStringLiteral("%1button_color_right").arg(player_prefix),
                         Settings::JOYCON_BUTTONS_NEON_RED)
                 .toUInt();
+    }
 
-        for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
-            const std::string default_param =
-                InputCommon::GenerateKeyboardParam(default_buttons[i]);
-            auto& player_buttons = player.buttons[i];
+    for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
+        const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
+        auto& player_buttons = player.buttons[i];
 
-            player_buttons = qt_config
-                                 ->value(QStringLiteral("player_%1_").arg(p) +
-                                             QString::fromUtf8(Settings::NativeButton::mapping[i]),
-                                         QString::fromStdString(default_param))
-                                 .toString()
-                                 .toStdString();
-            if (player_buttons.empty()) {
-                player_buttons = default_param;
-            }
+        player_buttons = qt_config
+                             ->value(QStringLiteral("%1").arg(player_prefix) +
+                                         QString::fromUtf8(Settings::NativeButton::mapping[i]),
+                                     QString::fromStdString(default_param))
+                             .toString()
+                             .toStdString();
+        if (player_buttons.empty()) {
+            player_buttons = default_param;
         }
+    }
 
-        for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
-            const std::string default_param =
-                InputCommon::GenerateKeyboardParam(default_motions[i]);
-            auto& player_motions = player.motions[i];
+    for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
+        const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
+        auto& player_motions = player.motions[i];
 
-            player_motions = qt_config
-                                 ->value(QStringLiteral("player_%1_").arg(p) +
-                                             QString::fromUtf8(Settings::NativeMotion::mapping[i]),
-                                         QString::fromStdString(default_param))
-                                 .toString()
-                                 .toStdString();
-            if (player_motions.empty()) {
-                player_motions = default_param;
-            }
+        player_motions = qt_config
+                             ->value(QStringLiteral("%1").arg(player_prefix) +
+                                         QString::fromUtf8(Settings::NativeMotion::mapping[i]),
+                                     QString::fromStdString(default_param))
+                             .toString()
+                             .toStdString();
+        if (player_motions.empty()) {
+            player_motions = default_param;
         }
+    }
 
-        for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
-            const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
-                default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
-                default_analogs[i][3], default_stick_mod[i], 0.5f);
-            auto& player_analogs = player.analogs[i];
+    for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
+        const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
+            default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
+            default_analogs[i][3], default_stick_mod[i], 0.5f);
+        auto& player_analogs = player.analogs[i];
 
-            player_analogs = qt_config
-                                 ->value(QStringLiteral("player_%1_").arg(p) +
-                                             QString::fromUtf8(Settings::NativeAnalog::mapping[i]),
-                                         QString::fromStdString(default_param))
-                                 .toString()
-                                 .toStdString();
-            if (player_analogs.empty()) {
-                player_analogs = default_param;
-            }
+        player_analogs = qt_config
+                             ->value(QStringLiteral("%1").arg(player_prefix) +
+                                         QString::fromUtf8(Settings::NativeAnalog::mapping[i]),
+                                     QString::fromStdString(default_param))
+                             .toString()
+                             .toStdString();
+        if (player_analogs.empty()) {
+            player_analogs = default_param;
         }
     }
 }
@@ -436,7 +469,9 @@ void Config::ReadAudioValues() {
 void Config::ReadControlValues() {
     qt_config->beginGroup(QStringLiteral("Controls"));
 
-    ReadPlayerValues();
+    for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
+        ReadPlayerValue(p);
+    }
     ReadDebugValues();
     ReadKeyboardValues();
     ReadMouseValues();
@@ -920,49 +955,55 @@ void Config::ReadValues() {
     ReadSystemValues();
 }
 
-void Config::SavePlayerValues() {
-    for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
-        const auto& player = Settings::values.players[p];
+void Config::SavePlayerValue(std::size_t player_index) {
+    const QString player_prefix = [this, player_index] {
+        if (type == ConfigType::InputProfile) {
+            return QString{};
+        } else {
+            return QStringLiteral("player_%1_").arg(player_index);
+        }
+    }();
 
-        WriteSetting(QStringLiteral("player_%1_connected").arg(p), player.connected, false);
-        WriteSetting(QStringLiteral("player_%1_type").arg(p),
-                     static_cast<u8>(player.controller_type),
-                     static_cast<u8>(Settings::ControllerType::ProController));
+    const auto& player = Settings::values.players[player_index];
 
-        WriteSetting(QStringLiteral("player_%1_body_color_left").arg(p), player.body_color_left,
+    WriteSetting(QStringLiteral("%1type").arg(player_prefix),
+                 static_cast<u8>(player.controller_type),
+                 static_cast<u8>(Settings::ControllerType::ProController));
+
+    if (!player_prefix.isEmpty()) {
+        WriteSetting(QStringLiteral("%1connected").arg(player_prefix), player.connected, false);
+        WriteSetting(QStringLiteral("%1body_color_left").arg(player_prefix), player.body_color_left,
                      Settings::JOYCON_BODY_NEON_BLUE);
-        WriteSetting(QStringLiteral("player_%1_body_color_right").arg(p), player.body_color_right,
-                     Settings::JOYCON_BODY_NEON_RED);
-        WriteSetting(QStringLiteral("player_%1_button_color_left").arg(p), player.button_color_left,
-                     Settings::JOYCON_BUTTONS_NEON_BLUE);
-        WriteSetting(QStringLiteral("player_%1_button_color_right").arg(p),
+        WriteSetting(QStringLiteral("%1body_color_right").arg(player_prefix),
+                     player.body_color_right, Settings::JOYCON_BODY_NEON_RED);
+        WriteSetting(QStringLiteral("%1button_color_left").arg(player_prefix),
+                     player.button_color_left, Settings::JOYCON_BUTTONS_NEON_BLUE);
+        WriteSetting(QStringLiteral("%1button_color_right").arg(player_prefix),
                      player.button_color_right, Settings::JOYCON_BUTTONS_NEON_RED);
+    }
 
-        for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
-            const std::string default_param =
-                InputCommon::GenerateKeyboardParam(default_buttons[i]);
-            WriteSetting(QStringLiteral("player_%1_").arg(p) +
-                             QString::fromStdString(Settings::NativeButton::mapping[i]),
-                         QString::fromStdString(player.buttons[i]),
-                         QString::fromStdString(default_param));
-        }
-        for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
-            const std::string default_param =
-                InputCommon::GenerateKeyboardParam(default_motions[i]);
-            WriteSetting(QStringLiteral("player_%1_").arg(p) +
-                             QString::fromStdString(Settings::NativeMotion::mapping[i]),
-                         QString::fromStdString(player.motions[i]),
-                         QString::fromStdString(default_param));
-        }
-        for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
-            const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
-                default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
-                default_analogs[i][3], default_stick_mod[i], 0.5f);
-            WriteSetting(QStringLiteral("player_%1_").arg(p) +
-                             QString::fromStdString(Settings::NativeAnalog::mapping[i]),
-                         QString::fromStdString(player.analogs[i]),
-                         QString::fromStdString(default_param));
-        }
+    for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
+        const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
+        WriteSetting(QStringLiteral("%1").arg(player_prefix) +
+                         QString::fromStdString(Settings::NativeButton::mapping[i]),
+                     QString::fromStdString(player.buttons[i]),
+                     QString::fromStdString(default_param));
+    }
+    for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
+        const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
+        WriteSetting(QStringLiteral("%1").arg(player_prefix) +
+                         QString::fromStdString(Settings::NativeMotion::mapping[i]),
+                     QString::fromStdString(player.motions[i]),
+                     QString::fromStdString(default_param));
+    }
+    for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
+        const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
+            default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
+            default_analogs[i][3], default_stick_mod[i], 0.5f);
+        WriteSetting(QStringLiteral("%1").arg(player_prefix) +
+                         QString::fromStdString(Settings::NativeAnalog::mapping[i]),
+                     QString::fromStdString(player.analogs[i]),
+                     QString::fromStdString(default_param));
     }
 }
 
@@ -1087,7 +1128,9 @@ void Config::SaveAudioValues() {
 void Config::SaveControlValues() {
     qt_config->beginGroup(QStringLiteral("Controls"));
 
-    SavePlayerValues();
+    for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
+        SavePlayerValue(p);
+    }
     SaveDebugValues();
     SaveMouseValues();
     SaveTouchscreenValues();
@@ -1515,3 +1558,19 @@ void Config::Save() {
     Settings::Sanitize();
     SaveValues();
 }
+
+void Config::ReadControlPlayerValue(std::size_t player_index) {
+    qt_config->beginGroup(QStringLiteral("Controls"));
+    ReadPlayerValue(player_index);
+    qt_config->endGroup();
+}
+
+void Config::SaveControlPlayerValue(std::size_t player_index) {
+    qt_config->beginGroup(QStringLiteral("Controls"));
+    SavePlayerValue(player_index);
+    qt_config->endGroup();
+}
+
+const std::string& Config::GetConfigFilePath() const {
+    return qt_config_loc;
+}
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 5d8e45d78..a1ffca48f 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -16,12 +16,24 @@ class QSettings;
 
 class Config {
 public:
-    explicit Config(const std::string& config_loc = "qt-config.ini", bool is_global = true);
+    enum class ConfigType {
+        GlobalConfig,
+        PerGameConfig,
+        InputProfile,
+    };
+
+    explicit Config(const std::string& config_loc = "qt-config",
+                    ConfigType config_type = ConfigType::GlobalConfig);
     ~Config();
 
     void Reload();
     void Save();
 
+    void ReadControlPlayerValue(std::size_t player_index);
+    void SaveControlPlayerValue(std::size_t player_index);
+
+    const std::string& GetConfigFilePath() const;
+
     static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
     static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
     static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
@@ -34,7 +46,7 @@ public:
 
 private:
     void ReadValues();
-    void ReadPlayerValues();
+    void ReadPlayerValue(std::size_t player_index);
     void ReadDebugValues();
     void ReadKeyboardValues();
     void ReadMouseValues();
@@ -62,7 +74,7 @@ private:
     void ReadWebServiceValues();
 
     void SaveValues();
-    void SavePlayerValues();
+    void SavePlayerValue(std::size_t player_index);
     void SaveDebugValues();
     void SaveMouseValues();
     void SaveTouchscreenValues();
@@ -111,9 +123,9 @@ private:
     void WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
                             const QVariant& default_value);
 
+    ConfigType type;
     std::unique_ptr<QSettings> qt_config;
     std::string qt_config_loc;
-
     bool global;
 };
 
diff --git a/src/yuzu/configuration/configure_debug_controller.cpp b/src/yuzu/configuration/configure_debug_controller.cpp
index 0097c9a29..6dc9c5e57 100644
--- a/src/yuzu/configuration/configure_debug_controller.cpp
+++ b/src/yuzu/configuration/configure_debug_controller.cpp
@@ -6,9 +6,11 @@
 #include "yuzu/configuration/configure_debug_controller.h"
 
 ConfigureDebugController::ConfigureDebugController(QWidget* parent,
-                                                   InputCommon::InputSubsystem* input_subsystem)
+                                                   InputCommon::InputSubsystem* input_subsystem,
+                                                   InputProfiles* profiles)
     : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()),
-      debug_controller(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, true)) {
+      debug_controller(
+          new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, true)) {
     ui->setupUi(this);
 
     ui->controllerLayout->addWidget(debug_controller);
diff --git a/src/yuzu/configuration/configure_debug_controller.h b/src/yuzu/configuration/configure_debug_controller.h
index 34dcf705f..2694b3419 100644
--- a/src/yuzu/configuration/configure_debug_controller.h
+++ b/src/yuzu/configuration/configure_debug_controller.h
@@ -10,6 +10,8 @@
 
 class QPushButton;
 
+class InputProfiles;
+
 namespace InputCommon {
 class InputSubsystem;
 }
@@ -22,8 +24,8 @@ class ConfigureDebugController : public QDialog {
     Q_OBJECT
 
 public:
-    explicit ConfigureDebugController(QWidget* parent,
-                                      InputCommon::InputSubsystem* input_subsystem);
+    explicit ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem,
+                                      InputProfiles* profiles);
     ~ConfigureDebugController() override;
 
     void ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index f2932aa0b..523ece426 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -23,6 +23,7 @@
 #include "yuzu/configuration/configure_motion_touch.h"
 #include "yuzu/configuration/configure_mouse_advanced.h"
 #include "yuzu/configuration/configure_touchscreen_advanced.h"
+#include "yuzu/configuration/input_profiles.h"
 
 namespace {
 template <typename Dialog, typename... Args>
@@ -64,7 +65,8 @@ void OnDockedModeChanged(bool last_state, bool new_state) {
 }
 
 ConfigureInput::ConfigureInput(QWidget* parent)
-    : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
+    : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()),
+      profiles(std::make_unique<InputProfiles>()) {
     ui->setupUi(this);
 }
 
@@ -73,14 +75,22 @@ ConfigureInput::~ConfigureInput() = default;
 void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
                                 std::size_t max_players) {
     player_controllers = {
-        new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem),
-        new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem),
-        new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem),
-        new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem),
-        new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem),
-        new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem),
-        new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem),
-        new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem),
+        new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem,
+                                 profiles.get()),
+        new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem,
+                                 profiles.get()),
+        new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem,
+                                 profiles.get()),
+        new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem,
+                                 profiles.get()),
+        new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem,
+                                 profiles.get()),
+        new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem,
+                                 profiles.get()),
+        new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem,
+                                 profiles.get()),
+        new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem,
+                                 profiles.get()),
     };
 
     player_tabs = {
@@ -134,7 +144,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
     ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
     ui->tabAdvanced->layout()->addWidget(advanced);
     connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] {
-        CallConfigureDialog<ConfigureDebugController>(*this, input_subsystem);
+        CallConfigureDialog<ConfigureDebugController>(*this, input_subsystem, profiles.get());
     });
     connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] {
         CallConfigureDialog<ConfigureMouseAdvanced>(*this, input_subsystem);
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index 0e8b2fd4e..f135a4299 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -19,6 +19,8 @@ class QCheckBox;
 class QString;
 class QTimer;
 
+class InputProfiles;
+
 namespace InputCommon {
 class InputSubsystem;
 }
@@ -61,6 +63,8 @@ private:
 
     std::unique_ptr<Ui::ConfigureInput> ui;
 
+    std::unique_ptr<InputProfiles> profiles;
+
     std::array<ConfigureInputPlayer*, 8> player_controllers;
     std::array<QWidget*, 8> player_tabs;
     std::array<QCheckBox*, 8> player_connected;
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 0de0c6999..b4de2f6af 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -22,6 +22,8 @@
 #include "ui_configure_input_player.h"
 #include "yuzu/configuration/config.h"
 #include "yuzu/configuration/configure_input_player.h"
+#include "yuzu/configuration/input_profiles.h"
+#include "yuzu/util/limitable_input_dialog.h"
 
 constexpr std::size_t HANDHELD_INDEX = 8;
 
@@ -240,10 +242,11 @@ QString AnalogToText(const Common::ParamPackage& param, const std::string& dir)
 ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index,
                                            QWidget* bottom_row,
                                            InputCommon::InputSubsystem* input_subsystem_,
-                                           bool debug)
+                                           InputProfiles* profiles_, bool debug)
     : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
-      debug(debug), input_subsystem{input_subsystem_}, timeout_timer(std::make_unique<QTimer>()),
-      poll_timer(std::make_unique<QTimer>()), bottom_row(bottom_row) {
+      debug(debug), input_subsystem{input_subsystem_}, profiles(profiles_),
+      timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()),
+      bottom_row(bottom_row) {
     ui->setupUi(this);
 
     setFocusPolicy(Qt::ClickFocus);
@@ -521,6 +524,17 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
         }
     });
 
+    RefreshInputProfiles();
+
+    connect(ui->buttonProfilesNew, &QPushButton::clicked, this,
+            &ConfigureInputPlayer::CreateProfile);
+    connect(ui->buttonProfilesDelete, &QPushButton::clicked, this,
+            &ConfigureInputPlayer::DeleteProfile);
+    connect(ui->comboProfiles, qOverload<int>(&QComboBox::activated), this,
+            &ConfigureInputPlayer::LoadProfile);
+    connect(ui->buttonProfilesSave, &QPushButton::clicked, this,
+            &ConfigureInputPlayer::SaveProfile);
+
     LoadConfiguration();
 
     // TODO(wwylele): enable this when we actually emulate it
@@ -1061,3 +1075,94 @@ void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
 
     SetPollingResult({}, true);
 }
+
+void ConfigureInputPlayer::CreateProfile() {
+    const auto profile_name =
+        LimitableInputDialog::GetText(this, tr("New Profile"), tr("Enter a profile name:"), 1, 20);
+
+    if (profile_name.isEmpty()) {
+        return;
+    }
+
+    if (!profiles->IsProfileNameValid(profile_name.toStdString())) {
+        QMessageBox::critical(this, tr("Create Input Profile"),
+                              tr("The given profile name is not valid!"));
+        return;
+    }
+
+    ApplyConfiguration();
+
+    if (!profiles->CreateProfile(profile_name.toStdString(), player_index)) {
+        QMessageBox::critical(this, tr("Create Input Profile"),
+                              tr("Failed to create the input profile \"%1\"").arg(profile_name));
+        RefreshInputProfiles();
+        return;
+    }
+
+    ui->comboProfiles->addItem(profile_name);
+    ui->comboProfiles->setCurrentIndex(ui->comboProfiles->count() - 1);
+}
+
+void ConfigureInputPlayer::DeleteProfile() {
+    const QString profile_name = ui->comboProfiles->itemText(ui->comboProfiles->currentIndex());
+
+    if (profile_name.isEmpty()) {
+        return;
+    }
+
+    if (!profiles->DeleteProfile(profile_name.toStdString())) {
+        QMessageBox::critical(this, tr("Delete Input Profile"),
+                              tr("Failed to delete the input profile \"%1\"").arg(profile_name));
+        RefreshInputProfiles();
+        return;
+    }
+
+    ui->comboProfiles->removeItem(ui->comboProfiles->currentIndex());
+    ui->comboProfiles->setCurrentIndex(-1);
+}
+
+void ConfigureInputPlayer::LoadProfile() {
+    const QString profile_name = ui->comboProfiles->itemText(ui->comboProfiles->currentIndex());
+
+    if (profile_name.isEmpty()) {
+        return;
+    }
+
+    ApplyConfiguration();
+
+    if (!profiles->LoadProfile(profile_name.toStdString(), player_index)) {
+        QMessageBox::critical(this, tr("Load Input Profile"),
+                              tr("Failed to load the input profile \"%1\"").arg(profile_name));
+        RefreshInputProfiles();
+        return;
+    }
+
+    LoadConfiguration();
+}
+
+void ConfigureInputPlayer::SaveProfile() {
+    const QString profile_name = ui->comboProfiles->itemText(ui->comboProfiles->currentIndex());
+
+    if (profile_name.isEmpty()) {
+        return;
+    }
+
+    ApplyConfiguration();
+
+    if (!profiles->SaveProfile(profile_name.toStdString(), player_index)) {
+        QMessageBox::critical(this, tr("Save Input Profile"),
+                              tr("Failed to save the input profile \"%1\"").arg(profile_name));
+        RefreshInputProfiles();
+        return;
+    }
+}
+
+void ConfigureInputPlayer::RefreshInputProfiles() {
+    ui->comboProfiles->clear();
+
+    for (const auto& profile_name : profiles->GetInputProfileNames()) {
+        ui->comboProfiles->addItem(QString::fromStdString(profile_name));
+    }
+
+    ui->comboProfiles->setCurrentIndex(-1);
+}
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index a5414e624..05dee5af5 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -26,6 +26,8 @@ class QString;
 class QTimer;
 class QWidget;
 
+class InputProfiles;
+
 namespace InputCommon {
 class InputSubsystem;
 }
@@ -45,7 +47,7 @@ class ConfigureInputPlayer : public QWidget {
 public:
     explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row,
                                   InputCommon::InputSubsystem* input_subsystem_,
-                                  bool debug = false);
+                                  InputProfiles* profiles_, bool debug = false);
     ~ConfigureInputPlayer() override;
 
     /// Save all button configurations to settings file.
@@ -116,6 +118,21 @@ private:
     /// Gets the default controller mapping for this device and auto configures the input to match.
     void UpdateMappingWithDefaults();
 
+    /// Creates a controller profile.
+    void CreateProfile();
+
+    /// Deletes the selected controller profile.
+    void DeleteProfile();
+
+    /// Loads the selected controller profile.
+    void LoadProfile();
+
+    /// Saves the current controller configuration into a selected controller profile.
+    void SaveProfile();
+
+    /// Refreshes the list of controller profiles.
+    void RefreshInputProfiles();
+
     std::unique_ptr<Ui::ConfigureInputPlayer> ui;
 
     std::size_t player_index;
@@ -123,6 +140,8 @@ private:
 
     InputCommon::InputSubsystem* input_subsystem;
 
+    InputProfiles* profiles;
+
     std::unique_ptr<QTimer> timeout_timer;
     std::unique_ptr<QTimer> poll_timer;
 
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index 002db3f93..81464dd37 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -29,7 +29,8 @@
 
 ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id)
     : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) {
-    game_config = std::make_unique<Config>(fmt::format("{:016X}.ini", title_id), false);
+    game_config = std::make_unique<Config>(fmt::format("{:016X}", title_id),
+                                           Config::ConfigType::PerGameConfig);
 
     Settings::SetConfiguringGlobal(false);
 
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp
new file mode 100644
index 000000000..e87aededb
--- /dev/null
+++ b/src/yuzu/configuration/input_profiles.cpp
@@ -0,0 +1,131 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <fmt/format.h>
+
+#include "common/common_paths.h"
+#include "common/file_util.h"
+#include "yuzu/configuration/config.h"
+#include "yuzu/configuration/input_profiles.h"
+
+namespace FS = Common::FS;
+
+namespace {
+
+bool ProfileExistsInFilesystem(std::string_view profile_name) {
+    return FS::Exists(fmt::format("{}input" DIR_SEP "{}.ini",
+                                  FS::GetUserPath(FS::UserPath::ConfigDir), profile_name));
+}
+
+bool IsINI(std::string_view filename) {
+    const std::size_t index = filename.rfind('.');
+
+    if (index == std::string::npos) {
+        return false;
+    }
+
+    return filename.substr(index) == ".ini";
+}
+
+std::string GetNameWithoutExtension(const std::string& filename) {
+    const std::size_t index = filename.rfind('.');
+
+    if (index == std::string::npos) {
+        return filename;
+    }
+
+    return filename.substr(0, index);
+}
+
+} // namespace
+
+InputProfiles::InputProfiles() {
+    const std::string input_profile_loc =
+        fmt::format("{}input", FS::GetUserPath(FS::UserPath::ConfigDir));
+
+    FS::ForeachDirectoryEntry(
+        nullptr, input_profile_loc,
+        [this](u64* entries_out, const std::string& directory, const std::string& filename) {
+            if (IsINI(filename) && IsProfileNameValid(GetNameWithoutExtension(filename))) {
+                map_profiles.insert_or_assign(
+                    GetNameWithoutExtension(filename),
+                    std::make_unique<Config>(GetNameWithoutExtension(filename),
+                                             Config::ConfigType::InputProfile));
+            }
+            return true;
+        });
+}
+
+InputProfiles::~InputProfiles() = default;
+
+std::vector<std::string> InputProfiles::GetInputProfileNames() {
+    std::vector<std::string> profile_names;
+    profile_names.reserve(map_profiles.size());
+
+    for (const auto& [profile_name, config] : map_profiles) {
+        if (!ProfileExistsInFilesystem(profile_name)) {
+            DeleteProfile(profile_name);
+            continue;
+        }
+
+        profile_names.push_back(profile_name);
+    }
+
+    return profile_names;
+}
+
+bool InputProfiles::IsProfileNameValid(std::string_view profile_name) {
+    return profile_name.find_first_of("<>:;\"/\\|,.!?*") == std::string::npos;
+}
+
+bool InputProfiles::CreateProfile(const std::string& profile_name, std::size_t player_index) {
+    if (ProfileExistsInMap(profile_name)) {
+        return false;
+    }
+
+    map_profiles.insert_or_assign(
+        profile_name, std::make_unique<Config>(profile_name, Config::ConfigType::InputProfile));
+
+    return SaveProfile(profile_name, player_index);
+}
+
+bool InputProfiles::DeleteProfile(const std::string& profile_name) {
+    if (!ProfileExistsInMap(profile_name)) {
+        return false;
+    }
+
+    if (!ProfileExistsInFilesystem(profile_name) ||
+        FS::Delete(map_profiles[profile_name]->GetConfigFilePath())) {
+        map_profiles.erase(profile_name);
+    }
+
+    return !ProfileExistsInMap(profile_name) && !ProfileExistsInFilesystem(profile_name);
+}
+
+bool InputProfiles::LoadProfile(const std::string& profile_name, std::size_t player_index) {
+    if (!ProfileExistsInMap(profile_name)) {
+        return false;
+    }
+
+    if (!ProfileExistsInFilesystem(profile_name)) {
+        map_profiles.erase(profile_name);
+        return false;
+    }
+
+    map_profiles[profile_name]->ReadControlPlayerValue(player_index);
+    return true;
+}
+
+bool InputProfiles::SaveProfile(const std::string& profile_name, std::size_t player_index) {
+    if (!ProfileExistsInMap(profile_name)) {
+        return false;
+    }
+
+    map_profiles[profile_name]->SaveControlPlayerValue(player_index);
+    return true;
+}
+
+bool InputProfiles::ProfileExistsInMap(const std::string& profile_name) const {
+    return map_profiles.find(profile_name) != map_profiles.end();
+}
diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h
new file mode 100644
index 000000000..cb41fd9be
--- /dev/null
+++ b/src/yuzu/configuration/input_profiles.h
@@ -0,0 +1,32 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include <string_view>
+#include <unordered_map>
+
+class Config;
+
+class InputProfiles {
+
+public:
+    explicit InputProfiles();
+    virtual ~InputProfiles();
+
+    std::vector<std::string> GetInputProfileNames();
+
+    static bool IsProfileNameValid(std::string_view profile_name);
+
+    bool CreateProfile(const std::string& profile_name, std::size_t player_index);
+    bool DeleteProfile(const std::string& profile_name);
+    bool LoadProfile(const std::string& profile_name, std::size_t player_index);
+    bool SaveProfile(const std::string& profile_name, std::size_t player_index);
+
+private:
+    bool ProfileExistsInMap(const std::string& profile_name) const;
+
+    std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles;
+};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 18e68e590..4ff7fd92f 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1087,7 +1087,7 @@ void GMainWindow::BootGame(const QString& filename) {
     const auto loader = Loader::GetLoader(v_file);
     if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) {
         // Load per game settings
-        Config per_game_config(fmt::format("{:016X}.ini", title_id), false);
+        Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig);
     }
 
     Settings::LogSettings();

From 484623cd613b01a029a8a837ed7e2e5657d27202 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 27 Sep 2020 09:50:35 -0400
Subject: [PATCH 04/37] bootmanager: Allow mouse clicks only if touch is
 disabled

Previously mouse clicks will not register when touch is disabled.
This rectifies that and allows mouse clicks to be mapped to other buttons if the touchscreen is disabled.
---
 src/yuzu/bootmanager.cpp | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index e38bc7a9a..d62b0efc2 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -382,7 +382,12 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
 }
 
 void GRenderWindow::mousePressEvent(QMouseEvent* event) {
-    // touch input is handled in TouchBeginEvent
+    if (!Settings::values.touchscreen.enabled) {
+        input_subsystem->GetKeyboard()->PressKey(event->button());
+        return;
+    }
+
+    // Touch input is handled in TouchBeginEvent
     if (event->source() == Qt::MouseEventSynthesizedBySystem) {
         return;
     }
@@ -398,7 +403,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
 }
 
 void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
-    // touch input is handled in TouchUpdateEvent
+    // Touch input is handled in TouchUpdateEvent
     if (event->source() == Qt::MouseEventSynthesizedBySystem) {
         return;
     }
@@ -411,7 +416,12 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
 }
 
 void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
-    // touch input is handled in TouchEndEvent
+    if (!Settings::values.touchscreen.enabled) {
+        input_subsystem->GetKeyboard()->ReleaseKey(event->button());
+        return;
+    }
+
+    // Touch input is handled in TouchEndEvent
     if (event->source() == Qt::MouseEventSynthesizedBySystem) {
         return;
     }

From 5cafa70d3b7f24881b578d2d473dc993fc47364b Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 27 Sep 2020 11:18:07 -0400
Subject: [PATCH 05/37] applets/controller: Auto accept a valid single player
 configuration

---
 src/yuzu/applets/controller.cpp | 29 ++++++++++++++++++-----------
 src/yuzu/applets/controller.h   |  8 +++++---
 src/yuzu/main.cpp               |  1 +
 3 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index c6fa3e4f6..ee770f315 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -229,6 +229,13 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
     connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
             &QtControllerSelectorDialog::ApplyConfiguration);
 
+    // Enhancement: Check if the parameters have already been met before disconnecting controllers.
+    // If all the parameters are met AND only allows a single player,
+    // stop the constructor here as we do not need to continue.
+    if (CheckIfParametersMet() && parameters.enable_single_mode) {
+        return;
+    }
+
     // If keep_controllers_connected is false, forcefully disconnect all controllers
     if (!parameters.keep_controllers_connected) {
         for (auto player : player_groupboxes) {
@@ -236,13 +243,18 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
         }
     }
 
-    CheckIfParametersMet();
-
     resize(0, 0);
 }
 
 QtControllerSelectorDialog::~QtControllerSelectorDialog() = default;
 
+int QtControllerSelectorDialog::exec() {
+    if (parameters_met && parameters.enable_single_mode) {
+        return QDialog::Accepted;
+    }
+    return QDialog::exec();
+}
+
 void QtControllerSelectorDialog::ApplyConfiguration() {
     // Update the controller state once more, just to be sure they are properly applied.
     for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
@@ -287,7 +299,7 @@ void QtControllerSelectorDialog::CallConfigureInputDialog() {
     CheckIfParametersMet();
 }
 
-void QtControllerSelectorDialog::CheckIfParametersMet() {
+bool QtControllerSelectorDialog::CheckIfParametersMet() {
     // Here, we check and validate the current configuration against all applicable parameters.
     const auto num_connected_players = static_cast<int>(
         std::count_if(player_groupboxes.begin(), player_groupboxes.end(),
@@ -301,7 +313,7 @@ void QtControllerSelectorDialog::CheckIfParametersMet() {
         num_connected_players > max_supported_players) {
         parameters_met = false;
         ui->buttonBox->setEnabled(parameters_met);
-        return;
+        return parameters_met;
     }
 
     // Next, check against all connected controllers.
@@ -326,14 +338,9 @@ void QtControllerSelectorDialog::CheckIfParametersMet() {
         return true;
     }();
 
-    if (!all_controllers_compatible) {
-        parameters_met = false;
-        ui->buttonBox->setEnabled(parameters_met);
-        return;
-    }
-
-    parameters_met = true;
+    parameters_met = all_controllers_compatible;
     ui->buttonBox->setEnabled(parameters_met);
+    return parameters_met;
 }
 
 void QtControllerSelectorDialog::SetSupportedControllers() {
diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h
index 729ecc831..8fefecf05 100644
--- a/src/yuzu/applets/controller.h
+++ b/src/yuzu/applets/controller.h
@@ -33,6 +33,8 @@ public:
                                         InputCommon::InputSubsystem* input_subsystem_);
     ~QtControllerSelectorDialog() override;
 
+    int exec() override;
+
 private:
     // Applies the current configuration.
     void ApplyConfiguration();
@@ -43,9 +45,9 @@ private:
     // Initializes the "Configure Input" Dialog.
     void CallConfigureInputDialog();
 
-    // Checks the current configuration against the given parameters and
-    // sets the value of parameters_met.
-    void CheckIfParametersMet();
+    // Checks the current configuration against the given parameters.
+    // This sets and returns the value of parameters_met.
+    bool CheckIfParametersMet();
 
     // Sets the controller icons for "Supported Controller Types".
     void SetSupportedControllers();
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 4ff7fd92f..5f9f416ea 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -288,6 +288,7 @@ GMainWindow::~GMainWindow() {
 void GMainWindow::ControllerSelectorReconfigureControllers(
     const Core::Frontend::ControllerParameters& parameters) {
     QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
+
     dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
                           Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
     dialog.setWindowModality(Qt::WindowModal);

From c0c4ed0d3bff9670bfaab6a8de304e37ec9e0896 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 27 Sep 2020 11:40:15 -0400
Subject: [PATCH 06/37] controllers/npad: Connect a controller on init if none
 are connected

---
 src/core/hle/service/hid/controllers/npad.cpp | 13 +++++++++++++
 src/yuzu/configuration/config.cpp             |  3 ++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index e311bc18c..c4b26196a 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -224,6 +224,19 @@ void Controller_NPad::OnInit() {
                                                player.connected};
                    });
 
+    // Connect the Player 1 or Handheld controller if none are connected.
+    if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
+                     [](const ControllerHolder& controller) { return controller.is_connected; })) {
+        const auto controller = MapSettingsTypeToNPad(Settings::values.players[0].controller_type);
+        if (controller == NPadControllerType::Handheld) {
+            Settings::values.players[HANDHELD_INDEX].connected = true;
+            connected_controllers[HANDHELD_INDEX] = {controller, true};
+        } else {
+            Settings::values.players[0].connected = true;
+            connected_controllers[0] = {controller, true};
+        }
+    }
+
     // Account for handheld
     if (connected_controllers[HANDHELD_INDEX].is_connected) {
         connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld;
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 5c8b02fbe..545cafca9 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -280,7 +280,8 @@ void Config::ReadPlayerValue(std::size_t player_index) {
         }
     } else {
         player.connected =
-            ReadSetting(QStringLiteral("%1connected").arg(player_prefix), false).toBool();
+            ReadSetting(QStringLiteral("%1connected").arg(player_prefix), player_index == 0)
+                .toBool();
 
         player.controller_type = static_cast<Settings::ControllerType>(
             qt_config

From 64e174237e7ad9ae082e24303d321534f4e78bca Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 27 Sep 2020 14:20:22 -0400
Subject: [PATCH 07/37] config: Migrate config files into config/custom

Co-authored-by: lat9nq <lat9nq@virginia.edu>
---
 src/yuzu/configuration/config.cpp | 49 +++++++++++++++++++------------
 src/yuzu/configuration/config.h   |  4 ++-
 src/yuzu/main.cpp                 | 28 +++++++++++++++++-
 src/yuzu/main.h                   |  1 +
 4 files changed, 61 insertions(+), 21 deletions(-)

diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 545cafca9..618f991b0 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -15,27 +15,10 @@
 
 namespace FS = Common::FS;
 
-Config::Config(const std::string& config_file, ConfigType config_type) : type(config_type) {
+Config::Config(const std::string& config_name, ConfigType config_type) : type(config_type) {
     global = config_type == ConfigType::GlobalConfig;
 
-    switch (config_type) {
-    case ConfigType::GlobalConfig:
-    case ConfigType::PerGameConfig:
-        qt_config_loc = fmt::format("{}" DIR_SEP "{}.ini", FS::GetUserPath(FS::UserPath::ConfigDir),
-                                    config_file);
-        FS::CreateFullPath(qt_config_loc);
-        qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
-                                                QSettings::IniFormat);
-        Reload();
-        break;
-    case ConfigType::InputProfile:
-        qt_config_loc = fmt::format("{}input" DIR_SEP "{}.ini",
-                                    FS::GetUserPath(FS::UserPath::ConfigDir), config_file);
-        FS::CreateFullPath(qt_config_loc);
-        qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
-                                                QSettings::IniFormat);
-        break;
-    }
+    Initialize(config_name);
 }
 
 Config::~Config() {
@@ -256,6 +239,34 @@ const std::array<UISettings::Shortcut, 16> Config::default_hotkeys{{
 }};
 // clang-format on
 
+void Config::Initialize(const std::string& config_name) {
+    switch (type) {
+    case ConfigType::GlobalConfig:
+        qt_config_loc = fmt::format("{}" DIR_SEP "{}.ini", FS::GetUserPath(FS::UserPath::ConfigDir),
+                                    config_name);
+        FS::CreateFullPath(qt_config_loc);
+        qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
+                                                QSettings::IniFormat);
+        Reload();
+        break;
+    case ConfigType::PerGameConfig:
+        qt_config_loc = fmt::format("{}custom" DIR_SEP "{}.ini",
+                                    FS::GetUserPath(FS::UserPath::ConfigDir), config_name);
+        FS::CreateFullPath(qt_config_loc);
+        qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
+                                                QSettings::IniFormat);
+        Reload();
+        break;
+    case ConfigType::InputProfile:
+        qt_config_loc = fmt::format("{}input" DIR_SEP "{}.ini",
+                                    FS::GetUserPath(FS::UserPath::ConfigDir), config_name);
+        FS::CreateFullPath(qt_config_loc);
+        qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
+                                                QSettings::IniFormat);
+        break;
+    }
+}
+
 void Config::ReadPlayerValue(std::size_t player_index) {
     const QString player_prefix = [this, player_index] {
         if (type == ConfigType::InputProfile) {
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index a1ffca48f..8a600e19d 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -22,7 +22,7 @@ public:
         InputProfile,
     };
 
-    explicit Config(const std::string& config_loc = "qt-config",
+    explicit Config(const std::string& config_name = "qt-config",
                     ConfigType config_type = ConfigType::GlobalConfig);
     ~Config();
 
@@ -45,6 +45,8 @@ public:
     static const std::array<UISettings::Shortcut, 16> default_hotkeys;
 
 private:
+    void Initialize(const std::string& config_name);
+
     void ReadValues();
     void ReadPlayerValue(std::size_t player_index);
     void ReadDebugValues();
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 5f9f416ea..4a3dea2a5 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -50,6 +50,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
 #include <QDesktopServices>
 #include <QDesktopWidget>
 #include <QDialogButtonBox>
+#include <QDir>
 #include <QFile>
 #include <QFileDialog>
 #include <QInputDialog>
@@ -277,6 +278,8 @@ GMainWindow::GMainWindow()
     if (args.length() >= 2) {
         BootGame(args[1]);
     }
+
+    MigrateConfigFiles();
 }
 
 GMainWindow::~GMainWindow() {
@@ -1578,7 +1581,8 @@ void GMainWindow::RemoveCustomConfiguration(u64 program_id) {
     const QString config_dir =
         QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir));
     const QString custom_config_file_path =
-        config_dir + QString::fromStdString(fmt::format("{:016X}.ini", program_id));
+        config_dir + QStringLiteral("custom") + QDir::separator() +
+        QString::fromStdString(fmt::format("{:016X}.ini", program_id));
 
     if (!QFile::exists(custom_config_file_path)) {
         QMessageBox::warning(this, tr("Error Removing Custom Configuration"),
@@ -2394,6 +2398,28 @@ void GMainWindow::OnCaptureScreenshot() {
     OnStartGame();
 }
 
+// TODO: Written 2020-10-01: Remove per-game config migration code when it is irrelevant
+void GMainWindow::MigrateConfigFiles() {
+    const std::string& config_dir_str = Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir);
+    const QDir config_dir = QDir(QString::fromStdString(config_dir_str));
+    const QStringList config_dir_list = config_dir.entryList(QStringList(QStringLiteral("*.ini")));
+
+    Common::FS::CreateFullPath(fmt::format("{}custom" DIR_SEP, config_dir_str));
+    for (QStringList::const_iterator it = config_dir_list.constBegin(); it != config_dir_list.constEnd(); ++it) {
+        const auto filename = it->toStdString();
+        if (filename.find_first_not_of("0123456789abcdefACBDEF", 0) < 16) {
+            continue;
+        }
+        const auto origin = fmt::format("{}{}", config_dir_str, filename);
+        const auto destination = fmt::format("{}custom" DIR_SEP "{}", config_dir_str, filename);
+        LOG_INFO(Frontend, "Migrating config file from {} to {}", origin, destination);
+        if (!Common::FS::Rename(origin, destination)) {
+            // Delete the old config file if one already exists in the new location.
+            Common::FS::Delete(origin);
+        }
+    }
+}
+
 void GMainWindow::UpdateWindowTitle(const std::string& title_name,
                                     const std::string& title_version) {
     const auto full_name = std::string(Common::g_build_fullname);
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index afcfa68a9..b380a66f3 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -251,6 +251,7 @@ private:
     std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
     InstallResult InstallNSPXCI(const QString& filename);
     InstallResult InstallNCA(const QString& filename);
+    void MigrateConfigFiles();
     void UpdateWindowTitle(const std::string& title_name = {},
                            const std::string& title_version = {});
     void UpdateStatusBar();

From 8ead176639be482fb26c2eb3f95fc942e52efee0 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Mon, 28 Sep 2020 04:53:21 -0400
Subject: [PATCH 08/37] udp/client: Reduce testing period to 5 seconds

---
 src/input_common/udp/client.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 7039d6fc3..3677e79ca 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -344,7 +344,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
         };
         Socket socket{host, port, pad_index, client_id, std::move(callback)};
         std::thread worker_thread{SocketLoop, &socket};
-        const bool result = success_event.WaitFor(std::chrono::seconds(8));
+        const bool result = success_event.WaitFor(std::chrono::seconds(5));
         socket.Stop();
         worker_thread.join();
         if (result) {

From 8f2959f6804e0d1048ecaa6f4046622e069fe7db Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Mon, 28 Sep 2020 10:00:15 -0400
Subject: [PATCH 09/37] settings: Preparation for per-game input settings

---
 src/core/frontend/applets/controller.cpp      |  4 +-
 src/core/frontend/framebuffer_layout.cpp      |  2 +-
 src/core/hle/service/am/am.cpp                |  4 +-
 .../hle/service/am/applets/controller.cpp     |  2 +-
 src/core/hle/service/apm/controller.cpp       |  3 +-
 src/core/hle/service/hid/controllers/npad.cpp | 42 ++++++++------
 src/core/hle/service/hid/hid.cpp              |  4 +-
 src/core/hle/service/vi/vi.cpp                |  2 +-
 src/core/settings.cpp                         |  8 ++-
 src/core/settings.h                           | 57 +++++++++++++++----
 src/core/telemetry_session.cpp                |  2 +-
 src/yuzu/applets/controller.cpp               | 30 +++++-----
 src/yuzu/configuration/config.cpp             | 24 ++++----
 src/yuzu/configuration/configure_input.cpp    | 24 ++++----
 .../configure_input_advanced.cpp              |  4 +-
 .../configuration/configure_input_player.cpp  |  8 +--
 src/yuzu/main.cpp                             | 23 ++++----
 src/yuzu_cmd/config.cpp                       | 25 ++++----
 src/yuzu_tester/config.cpp                    | 14 ++---
 19 files changed, 167 insertions(+), 115 deletions(-)

diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index 5582091f4..1ac2fb80c 100644
--- a/src/core/frontend/applets/controller.cpp
+++ b/src/core/frontend/applets/controller.cpp
@@ -27,7 +27,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
             ->GetAppletResource()
             ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
 
-    auto& players = Settings::values.players;
+    auto& players = Settings::values.players.GetValue();
 
     const std::size_t min_supported_players =
         parameters.enable_single_mode ? 1 : parameters.min_players;
@@ -66,7 +66,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
                     npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index);
             }
         } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
-                   !Settings::values.use_docked_mode) {
+                   !Settings::values.use_docked_mode.GetValue()) {
             // We should *never* reach here under any normal circumstances.
             npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld),
                                     index);
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index 1acc82497..b9a270a55 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -47,7 +47,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
 FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
     u32 width, height;
 
-    if (Settings::values.use_docked_mode) {
+    if (Settings::values.use_docked_mode.GetValue()) {
         width = ScreenDocked::Width * res_scale;
         height = ScreenDocked::Height * res_scale;
     } else {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 2ce742e35..eb097738a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -751,7 +751,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
     IPC::ResponseBuilder rb{ctx, 4};
     rb.Push(RESULT_SUCCESS);
 
-    if (Settings::values.use_docked_mode) {
+    if (Settings::values.use_docked_mode.GetValue()) {
         rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
                 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
         rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
@@ -824,7 +824,7 @@ void IStorage::Open(Kernel::HLERequestContext& ctx) {
 }
 
 void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
-    const bool use_docked_mode{Settings::values.use_docked_mode};
+    const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()};
     LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
 
     IPC::ResponseBuilder rb{ctx, 3};
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
index a0152b4ea..43b79412e 100644
--- a/src/core/hle/service/am/applets/controller.cpp
+++ b/src/core/hle/service/am/applets/controller.cpp
@@ -222,7 +222,7 @@ void Controller::Execute() {
 void Controller::ConfigurationComplete() {
     ControllerSupportResultInfo result_info{};
 
-    const auto& players = Settings::values.players;
+    const auto& players = Settings::values.players.GetValue();
 
     // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
     // Otherwise, only count connected players from P1-P8.
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp
index 25a886238..ce993bad3 100644
--- a/src/core/hle/service/apm/controller.cpp
+++ b/src/core/hle/service/apm/controller.cpp
@@ -69,7 +69,8 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
 }
 
 PerformanceMode Controller::GetCurrentPerformanceMode() const {
-    return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld;
+    return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked
+                                                       : PerformanceMode::Handheld;
 }
 
 PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index c4b26196a..15d5fa6e8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -184,11 +184,14 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
     controller.single_color.button_color = 0;
 
     controller.dual_color_error = ColorReadError::ReadOk;
-    controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left;
-    controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left;
-    controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right;
+    controller.left_color.body_color =
+        Settings::values.players.GetValue()[controller_idx].body_color_left;
+    controller.left_color.button_color =
+        Settings::values.players.GetValue()[controller_idx].button_color_left;
+    controller.right_color.body_color =
+        Settings::values.players.GetValue()[controller_idx].body_color_right;
     controller.right_color.button_color =
-        Settings::values.players[controller_idx].button_color_right;
+        Settings::values.players.GetValue()[controller_idx].button_color_right;
 
     controller.battery_level[0] = BATTERY_FULL;
     controller.battery_level[1] = BATTERY_FULL;
@@ -218,8 +221,9 @@ void Controller_NPad::OnInit() {
         style.pokeball.Assign(1);
     }
 
-    std::transform(Settings::values.players.begin(), Settings::values.players.end(),
-                   connected_controllers.begin(), [](const Settings::PlayerInput& player) {
+    std::transform(Settings::values.players.GetValue().begin(),
+                   Settings::values.players.GetValue().end(), connected_controllers.begin(),
+                   [](const Settings::PlayerInput& player) {
                        return ControllerHolder{MapSettingsTypeToNPad(player.controller_type),
                                                player.connected};
                    });
@@ -227,12 +231,13 @@ void Controller_NPad::OnInit() {
     // Connect the Player 1 or Handheld controller if none are connected.
     if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
                      [](const ControllerHolder& controller) { return controller.is_connected; })) {
-        const auto controller = MapSettingsTypeToNPad(Settings::values.players[0].controller_type);
+        const auto controller =
+            MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type);
         if (controller == NPadControllerType::Handheld) {
-            Settings::values.players[HANDHELD_INDEX].connected = true;
+            Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
             connected_controllers[HANDHELD_INDEX] = {controller, true};
         } else {
-            Settings::values.players[0].connected = true;
+            Settings::values.players.GetValue()[0].connected = true;
             connected_controllers[0] = {controller, true};
         }
     }
@@ -255,7 +260,7 @@ void Controller_NPad::OnInit() {
 }
 
 void Controller_NPad::OnLoadInputDevices() {
-    const auto& players = Settings::values.players;
+    const auto& players = Settings::values.players.GetValue();
     for (std::size_t i = 0; i < players.size(); ++i) {
         std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
                        players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
@@ -528,7 +533,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
         // Try to read sixaxis sensor states
         std::array<MotionDevice, 2> motion_devices;
 
-        if (sixaxis_sensors_enabled && Settings::values.motion_enabled) {
+        if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) {
             sixaxis_at_rest = true;
             for (std::size_t e = 0; e < motion_devices.size(); ++e) {
                 const auto& device = motions[i][e];
@@ -666,7 +671,7 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controllers,
                                         const std::vector<Vibration>& vibrations) {
     LOG_TRACE(Service_HID, "called");
 
-    if (!Settings::values.vibration_enabled || !can_controllers_vibrate) {
+    if (!Settings::values.vibration_enabled.GetValue() || !can_controllers_vibrate) {
         return;
     }
     bool success = true;
@@ -714,16 +719,17 @@ void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::siz
     }
 
     if (controller == NPadControllerType::Handheld) {
-        Settings::values.players[HANDHELD_INDEX].controller_type =
+        Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type =
             MapNPadToSettingsType(controller);
-        Settings::values.players[HANDHELD_INDEX].connected = true;
+        Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
         connected_controllers[HANDHELD_INDEX] = {controller, true};
         InitNewlyAddedController(HANDHELD_INDEX);
         return;
     }
 
-    Settings::values.players[npad_index].controller_type = MapNPadToSettingsType(controller);
-    Settings::values.players[npad_index].connected = true;
+    Settings::values.players.GetValue()[npad_index].controller_type =
+        MapNPadToSettingsType(controller);
+    Settings::values.players.GetValue()[npad_index].connected = true;
     connected_controllers[npad_index] = {controller, true};
     InitNewlyAddedController(npad_index);
 }
@@ -733,7 +739,7 @@ void Controller_NPad::DisconnectNPad(u32 npad_id) {
 }
 
 void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) {
-    Settings::values.players[npad_index].connected = false;
+    Settings::values.players.GetValue()[npad_index].connected = false;
     connected_controllers[npad_index].is_connected = false;
 
     auto& controller = shared_memory_entries[npad_index];
@@ -895,7 +901,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
             return false;
         }
         // Handheld should not be supported in docked mode
-        if (Settings::values.use_docked_mode) {
+        if (Settings::values.use_docked_mode.GetValue()) {
             return false;
         }
 
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 50f709b25..fb57dec02 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -935,7 +935,7 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
 void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto can_vibrate{rp.Pop<bool>()};
-    Settings::values.vibration_enabled = can_vibrate;
+    Settings::values.vibration_enabled.SetValue(can_vibrate);
 
     LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
 
@@ -948,7 +948,7 @@ void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
-    rb.Push(Settings::values.vibration_enabled);
+    rb.Push(Settings::values.vibration_enabled.GetValue());
 }
 
 void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 5b0e371fe..55e00dd93 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -771,7 +771,7 @@ private:
         IPC::ResponseBuilder rb{ctx, 6};
         rb.Push(RESULT_SUCCESS);
 
-        if (Settings::values.use_docked_mode) {
+        if (Settings::values.use_docked_mode.GetValue()) {
             rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
                     static_cast<u32>(Settings::values.resolution_factor.GetValue()));
             rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 0587b9374..aadbc3932 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -49,7 +49,7 @@ void LogSettings() {
     };
 
     LOG_INFO(Config, "yuzu Configuration:");
-    log_setting("Controls_UseDockedMode", values.use_docked_mode);
+    log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
     log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
     log_setting("System_CurrentUser", values.current_user);
     log_setting("System_LanguageIndex", values.language_index.GetValue());
@@ -145,6 +145,12 @@ void RestoreGlobalState() {
     values.rng_seed.SetGlobal(true);
     values.custom_rtc.SetGlobal(true);
     values.sound_index.SetGlobal(true);
+
+    // Controls
+    values.players.SetGlobal(true);
+    values.use_docked_mode.SetGlobal(true);
+    values.vibration_enabled.SetGlobal(true);
+    values.motion_enabled.SetGlobal(true);
 }
 
 void Sanitize() {
diff --git a/src/core/settings.h b/src/core/settings.h
index 28616a574..edd2a00ca 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -65,6 +65,38 @@ private:
     Type local{};
 };
 
+/**
+ * The InputSetting class allows for getting a reference to either the global or local members.
+ * This is required as we cannot easily modify the values of user-defined types within containers
+ * using the SetValue() member function found in the Setting class. The primary purpose of this
+ * class is to store an array of 10 PlayerInput structs for both the global and local (per-game)
+ * setting and allows for easily accessing and modifying both settings.
+ */
+template <typename Type>
+class InputSetting final {
+public:
+    InputSetting() = default;
+    explicit InputSetting(Type val) : global{val} {}
+    ~InputSetting() = default;
+    void SetGlobal(bool to_global) {
+        use_global = to_global;
+    }
+    bool UsingGlobal() const {
+        return use_global;
+    }
+    Type& GetValue(bool need_global = false) {
+        if (use_global || need_global) {
+            return global;
+        }
+        return local;
+    }
+
+private:
+    bool use_global = true;
+    Type global{};
+    Type local{};
+};
+
 struct TouchFromButtonMap {
     std::string name;
     std::vector<std::string> buttons;
@@ -133,9 +165,17 @@ struct Values {
     Setting<s32> sound_index;
 
     // Controls
-    std::array<PlayerInput, 10> players;
+    InputSetting<std::array<PlayerInput, 10>> players;
 
-    bool use_docked_mode;
+    Setting<bool> use_docked_mode;
+
+    Setting<bool> vibration_enabled;
+
+    Setting<bool> motion_enabled;
+    std::string motion_device;
+    std::string udp_input_address;
+    u16 udp_input_port;
+    u8 udp_pad_index;
 
     bool mouse_enabled;
     std::string mouse_device;
@@ -149,20 +189,15 @@ struct Values {
     ButtonsRaw debug_pad_buttons;
     AnalogsRaw debug_pad_analogs;
 
-    bool vibration_enabled;
-
-    bool motion_enabled;
-    std::string motion_device;
-    std::string touch_device;
     TouchscreenInput touchscreen;
-    std::atomic_bool is_device_reload_pending{true};
+
     bool use_touch_from_button;
+    std::string touch_device;
     int touch_from_button_map_index;
-    std::string udp_input_address;
-    u16 udp_input_port;
-    u8 udp_pad_index;
     std::vector<TouchFromButtonMap> touch_from_button_maps;
 
+    std::atomic_bool is_device_reload_pending{true};
+
     // Data Storage
     bool use_virtual_sd;
     bool gamecard_inserted;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index ebc19e18a..e0908186b 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -213,7 +213,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
              Settings::values.use_assembly_shaders.GetValue());
     AddField(field_type, "Renderer_UseAsynchronousShaders",
              Settings::values.use_asynchronous_shaders.GetValue());
-    AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode);
+    AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode.GetValue());
 }
 
 bool TelemetrySession::SubmitTestcase() {
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index ee770f315..7697fe434 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -261,26 +261,26 @@ void QtControllerSelectorDialog::ApplyConfiguration() {
         UpdateControllerState(index);
     }
 
-    const bool pre_docked_mode = Settings::values.use_docked_mode;
-    Settings::values.use_docked_mode = ui->radioDocked->isChecked();
-    OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
+    const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
+    Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked());
+    OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue());
 
-    Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
+    Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
 }
 
 void QtControllerSelectorDialog::LoadConfiguration() {
     for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
-        const auto connected = Settings::values.players[index].connected ||
-                               (index == 0 && Settings::values.players[8].connected);
+        const auto connected = Settings::values.players.GetValue()[index].connected ||
+                               (index == 0 && Settings::values.players.GetValue()[8].connected);
         player_groupboxes[index]->setChecked(connected);
         connected_controller_checkboxes[index]->setChecked(connected);
         emulated_controllers[index]->setCurrentIndex(
-            GetIndexFromControllerType(Settings::values.players[index].controller_type));
+            GetIndexFromControllerType(Settings::values.players.GetValue()[index].controller_type));
     }
 
-    UpdateDockedState(Settings::values.players[8].connected);
+    UpdateDockedState(Settings::values.players.GetValue()[8].connected);
 
-    ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
+    ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
 }
 
 void QtControllerSelectorDialog::CallConfigureInputDialog() {
@@ -448,7 +448,7 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
 }
 
 void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
-    auto& player = Settings::values.players[player_index];
+    auto& player = Settings::values.players.GetValue()[player_index];
 
     player.controller_type =
         GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex());
@@ -461,7 +461,7 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index)
     }
 
     // Player 1 and Handheld
-    auto& handheld = Settings::values.players[8];
+    auto& handheld = Settings::values.players.GetValue()[8];
     // If Handheld is selected, copy all the settings from Player 1 to Handheld.
     if (player.controller_type == Settings::ControllerType::Handheld) {
         handheld = player;
@@ -527,8 +527,8 @@ void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) {
     ui->radioDocked->setEnabled(!is_handheld);
     ui->radioUndocked->setEnabled(!is_handheld);
 
-    ui->radioDocked->setChecked(Settings::values.use_docked_mode);
-    ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
+    ui->radioDocked->setChecked(Settings::values.use_docked_mode.GetValue());
+    ui->radioUndocked->setChecked(!Settings::values.use_docked_mode.GetValue());
 
     // Also force into undocked mode if the controller type is handheld.
     if (is_handheld) {
@@ -571,8 +571,8 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
 
     for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) {
         // Disconnect any unsupported players here and disable or hide them if applicable.
-        Settings::values.players[index].connected = false;
-        UpdateController(Settings::values.players[index].controller_type, index, false);
+        Settings::values.players.GetValue()[index].connected = false;
+        UpdateController(Settings::values.players.GetValue()[index].controller_type, index, false);
         // Hide the player widgets when max_supported_controllers is less than or equal to 4.
         if (max_supported_players <= 4) {
             player_widgets[index]->hide();
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 618f991b0..296c58f58 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -276,7 +276,7 @@ void Config::ReadPlayerValue(std::size_t player_index) {
         }
     }();
 
-    auto& player = Settings::values.players[player_index];
+    auto& player = Settings::values.players.GetValue()[player_index];
 
     if (player_prefix.isEmpty()) {
         const auto controller = static_cast<Settings::ControllerType>(
@@ -481,7 +481,7 @@ void Config::ReadAudioValues() {
 void Config::ReadControlValues() {
     qt_config->beginGroup(QStringLiteral("Controls"));
 
-    for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
+    for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
         ReadPlayerValue(p);
     }
     ReadDebugValues();
@@ -490,11 +490,10 @@ void Config::ReadControlValues() {
     ReadTouchscreenValues();
     ReadMotionTouchValues();
 
-    Settings::values.vibration_enabled =
-        ReadSetting(QStringLiteral("vibration_enabled"), true).toBool();
-    Settings::values.motion_enabled = ReadSetting(QStringLiteral("motion_enabled"), true).toBool();
-    Settings::values.use_docked_mode =
-        ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
+    ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), false);
+    ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"),
+                      true);
+    ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"), true);
 
     qt_config->endGroup();
 }
@@ -976,7 +975,7 @@ void Config::SavePlayerValue(std::size_t player_index) {
         }
     }();
 
-    const auto& player = Settings::values.players[player_index];
+    const auto& player = Settings::values.players.GetValue()[player_index];
 
     WriteSetting(QStringLiteral("%1type").arg(player_prefix),
                  static_cast<u8>(player.controller_type),
@@ -1140,7 +1139,7 @@ void Config::SaveAudioValues() {
 void Config::SaveControlValues() {
     qt_config->beginGroup(QStringLiteral("Controls"));
 
-    for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
+    for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
         SavePlayerValue(p);
     }
     SaveDebugValues();
@@ -1148,8 +1147,10 @@ void Config::SaveControlValues() {
     SaveTouchscreenValues();
     SaveMotionTouchValues();
 
-    WriteSetting(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true);
-    WriteSetting(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true);
+    WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
+    WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled,
+                       true);
+    WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true);
     WriteSetting(QStringLiteral("motion_device"),
                  QString::fromStdString(Settings::values.motion_device),
                  QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
@@ -1157,7 +1158,6 @@ void Config::SaveControlValues() {
                  QString::fromStdString(Settings::values.touch_device),
                  QStringLiteral("engine:emu_window"));
     WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
-    WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
 
     qt_config->endGroup();
 }
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 523ece426..9a4de4c5d 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -181,12 +181,12 @@ void ConfigureInput::ApplyConfiguration() {
 
     advanced->ApplyConfiguration();
 
-    const bool pre_docked_mode = Settings::values.use_docked_mode;
-    Settings::values.use_docked_mode = ui->radioDocked->isChecked();
-    OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
+    const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
+    Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked());
+    OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue());
 
-    Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
-    Settings::values.motion_enabled = ui->motionGroup->isChecked();
+    Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
+    Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
 }
 
 void ConfigureInput::changeEvent(QEvent* event) {
@@ -203,16 +203,16 @@ void ConfigureInput::RetranslateUI() {
 
 void ConfigureInput::LoadConfiguration() {
     LoadPlayerControllerIndices();
-    UpdateDockedState(Settings::values.players[8].connected);
+    UpdateDockedState(Settings::values.players.GetValue()[8].connected);
 
-    ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
-    ui->motionGroup->setChecked(Settings::values.motion_enabled);
+    ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
+    ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
 }
 
 void ConfigureInput::LoadPlayerControllerIndices() {
     for (std::size_t i = 0; i < player_connected.size(); ++i) {
-        const auto connected = Settings::values.players[i].connected ||
-                               (i == 0 && Settings::values.players[8].connected);
+        const auto connected = Settings::values.players.GetValue()[i].connected ||
+                               (i == 0 && Settings::values.players.GetValue()[8].connected);
         player_connected[i]->setChecked(connected);
     }
 }
@@ -241,8 +241,8 @@ void ConfigureInput::UpdateDockedState(bool is_handheld) {
     ui->radioDocked->setEnabled(!is_handheld);
     ui->radioUndocked->setEnabled(!is_handheld);
 
-    ui->radioDocked->setChecked(Settings::values.use_docked_mode);
-    ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
+    ui->radioDocked->setChecked(Settings::values.use_docked_mode.GetValue());
+    ui->radioUndocked->setChecked(!Settings::values.use_docked_mode.GetValue());
 
     // Also force into undocked mode if the controller type is handheld.
     if (is_handheld) {
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index 3715db0ab..3074be833 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -107,7 +107,7 @@ void ConfigureInputAdvanced::OnControllerButtonClick(int player_idx, int button_
 
 void ConfigureInputAdvanced::ApplyConfiguration() {
     for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
-        auto& player = Settings::values.players[player_idx];
+        auto& player = Settings::values.players.GetValue()[player_idx];
         std::array<u32, 4> colors{};
         std::transform(controllers_colors[player_idx].begin(), controllers_colors[player_idx].end(),
                        colors.begin(), [](QColor color) { return color.rgb(); });
@@ -126,7 +126,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
 
 void ConfigureInputAdvanced::LoadConfiguration() {
     for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
-        auto& player = Settings::values.players[player_idx];
+        auto& player = Settings::values.players.GetValue()[player_idx];
         std::array<u32, 4> colors = {
             player.body_color_left,
             player.button_color_left,
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index b4de2f6af..213a76224 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -544,7 +544,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
 ConfigureInputPlayer::~ConfigureInputPlayer() = default;
 
 void ConfigureInputPlayer::ApplyConfiguration() {
-    auto& player = Settings::values.players[player_index];
+    auto& player = Settings::values.players.GetValue()[player_index];
     auto& buttons = debug ? Settings::values.debug_pad_buttons : player.buttons;
     auto& analogs = debug ? Settings::values.debug_pad_analogs : player.analogs;
 
@@ -572,7 +572,7 @@ void ConfigureInputPlayer::ApplyConfiguration() {
     }
 
     // Player 1 and Handheld
-    auto& handheld = Settings::values.players[HANDHELD_INDEX];
+    auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX];
     // If Handheld is selected, copy all the settings from Player 1 to Handheld.
     if (player.controller_type == Settings::ControllerType::Handheld) {
         handheld = player;
@@ -609,7 +609,7 @@ void ConfigureInputPlayer::RetranslateUI() {
 }
 
 void ConfigureInputPlayer::LoadConfiguration() {
-    auto& player = Settings::values.players[player_index];
+    auto& player = Settings::values.players.GetValue()[player_index];
     if (debug) {
         std::transform(Settings::values.debug_pad_buttons.begin(),
                        Settings::values.debug_pad_buttons.end(), buttons_param.begin(),
@@ -636,7 +636,7 @@ void ConfigureInputPlayer::LoadConfiguration() {
     ui->comboControllerType->setCurrentIndex(static_cast<int>(player.controller_type));
     ui->groupConnectedController->setChecked(
         player.connected ||
-        (player_index == 0 && Settings::values.players[HANDHELD_INDEX].connected));
+        (player_index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected));
 }
 
 void ConfigureInputPlayer::ConnectPlayer(bool connected) {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 4a3dea2a5..54a46827f 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -551,13 +551,14 @@ void GMainWindow::InitializeWidgets() {
     dock_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
     dock_status_button->setFocusPolicy(Qt::NoFocus);
     connect(dock_status_button, &QPushButton::clicked, [&] {
-        Settings::values.use_docked_mode = !Settings::values.use_docked_mode;
-        dock_status_button->setChecked(Settings::values.use_docked_mode);
-        OnDockedModeChanged(!Settings::values.use_docked_mode, Settings::values.use_docked_mode);
+        Settings::values.use_docked_mode.SetValue(!Settings::values.use_docked_mode.GetValue());
+        dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
+        OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
+                            Settings::values.use_docked_mode.GetValue());
     });
     dock_status_button->setText(tr("DOCK"));
     dock_status_button->setCheckable(true);
-    dock_status_button->setChecked(Settings::values.use_docked_mode);
+    dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
     statusBar()->insertPermanentWidget(0, dock_status_button);
 
     // Setup ASync button
@@ -796,10 +797,11 @@ void GMainWindow::InitializeHotkeys() {
             });
     connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Change Docked Mode"), this),
             &QShortcut::activated, this, [&] {
-                Settings::values.use_docked_mode = !Settings::values.use_docked_mode;
-                OnDockedModeChanged(!Settings::values.use_docked_mode,
-                                    Settings::values.use_docked_mode);
-                dock_status_button->setChecked(Settings::values.use_docked_mode);
+                Settings::values.use_docked_mode.SetValue(
+                    !Settings::values.use_docked_mode.GetValue());
+                OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
+                                    Settings::values.use_docked_mode.GetValue());
+                dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
             });
     connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
             &QShortcut::activated, this,
@@ -2405,7 +2407,8 @@ void GMainWindow::MigrateConfigFiles() {
     const QStringList config_dir_list = config_dir.entryList(QStringList(QStringLiteral("*.ini")));
 
     Common::FS::CreateFullPath(fmt::format("{}custom" DIR_SEP, config_dir_str));
-    for (QStringList::const_iterator it = config_dir_list.constBegin(); it != config_dir_list.constEnd(); ++it) {
+    for (QStringList::const_iterator it = config_dir_list.constBegin();
+         it != config_dir_list.constEnd(); ++it) {
         const auto filename = it->toStdString();
         if (filename.find_first_not_of("0123456789abcdefACBDEF", 0) < 16) {
             continue;
@@ -2477,7 +2480,7 @@ void GMainWindow::UpdateStatusBar() {
 }
 
 void GMainWindow::UpdateStatusButtons() {
-    dock_status_button->setChecked(Settings::values.use_docked_mode);
+    dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
     multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
     Settings::values.use_asynchronous_gpu_emulation.SetValue(
         Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 334038ef9..feee02fcd 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -228,24 +228,24 @@ static const std::array<int, 8> keyboard_mods{
 
 void Config::ReadValues() {
     // Controls
-    for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
+    for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
         const auto group = fmt::format("ControlsP{}", p);
         for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
             std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
-            Settings::values.players[p].buttons[i] =
+            Settings::values.players.GetValue()[p].buttons[i] =
                 sdl2_config->Get(group, Settings::NativeButton::mapping[i], default_param);
-            if (Settings::values.players[p].buttons[i].empty())
-                Settings::values.players[p].buttons[i] = default_param;
+            if (Settings::values.players.GetValue()[p].buttons[i].empty())
+                Settings::values.players.GetValue()[p].buttons[i] = default_param;
         }
 
         for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
             std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
                 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
                 default_analogs[i][3], default_analogs[i][4], 0.5f);
-            Settings::values.players[p].analogs[i] =
+            Settings::values.players.GetValue()[p].analogs[i] =
                 sdl2_config->Get(group, Settings::NativeAnalog::mapping[i], default_param);
-            if (Settings::values.players[p].analogs[i].empty())
-                Settings::values.players[p].analogs[i] = default_param;
+            if (Settings::values.players.GetValue()[p].analogs[i].empty())
+                Settings::values.players.GetValue()[p].analogs[i] = default_param;
         }
     }
 
@@ -288,10 +288,10 @@ void Config::ReadValues() {
             Settings::values.debug_pad_analogs[i] = default_param;
     }
 
-    Settings::values.vibration_enabled =
-        sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true);
-    Settings::values.motion_enabled =
-        sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true);
+    Settings::values.vibration_enabled.SetValue(
+        sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true));
+    Settings::values.motion_enabled.SetValue(
+        sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true));
     Settings::values.touchscreen.enabled =
         sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
     Settings::values.touchscreen.device =
@@ -343,7 +343,8 @@ void Config::ReadValues() {
     Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
 
     // System
-    Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
+    Settings::values.use_docked_mode.SetValue(
+        sdl2_config->GetBoolean("System", "use_docked_mode", false));
     const auto size = sdl2_config->GetInteger("System", "users_size", 0);
 
     Settings::values.current_user = std::clamp<int>(
diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp
index bc273fb51..3a8a333f0 100644
--- a/src/yuzu_tester/config.cpp
+++ b/src/yuzu_tester/config.cpp
@@ -47,13 +47,13 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) {
 
 void Config::ReadValues() {
     // Controls
-    for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
+    for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
         for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
-            Settings::values.players[p].buttons[i] = "";
+            Settings::values.players.GetValue()[p].buttons[i] = "";
         }
 
         for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
-            Settings::values.players[p].analogs[i] = "";
+            Settings::values.players.GetValue()[p].analogs[i] = "";
         }
     }
 
@@ -75,8 +75,8 @@ void Config::ReadValues() {
         Settings::values.debug_pad_analogs[i] = "";
     }
 
-    Settings::values.vibration_enabled = true;
-    Settings::values.motion_enabled = true;
+    Settings::values.vibration_enabled.SetValue(true);
+    Settings::values.motion_enabled.SetValue(true);
     Settings::values.touchscreen.enabled = "";
     Settings::values.touchscreen.device = "";
     Settings::values.touchscreen.finger = 0;
@@ -84,8 +84,8 @@ void Config::ReadValues() {
     Settings::values.touchscreen.diameter_x = 15;
     Settings::values.touchscreen.diameter_y = 15;
 
-    Settings::values.use_docked_mode =
-        sdl2_config->GetBoolean("Controls", "use_docked_mode", false);
+    Settings::values.use_docked_mode.SetValue(
+        sdl2_config->GetBoolean("Controls", "use_docked_mode", false));
 
     // Data Storage
     Settings::values.use_virtual_sd =

From ceb7b11f166a4e59945a6296d364980c37ca681e Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Mon, 28 Sep 2020 10:27:29 -0400
Subject: [PATCH 10/37] configure_input_player: Change "Defaults" button
 behavior

RestoreDefaults() now restores the selected devices' mappings using UpdateMappingWithDefaults().
This allows us to move the keyboard mapping from RestoreDefaults() to UpdateMappingWithDefaults().
---
 src/input_common/main.cpp                     |  8 ---
 .../configuration/configure_input_player.cpp  | 57 ++++++++++---------
 2 files changed, 30 insertions(+), 35 deletions(-)

diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 354c734fe..b438482cc 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -96,10 +96,6 @@ struct InputSubsystem::Impl {
         if (!params.Has("class") || params.Get("class", "") == "any") {
             return {};
         }
-        if (params.Get("class", "") == "keyboard") {
-            // TODO consider returning the SDL key codes for the default keybindings
-            return {};
-        }
         if (params.Get("class", "") == "gcpad") {
             return gcadapter->GetAnalogMappingForDevice(params);
         }
@@ -116,10 +112,6 @@ struct InputSubsystem::Impl {
         if (!params.Has("class") || params.Get("class", "") == "any") {
             return {};
         }
-        if (params.Get("class", "") == "keyboard") {
-            // TODO consider returning the SDL key codes for the default keybindings
-            return {};
-        }
         if (params.Get("class", "") == "gcpad") {
             return gcadapter->GetButtonMappingForDevice(params);
         }
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 213a76224..460ff08a4 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -693,32 +693,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() {
 }
 
 void ConfigureInputPlayer::RestoreDefaults() {
-    // Reset Buttons
-    for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
-        buttons_param[button_id] = Common::ParamPackage{
-            InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
-    }
-
-    // Reset Analogs and Modifier Buttons
-    for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
-        for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
-            Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
-                Config::default_analogs[analog_id][sub_button_id])};
-            SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
-        }
-
-        analogs_param[analog_id].Set(
-            "modifier", InputCommon::GenerateKeyboardParam(Config::default_stick_mod[analog_id]));
-    }
-
-    for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
-        motions_param[motion_id] = Common::ParamPackage{
-            InputCommon::GenerateKeyboardParam(Config::default_motions[motion_id])};
-    }
-
-    UpdateUI();
-    UpdateInputDeviceCombobox();
-    ui->comboControllerType->setCurrentIndex(0);
+    UpdateMappingWithDefaults();
 }
 
 void ConfigureInputPlayer::ClearAll() {
@@ -951,9 +926,37 @@ void ConfigureInputPlayer::UpdateMotionButtons() {
 }
 
 void ConfigureInputPlayer::UpdateMappingWithDefaults() {
-    if (ui->comboDevices->currentIndex() < 2) {
+    if (ui->comboDevices->currentIndex() == 0) {
         return;
     }
+
+    if (ui->comboDevices->currentIndex() == 1) {
+        // Reset keyboard bindings
+        for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
+            buttons_param[button_id] = Common::ParamPackage{
+                InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
+        }
+        for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
+            for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
+                Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
+                    Config::default_analogs[analog_id][sub_button_id])};
+                SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
+            }
+
+            analogs_param[analog_id].Set("modifier", InputCommon::GenerateKeyboardParam(
+                                                         Config::default_stick_mod[analog_id]));
+        }
+
+        for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
+            motions_param[motion_id] = Common::ParamPackage{
+                InputCommon::GenerateKeyboardParam(Config::default_motions[motion_id])};
+        }
+
+        UpdateUI();
+        return;
+    }
+
+    // Reset controller bindings
     const auto& device = input_devices[ui->comboDevices->currentIndex()];
     auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
     auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);

From 0a966e2cac40477ffc62f747f7703afbf3bfda2a Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Tue, 6 Oct 2020 04:35:07 -0400
Subject: [PATCH 11/37] controllers/npad: Add DeviceHandle struct

A DeviceHandle describes a vibration device or six-axis sensor based on the npad type, npad id, and device index/position
---
 src/core/hle/service/hid/controllers/npad.h | 87 +++++++++++++--------
 1 file changed, 55 insertions(+), 32 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index fd5c5a6eb..8dabae6e3 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -39,6 +39,61 @@ public:
     // Called when input devices should be loaded
     void OnLoadInputDevices() override;
 
+    enum class NPadControllerType {
+        None,
+        ProController,
+        Handheld,
+        JoyDual,
+        JoyLeft,
+        JoyRight,
+        Pokeball,
+    };
+
+    enum class NpadType : u8 {
+        ProController = 3,
+        Handheld = 4,
+        JoyconDual = 5,
+        JoyconLeft = 6,
+        JoyconRight = 7,
+        Pokeball = 9,
+    };
+
+    enum class DeviceIndex : u8 {
+        Left = 0,
+        Right = 1,
+        None = 2,
+    };
+
+    enum class GyroscopeZeroDriftMode : u32 {
+        Loose = 0,
+        Standard = 1,
+        Tight = 2,
+    };
+
+    enum class NpadHoldType : u64 {
+        Vertical = 0,
+        Horizontal = 1,
+    };
+
+    enum class NPadAssignments : u32 {
+        Dual = 0,
+        Single = 1,
+    };
+
+    enum class NpadHandheldActivationMode : u64 {
+        Dual = 0,
+        Single = 1,
+        None = 2,
+    };
+
+    struct DeviceHandle {
+        NpadType npad_type{};
+        u8 npad_id{};
+        DeviceIndex device_index{};
+        INSERT_PADDING_BYTES(1);
+    };
+    static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size");
+
     struct NPadType {
         union {
             u32_le raw{};
@@ -62,38 +117,6 @@ public:
     };
     static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size");
 
-    enum class GyroscopeZeroDriftMode : u32 {
-        Loose = 0,
-        Standard = 1,
-        Tight = 2,
-    };
-
-    enum class NpadHoldType : u64 {
-        Vertical = 0,
-        Horizontal = 1,
-    };
-
-    enum class NPadAssignments : u32_le {
-        Dual = 0,
-        Single = 1,
-    };
-
-    enum class NpadHandheldActivationMode : u64 {
-        Dual = 0,
-        Single = 1,
-        None = 2,
-    };
-
-    enum class NPadControllerType {
-        None,
-        ProController,
-        Handheld,
-        JoyDual,
-        JoyLeft,
-        JoyRight,
-        Pokeball,
-    };
-
     struct LedPattern {
         explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
             position1.Assign(light1);

From 428ce8ec2909100fb8dde520254508a274c448ea Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Thu, 8 Oct 2020 01:08:37 -0400
Subject: [PATCH 12/37] controllers/npad: Rename NPadType to NpadStyleSet

This more accurately represents the underlying type and avoids confusion with NpadType
---
 src/core/hle/service/am/applets/controller.cpp |  2 +-
 src/core/hle/service/hid/controllers/npad.cpp  |  4 ++--
 src/core/hle/service/hid/controllers/npad.h    | 12 ++++++------
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
index 43b79412e..3ca63f020 100644
--- a/src/core/hle/service/am/applets/controller.cpp
+++ b/src/core/hle/service/am/applets/controller.cpp
@@ -25,7 +25,7 @@ namespace Service::AM::Applets {
 static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
     ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
     std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
-    HID::Controller_NPad::NPadType npad_style_set;
+    HID::Controller_NPad::NpadStyleSet npad_style_set;
     npad_style_set.raw = private_arg.style_set;
 
     return {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 15d5fa6e8..8181bddbc 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -619,11 +619,11 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
                 shared_memory_entries.size() * sizeof(NPadEntry));
 }
 
-void Controller_NPad::SetSupportedStyleSet(NPadType style_set) {
+void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) {
     style.raw = style_set.raw;
 }
 
-Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const {
+Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const {
     return style;
 }
 
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 8dabae6e3..fed8425b1 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -94,7 +94,7 @@ public:
     };
     static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size");
 
-    struct NPadType {
+    struct NpadStyleSet {
         union {
             u32_le raw{};
 
@@ -107,7 +107,7 @@ public:
             BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible
         };
     };
-    static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size");
+    static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
 
     struct Vibration {
         f32 amp_low;
@@ -133,8 +133,8 @@ public:
         };
     };
 
-    void SetSupportedStyleSet(NPadType style_set);
-    NPadType GetSupportedStyleSet() const;
+    void SetSupportedStyleSet(NpadStyleSet style_set);
+    NpadStyleSet GetSupportedStyleSet() const;
 
     void SetSupportedNPadIdTypes(u8* data, std::size_t length);
     void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
@@ -347,7 +347,7 @@ private:
     };
 
     struct NPadEntry {
-        NPadType joy_styles;
+        NpadStyleSet joy_styles;
         NPadAssignments pad_assignment;
 
         ColorReadError single_color_error;
@@ -391,7 +391,7 @@ private:
 
     u32 press_state{};
 
-    NPadType style{};
+    NpadStyleSet style{};
     std::array<NPadEntry, 10> shared_memory_entries{};
     using ButtonArray = std::array<
         std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,

From 16e2e1c45f8d510946645199140b20e1bde3e7da Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Tue, 6 Oct 2020 04:50:15 -0400
Subject: [PATCH 13/37] hid: Stub InitializeVibrationDevice

---
 src/core/hle/service/hid/hid.cpp | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index fb57dec02..86b83dcc6 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -140,15 +140,23 @@ void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose
 class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
 public:
     IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") {
+        // clang-format off
         static const FunctionInfo functions[] = {
-            {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"},
+            {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},
         };
+        // clang-format on
+
         RegisterHandlers(functions);
     }
 
 private:
-    void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) {
-        LOG_WARNING(Service_HID, "(STUBBED) called");
+    void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
+
+        LOG_WARNING(Service_HID, "(STUBBED) called, npad_type={}, npad_id={}, device_index={}",
+                    vibration_device_handle.npad_type, vibration_device_handle.npad_id,
+                    vibration_device_handle.device_index);
 
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(RESULT_SUCCESS);

From b92bf51ae1a08eca22bf0ce98b234692b9d59207 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Tue, 6 Oct 2020 05:08:52 -0400
Subject: [PATCH 14/37] hid: Implement GetVibrationDeviceInfo

The first u32 describes the vibration device type which is a Linear Resonant Actuator used in Nintendo Switch controller hardware.

The second u32 describes the vibration device position, in this case distinguishing between left and right vibration actuators.

Pro Controllers have 2 LRAs each that can vibrate independently of each other, which means they have 2 distinct vibration device handles to distinguish between the two actuators.

Similarly for joycons, the left joycon can be distinguished from the right joycon through the vibration device handle since each joycon has 1 LRA.
---
 src/core/hle/service/hid/hid.cpp | 26 +++++++++++++++++++++++---
 src/core/hle/service/hid/hid.h   | 16 ++++++++++++++++
 2 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 86b83dcc6..993738f36 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -924,12 +924,32 @@ void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
 }
 
 void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
-    LOG_DEBUG(Service_HID, "called");
+    IPC::RequestParser rp{ctx};
+    const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
+
+    VibrationDeviceInfo vibration_device_info;
+
+    vibration_device_info.type = VibrationDeviceType::LinearResonantActuator;
+
+    switch (vibration_device_handle.device_index) {
+    case Controller_NPad::DeviceIndex::Left:
+        vibration_device_info.position = VibrationDevicePosition::Left;
+        break;
+    case Controller_NPad::DeviceIndex::Right:
+        vibration_device_info.position = VibrationDevicePosition::Right;
+        break;
+    case Controller_NPad::DeviceIndex::None:
+    default:
+        vibration_device_info.position = VibrationDevicePosition::None;
+        break;
+    }
+
+    LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
+              vibration_device_info.type, vibration_device_info.position);
 
     IPC::ResponseBuilder rb{ctx, 4};
     rb.Push(RESULT_SUCCESS);
-    rb.Push<u32>(1);
-    rb.Push<u32>(0);
+    rb.PushRaw<VibrationDeviceInfo>(vibration_device_info);
 }
 
 void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index fd0372b18..2f7483170 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -146,6 +146,22 @@ private:
     void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
     void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
 
+    enum class VibrationDeviceType : u32 {
+        LinearResonantActuator = 1,
+    };
+
+    enum class VibrationDevicePosition : u32 {
+        None = 0,
+        Left = 1,
+        Right = 2,
+    };
+
+    struct VibrationDeviceInfo {
+        VibrationDeviceType type{};
+        VibrationDevicePosition position{};
+    };
+    static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
+
     std::shared_ptr<IAppletResource> applet_resource;
     Core::System& system;
 };

From e3c274998603b1bf3aa00a79474f5796c7dadac6 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Tue, 6 Oct 2020 07:00:18 -0400
Subject: [PATCH 15/37] hid: Reorder all HID commands

Reorders all HID commands in command id order.
---
 src/core/frontend/applets/controller.cpp      |   4 +-
 src/core/hle/service/hid/controllers/npad.cpp |  34 +-
 src/core/hle/service/hid/controllers/npad.h   |  14 +-
 src/core/hle/service/hid/hid.cpp              | 443 +++++++++---------
 src/core/hle/service/hid/hid.h                |  22 +-
 5 files changed, 266 insertions(+), 251 deletions(-)

diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index 1ac2fb80c..03bbedf8b 100644
--- a/src/core/frontend/applets/controller.cpp
+++ b/src/core/frontend/applets/controller.cpp
@@ -33,13 +33,13 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
         parameters.enable_single_mode ? 1 : parameters.min_players;
 
     // Disconnect Handheld first.
-    npad.DisconnectNPadAtIndex(8);
+    npad.DisconnectNpadAtIndex(8);
 
     // Deduce the best configuration based on the input parameters.
     for (std::size_t index = 0; index < players.size() - 2; ++index) {
         // First, disconnect all controllers regardless of the value of keep_controllers_connected.
         // This makes it easy to connect the desired controllers.
-        npad.DisconnectNPadAtIndex(index);
+        npad.DisconnectNpadAtIndex(index);
 
         // Only connect the minimum number of required players.
         if (index >= min_supported_players) {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 8181bddbc..b330c5e40 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -139,7 +139,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
         controller.properties.is_vertical.Assign(1);
         controller.properties.use_plus.Assign(1);
         controller.properties.use_minus.Assign(1);
-        controller.pad_assignment = NPadAssignments::Single;
+        controller.pad_assignment = NpadAssignments::Single;
         break;
     case NPadControllerType::Handheld:
         controller.joy_styles.handheld.Assign(1);
@@ -147,7 +147,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
         controller.properties.is_vertical.Assign(1);
         controller.properties.use_plus.Assign(1);
         controller.properties.use_minus.Assign(1);
-        controller.pad_assignment = NPadAssignments::Dual;
+        controller.pad_assignment = NpadAssignments::Dual;
         break;
     case NPadControllerType::JoyDual:
         controller.joy_styles.joycon_dual.Assign(1);
@@ -156,26 +156,26 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
         controller.properties.is_vertical.Assign(1);
         controller.properties.use_plus.Assign(1);
         controller.properties.use_minus.Assign(1);
-        controller.pad_assignment = NPadAssignments::Dual;
+        controller.pad_assignment = NpadAssignments::Dual;
         break;
     case NPadControllerType::JoyLeft:
         controller.joy_styles.joycon_left.Assign(1);
         controller.device_type.joycon_left.Assign(1);
         controller.properties.is_horizontal.Assign(1);
         controller.properties.use_minus.Assign(1);
-        controller.pad_assignment = NPadAssignments::Single;
+        controller.pad_assignment = NpadAssignments::Single;
         break;
     case NPadControllerType::JoyRight:
         controller.joy_styles.joycon_right.Assign(1);
         controller.device_type.joycon_right.Assign(1);
         controller.properties.is_horizontal.Assign(1);
         controller.properties.use_plus.Assign(1);
-        controller.pad_assignment = NPadAssignments::Single;
+        controller.pad_assignment = NpadAssignments::Single;
         break;
     case NPadControllerType::Pokeball:
         controller.joy_styles.pokeball.Assign(1);
         controller.device_type.pokeball.Assign(1);
-        controller.pad_assignment = NPadAssignments::Single;
+        controller.pad_assignment = NpadAssignments::Single;
         break;
     }
 
@@ -202,7 +202,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
 
 void Controller_NPad::OnInit() {
     auto& kernel = system.Kernel();
-    for (std::size_t i = 0; i < styleset_changed_events.size(); i++) {
+    for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
         styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
             kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));
     }
@@ -357,7 +357,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
     if (!IsControllerActivated()) {
         return;
     }
-    for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
+    for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
         auto& npad = shared_memory_entries[i];
         const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
                                                            &npad.handheld_states,
@@ -499,7 +499,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
     if (!IsControllerActivated()) {
         return;
     }
-    for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
+    for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
         auto& npad = shared_memory_entries[i];
 
         const auto& controller_type = connected_controllers[i].type;
@@ -627,7 +627,7 @@ Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const {
     return style;
 }
 
-void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
+void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {
     ASSERT(length > 0 && (length % sizeof(u32)) == 0);
     supported_npad_id_types.clear();
     supported_npad_id_types.resize(length / sizeof(u32));
@@ -639,7 +639,7 @@ void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length)
     std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());
 }
 
-std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
+std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const {
     return supported_npad_id_types.size();
 }
 
@@ -659,7 +659,7 @@ Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActi
     return handheld_activation_mode;
 }
 
-void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
+void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) {
     const std::size_t npad_index = NPadIdToIndex(npad_id);
     ASSERT(npad_index < shared_memory_entries.size());
     if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) {
@@ -714,7 +714,7 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz
 void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
                                          bool connected) {
     if (!connected) {
-        DisconnectNPadAtIndex(npad_index);
+        DisconnectNpadAtIndex(npad_index);
         return;
     }
 
@@ -734,11 +734,11 @@ void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::siz
     InitNewlyAddedController(npad_index);
 }
 
-void Controller_NPad::DisconnectNPad(u32 npad_id) {
-    DisconnectNPadAtIndex(NPadIdToIndex(npad_id));
+void Controller_NPad::DisconnectNpad(u32 npad_id) {
+    DisconnectNpadAtIndex(NPadIdToIndex(npad_id));
 }
 
-void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) {
+void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
     Settings::values.players.GetValue()[npad_index].connected = false;
     connected_controllers[npad_index].is_connected = false;
 
@@ -777,7 +777,7 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {
         (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft &&
          connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) {
         // Disconnect the joycon at the second id and connect the dual joycon at the first index.
-        DisconnectNPad(npad_id_2);
+        DisconnectNpad(npad_id_2);
         AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1);
     }
 }
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index fed8425b1..35dd2bf5f 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -75,7 +75,7 @@ public:
         Horizontal = 1,
     };
 
-    enum class NPadAssignments : u32 {
+    enum class NpadAssignments : u32 {
         Dual = 0,
         Single = 1,
     };
@@ -136,9 +136,9 @@ public:
     void SetSupportedStyleSet(NpadStyleSet style_set);
     NpadStyleSet GetSupportedStyleSet() const;
 
-    void SetSupportedNPadIdTypes(u8* data, std::size_t length);
+    void SetSupportedNpadIdTypes(u8* data, std::size_t length);
     void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
-    std::size_t GetSupportedNPadIdTypesSize() const;
+    std::size_t GetSupportedNpadIdTypesSize() const;
 
     void SetHoldType(NpadHoldType joy_hold_type);
     NpadHoldType GetHoldType() const;
@@ -146,7 +146,7 @@ public:
     void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
     NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
 
-    void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode);
+    void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode);
 
     void VibrateController(const std::vector<u32>& controllers,
                            const std::vector<Vibration>& vibrations);
@@ -161,8 +161,8 @@ public:
     // Adds a new controller at an index with connection status.
     void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
 
-    void DisconnectNPad(u32 npad_id);
-    void DisconnectNPadAtIndex(std::size_t index);
+    void DisconnectNpad(u32 npad_id);
+    void DisconnectNpadAtIndex(std::size_t index);
 
     void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
     GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
@@ -348,7 +348,7 @@ private:
 
     struct NPadEntry {
         NpadStyleSet joy_styles;
-        NPadAssignments pad_assignment;
+        NpadAssignments pad_assignment;
 
         ColorReadError single_color_error;
         ControllerColor single_color;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 993738f36..9a631008f 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -328,15 +328,74 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
     rb.PushIpcInterface<IAppletResource>(applet_resource);
 }
 
+void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    applet_resource->ActivateController(HidController::DebugPad);
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    applet_resource->ActivateController(HidController::Touchscreen);
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    applet_resource->ActivateController(HidController::Mouse);
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    applet_resource->ActivateController(HidController::Keyboard);
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto flags{rp.Pop<u32>()};
+
+    LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
 void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto basic_xpad_id{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->ActivateController(HidController::XPad);
+
     LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id,
               applet_resource_user_id);
 
-    applet_resource->ActivateController(HidController::XPad);
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -356,7 +415,9 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto handle{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
+
     applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
+
     LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
               applet_resource_user_id);
 
@@ -368,6 +429,7 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto handle{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
+
     applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
 
     LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
@@ -377,86 +439,6 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
     rb.Push(RESULT_SUCCESS);
 }
 
-void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-    applet_resource->ActivateController(HidController::DebugPad);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
-void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-    applet_resource->ActivateController(HidController::Touchscreen);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
-void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-    applet_resource->ActivateController(HidController::Mouse);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
-void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-    applet_resource->ActivateController(HidController::Keyboard);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
-void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto flags{rp.Pop<u32>()};
-    LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
-
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
-void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto unknown{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
-              applet_resource_user_id);
-
-    applet_resource->ActivateController(HidController::Gesture);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
-void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
-    // Should have no effect with how our npad sets up the data
-    IPC::RequestParser rp{ctx};
-    const auto unknown{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
-              applet_resource_user_id);
-
-    applet_resource->ActivateController(HidController::NPad);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
 void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto handle{rp.Pop<u32>()};
@@ -487,8 +469,8 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
     const auto handle{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
-                applet_resource_user_id);
+    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", enable,
+                handle, applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -501,7 +483,7 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode{drift_mode});
+        .SetGyroscopeZeroDriftMode({drift_mode});
 
     LOG_DEBUG(Service_HID, "called, handle={}, drift_mode={}, applet_resource_user_id={}", handle,
               drift_mode, applet_resource_user_id);
@@ -520,9 +502,8 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
-    rb.Push<u32>(
-        static_cast<u32>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                             .GetGyroscopeZeroDriftMode()));
+    rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                    .GetGyroscopeZeroDriftMode());
 }
 
 void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
@@ -554,15 +535,29 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
                 .IsSixAxisSensorAtRest());
 }
 
+void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto unknown{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    applet_resource->ActivateController(HidController::Gesture);
+
+    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
+              applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
 void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto supported_styleset{rp.Pop<u32>()};
 
-    LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
-
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
         .SetSupportedStyleSet({supported_styleset});
 
+    LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
+
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -573,21 +568,22 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
 
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
-    rb.Push<u32>(controller.GetSupportedStyleSet().raw);
+    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                .GetSupportedStyleSet()
+                .raw);
 }
 
 void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetSupportedNpadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
+
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -596,22 +592,24 @@ void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->ActivateController(HidController::NPad);
+
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
-    applet_resource->ActivateController(HidController::NPad);
 }
 
 void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->DeactivateController(HidController::NPad);
+
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
-    applet_resource->DeactivateController(HidController::NPad);
 }
 
 void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
@@ -634,10 +632,11 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
     const auto npad_id{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNpad(npad_id);
+
     LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
               applet_resource_user_id);
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id);
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -650,9 +649,24 @@ void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 4};
     rb.Push(RESULT_SUCCESS);
-    rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                        .GetLedPattern(npad_id)
-                        .raw);
+    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                .GetLedPattern(npad_id)
+                .raw);
+}
+
+void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
+    // Should have no effect with how our npad sets up the data
+    IPC::RequestParser rp{ctx};
+    const auto unknown{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    applet_resource->ActivateController(HidController::NPad);
+
+    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
+              applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
 }
 
 void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
@@ -660,12 +674,11 @@ void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
     const auto applet_resource_user_id{rp.Pop<u64>()};
     const auto hold_type{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType({hold_type});
+
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
               applet_resource_user_id, hold_type);
 
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-    controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
-
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -676,10 +689,9 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
 
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-    const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
     IPC::ResponseBuilder rb{ctx, 4};
     rb.Push(RESULT_SUCCESS);
-    rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
+    rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType()));
 }
 
 void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
@@ -687,12 +699,12 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
     const auto npad_id{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetNpadMode(npad_id, Controller_NPad::NpadAssignments::Single);
+
     LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
                 applet_resource_user_id);
 
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-    controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single);
-
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -704,13 +716,13 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
     const auto applet_resource_user_id{rp.Pop<u64>()};
     const auto npad_joy_device_type{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetNpadMode(npad_id, Controller_NPad::NpadAssignments::Single);
+
     LOG_WARNING(Service_HID,
                 "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
                 npad_id, applet_resource_user_id, npad_joy_device_type);
 
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-    controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single);
-
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -720,12 +732,12 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
     const auto npad_id{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetNpadMode(npad_id, Controller_NPad::NpadAssignments::Dual);
+
     LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
               applet_resource_user_id);
 
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-    controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual);
-
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -736,12 +748,12 @@ void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
     const auto npad_id_2{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
+
     LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
               npad_id_1, npad_id_2, applet_resource_user_id);
 
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-    controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
-
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -750,9 +762,9 @@ void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).StartLRAssignmentMode();
+
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-    controller.StartLRAssignmentMode();
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -762,9 +774,9 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).StopLRAssignmentMode();
+
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-    controller.StopLRAssignmentMode();
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -775,12 +787,12 @@ void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
     const auto applet_resource_user_id{rp.Pop<u64>()};
     const auto mode{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetNpadHandheldActivationMode({mode});
+
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, mode={}", applet_resource_user_id,
               mode);
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetNpadHandheldActivationMode(Controller_NPad::NpadHandheldActivationMode{mode});
-
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
@@ -793,23 +805,24 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 4};
     rb.Push(RESULT_SUCCESS);
-    rb.Push<u64>(
-        static_cast<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                             .GetNpadHandheldActivationMode()));
+    rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                    .GetNpadHandheldActivationMode());
 }
 
 void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto npad_1{rp.Pop<u32>()};
-    const auto npad_2{rp.Pop<u32>()};
+    const auto npad_id_1{rp.Pop<u32>()};
+    const auto npad_id_2{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}",
-              applet_resource_user_id, npad_1, npad_2);
+    const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                         .SwapNpadAssignment(npad_id_1, npad_id_2);
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_id_1={}, npad_id_2={}",
+              applet_resource_user_id, npad_id_1, npad_id_2);
 
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
     IPC::ResponseBuilder rb{ctx, 2};
-    if (controller.SwapNpadAssignment(npad_1, npad_2)) {
+    if (res) {
         rb.Push(RESULT_SUCCESS);
     } else {
         LOG_ERROR(Service_HID, "Npads are not connected!");
@@ -825,11 +838,10 @@ void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext
     LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
                 applet_resource_user_id);
 
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
-    rb.Push<bool>(controller.IsUnintendedHomeButtonInputProtectionEnabled(npad_id));
+    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                .IsUnintendedHomeButtonInputProtectionEnabled(npad_id));
 }
 
 void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {
@@ -838,91 +850,19 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
     const auto npad_id{rp.Pop<u32>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetUnintendedHomeButtonInputProtectionEnabled(unintended_home_button_input_protection,
+                                                       npad_id);
+
     LOG_WARNING(Service_HID,
                 "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"
                 "applet_resource_user_id={}",
-                npad_id, unintended_home_button_input_protection, applet_resource_user_id);
-
-    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-    controller.SetUnintendedHomeButtonInputProtectionEnabled(
-        unintended_home_button_input_protection, npad_id);
+                unintended_home_button_input_protection, npad_id, applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
 
-void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
-void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
-    LOG_DEBUG(Service_HID, "called");
-
-    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
-void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto controller{rp.Pop<u32>()};
-    const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller,
-              applet_resource_user_id);
-
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .VibrateController({controller}, {vibration_values});
-}
-
-void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-    const auto controllers = ctx.ReadBuffer(0);
-    const auto vibrations = ctx.ReadBuffer(1);
-
-    std::vector<u32> controller_list(controllers.size() / sizeof(u32));
-    std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() /
-                                                           sizeof(Controller_NPad::Vibration));
-
-    std::memcpy(controller_list.data(), controllers.data(), controllers.size());
-    std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
-
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .VibrateController(controller_list, vibration_list);
-
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(RESULT_SUCCESS);
-}
-
-void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto controller_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-
-    LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
-              applet_resource_user_id);
-
-    IPC::ResponseBuilder rb{ctx, 6};
-    rb.Push(RESULT_SUCCESS);
-    rb.PushRaw<Controller_NPad::Vibration>(
-        applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration());
-}
-
 void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
@@ -949,7 +889,37 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 4};
     rb.Push(RESULT_SUCCESS);
-    rb.PushRaw<VibrationDeviceInfo>(vibration_device_info);
+    rb.PushRaw(vibration_device_info);
+}
+
+void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto controller{rp.Pop<u32>()};
+    const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .VibrateController({controller}, {vibration_values});
+
+    LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller,
+              applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto controller_id{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
+              applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 6};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushRaw(
+        applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration());
 }
 
 void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
@@ -963,6 +933,7 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
 void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto can_vibrate{rp.Pop<bool>()};
+
     Settings::values.vibration_enabled.SetValue(can_vibrate);
 
     LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
@@ -979,6 +950,50 @@ void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
     rb.Push(Settings::values.vibration_enabled.GetValue());
 }
 
+void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    const auto controllers = ctx.ReadBuffer(0);
+    const auto vibrations = ctx.ReadBuffer(1);
+
+    std::vector<u32> controller_list(controllers.size() / sizeof(u32));
+    std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() /
+                                                           sizeof(Controller_NPad::Vibration));
+
+    std::memcpy(controller_list.data(), controllers.data(), controllers.size());
+    std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
+
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .VibrateController(controller_list, vibration_list);
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true);
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false);
+
+    LOG_DEBUG(Service_HID, "called");
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
 void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 2f7483170..57bc93778 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -86,17 +86,15 @@ public:
 
 private:
     void CreateAppletResource(Kernel::HLERequestContext& ctx);
-    void ActivateXpad(Kernel::HLERequestContext& ctx);
-    void GetXpadIDs(Kernel::HLERequestContext& ctx);
-    void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx);
-    void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);
     void ActivateDebugPad(Kernel::HLERequestContext& ctx);
     void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
     void ActivateMouse(Kernel::HLERequestContext& ctx);
     void ActivateKeyboard(Kernel::HLERequestContext& ctx);
     void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx);
-    void ActivateGesture(Kernel::HLERequestContext& ctx);
-    void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
+    void ActivateXpad(Kernel::HLERequestContext& ctx);
+    void GetXpadIDs(Kernel::HLERequestContext& ctx);
+    void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx);
+    void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);
     void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
     void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
     void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx);
@@ -104,6 +102,7 @@ private:
     void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
     void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
     void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx);
+    void ActivateGesture(Kernel::HLERequestContext& ctx);
     void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
     void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
     void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx);
@@ -112,6 +111,7 @@ private:
     void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx);
     void DisconnectNpad(Kernel::HLERequestContext& ctx);
     void GetPlayerLedPattern(Kernel::HLERequestContext& ctx);
+    void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
     void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
     void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
     void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx);
@@ -125,15 +125,15 @@ private:
     void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
     void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
     void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
-    void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
-    void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
-    void SendVibrationValue(Kernel::HLERequestContext& ctx);
-    void SendVibrationValues(Kernel::HLERequestContext& ctx);
-    void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
     void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
+    void SendVibrationValue(Kernel::HLERequestContext& ctx);
+    void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
     void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx);
     void PermitVibration(Kernel::HLERequestContext& ctx);
     void IsVibrationPermitted(Kernel::HLERequestContext& ctx);
+    void SendVibrationValues(Kernel::HLERequestContext& ctx);
+    void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
+    void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
     void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
     void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
     void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);

From 31de52513eef90ed19583ab1ffe3e74ebe95e45d Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Wed, 7 Oct 2020 00:37:13 -0400
Subject: [PATCH 16/37] hid: Pop a struct of parameters instead of popping
 individual parameters

Some parameters need to be doubleword aligned due to the presence of the applet_resource_user_id.
Previously, this value was invalid in many commands where it was not doubleword aligned when popped.
---
 src/core/hle/service/hid/hid.cpp | 340 +++++++++++++++++++++----------
 1 file changed, 237 insertions(+), 103 deletions(-)

diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 9a631008f..fdac598f0 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -388,13 +388,18 @@ void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {
 
 void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto basic_xpad_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        u32 basic_xpad_id{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->ActivateController(HidController::XPad);
 
-    LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id,
-              applet_resource_user_id);
+    LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
+              parameters.basic_xpad_id, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -413,13 +418,20 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {
 
 void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
 
-    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
-              applet_resource_user_id);
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -427,13 +439,20 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
 
 void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
 
-    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
-              applet_resource_user_id);
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -441,11 +460,20 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
 
 void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
 
-    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
-                applet_resource_user_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
+
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -453,11 +481,20 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
 
 void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
 
-    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
-                applet_resource_user_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
+
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -465,12 +502,21 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
 
 void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    [[maybe_unused]] const auto enable{rp.Pop<bool>()};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        bool enable_sixaxis_sensor_fusion{};
+        INSERT_PADDING_BYTES(3);
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        u64 applet_resource_user_id{};
+    };
 
-    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", enable,
-                handle, applet_resource_user_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    LOG_WARNING(Service_HID,
+                "(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
+                "device_index={}, applet_resource_user_id={}",
+                parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
+                parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
+                parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -478,14 +524,17 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
 
 void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto drift_mode{rp.Pop<u32>()};
+    const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
+    const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetGyroscopeZeroDriftMode({drift_mode});
+        .SetGyroscopeZeroDriftMode(drift_mode);
 
-    LOG_DEBUG(Service_HID, "called, handle={}, drift_mode={}, applet_resource_user_id={}", handle,
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
+              "applet_resource_user_id={}",
+              sixaxis_handle.npad_type, sixaxis_handle.npad_id, sixaxis_handle.device_index,
               drift_mode, applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
@@ -494,11 +543,18 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
 
 void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
 
-    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
-              applet_resource_user_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
@@ -508,14 +564,21 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
 
 void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
         .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard);
 
-    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
-              applet_resource_user_id);
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -523,11 +586,18 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
 
 void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
 
-    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
-              applet_resource_user_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
@@ -537,13 +607,18 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
 
 void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto unknown{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        u32 unknown{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->ActivateController(HidController::Gesture);
 
-    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
-              applet_resource_user_id);
+    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown,
+              parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -614,28 +689,39 @@ void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) {
 
 void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto npad_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-    const auto unknown{rp.Pop<u64>()};
+    struct Parameters {
+        u32 npad_id{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+        u64 unknown{};
+    };
 
-    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id,
-              applet_resource_user_id, unknown);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
+              parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);
 
     IPC::ResponseBuilder rb{ctx, 2, 1};
     rb.Push(RESULT_SUCCESS);
     rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                           .GetStyleSetChangedEvent(npad_id));
+                           .GetStyleSetChangedEvent(parameters.npad_id));
 }
 
 void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto npad_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        u32 npad_id{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNpad(npad_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
 
-    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
-              applet_resource_user_id);
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .DisconnectNpad(parameters.npad_id);
+
+    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
+              parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -657,13 +743,18 @@ void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
 void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
     // Should have no effect with how our npad sets up the data
     IPC::RequestParser rp{ctx};
-    const auto unknown{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        u32 unknown{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->ActivateController(HidController::NPad);
 
-    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
-              applet_resource_user_id);
+    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown,
+              parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -672,9 +763,9 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
 void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
-    const auto hold_type{rp.Pop<u64>()};
+    const auto hold_type{rp.PopEnum<Controller_NPad::NpadHoldType>()};
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType({hold_type});
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type);
 
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
               applet_resource_user_id, hold_type);
@@ -691,19 +782,24 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 4};
     rb.Push(RESULT_SUCCESS);
-    rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType()));
+    rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType());
 }
 
 void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto npad_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        u32 npad_id{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetNpadMode(npad_id, Controller_NPad::NpadAssignments::Single);
+        .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single);
 
-    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
-                applet_resource_user_id);
+    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
+                parameters.npad_id, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -712,16 +808,22 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
 void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
     // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault
     IPC::RequestParser rp{ctx};
-    const auto npad_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
-    const auto npad_joy_device_type{rp.Pop<u64>()};
+    struct Parameters {
+        u32 npad_id{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+        u64 npad_joy_device_type{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetNpadMode(npad_id, Controller_NPad::NpadAssignments::Single);
+        .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single);
 
     LOG_WARNING(Service_HID,
                 "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
-                npad_id, applet_resource_user_id, npad_joy_device_type);
+                parameters.npad_id, parameters.applet_resource_user_id,
+                parameters.npad_joy_device_type);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -729,14 +831,19 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
 
 void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto npad_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        u32 npad_id{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetNpadMode(npad_id, Controller_NPad::NpadAssignments::Dual);
+        .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual);
 
-    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
-              applet_resource_user_id);
+    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
+                parameters.npad_id, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -785,13 +892,13 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
 void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
-    const auto mode{rp.Pop<u64>()};
+    const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetNpadHandheldActivationMode({mode});
+        .SetNpadHandheldActivationMode(activation_mode);
 
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, mode={}", applet_resource_user_id,
-              mode);
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}",
+              applet_resource_user_id, activation_mode);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -818,8 +925,8 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
     const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad)
                          .SwapNpadAssignment(npad_id_1, npad_id_2);
 
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_id_1={}, npad_id_2={}",
-              applet_resource_user_id, npad_id_1, npad_id_2);
+    LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
+              npad_id_1, npad_id_2, applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     if (res) {
@@ -832,32 +939,43 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
 
 void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto npad_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        u32 npad_id{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
 
-    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
-                applet_resource_user_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
+                parameters.npad_id, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
     rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                .IsUnintendedHomeButtonInputProtectionEnabled(npad_id));
+                .IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id));
 }
 
 void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto unintended_home_button_input_protection{rp.Pop<bool>()};
-    const auto npad_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        bool unintended_home_button_input_protection{};
+        INSERT_PADDING_BYTES(3);
+        u32 npad_id{};
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetUnintendedHomeButtonInputProtectionEnabled(unintended_home_button_input_protection,
-                                                       npad_id);
+        .SetUnintendedHomeButtonInputProtectionEnabled(
+            parameters.unintended_home_button_input_protection, parameters.npad_id);
 
     LOG_WARNING(Service_HID,
                 "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"
                 "applet_resource_user_id={}",
-                unintended_home_button_input_protection, npad_id, applet_resource_user_id);
+                parameters.unintended_home_button_input_protection, parameters.npad_id,
+                parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -1007,11 +1125,19 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
 
 void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
 
-    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
-                applet_resource_user_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    LOG_WARNING(
+        Service_HID,
+        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+        parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+        parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -1019,11 +1145,19 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
 
 void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto handle{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle sixaxis_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
 
-    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
-                applet_resource_user_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    LOG_WARNING(
+        Service_HID,
+        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+        parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+        parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);

From 07b81f57babcc7aa41fddfc892148688e841d96e Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Wed, 7 Oct 2020 14:22:47 -0400
Subject: [PATCH 17/37] hid: Fix controller rumble based on new research

This fixes the issue where rumble is only sent to the first controller.
Now, individual controllers can receive their own rumble commands.
---
 src/core/hle/service/hid/controllers/npad.cpp | 45 +++++++++------
 src/core/hle/service/hid/controllers/npad.h   | 12 ++--
 src/core/hle/service/hid/hid.cpp              | 55 ++++++++++++-------
 3 files changed, 69 insertions(+), 43 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index b330c5e40..8a5e5abcf 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -667,35 +667,44 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode)
     }
 }
 
-void Controller_NPad::VibrateController(const std::vector<u32>& controllers,
-                                        const std::vector<Vibration>& vibrations) {
+void Controller_NPad::VibrateController(const std::vector<DeviceHandle>& vibration_device_handles,
+                                        const std::vector<VibrationValue>& vibration_values) {
     LOG_TRACE(Service_HID, "called");
 
     if (!Settings::values.vibration_enabled.GetValue() || !can_controllers_vibrate) {
         return;
     }
-    bool success = true;
-    for (std::size_t i = 0; i < controllers.size(); ++i) {
-        if (!connected_controllers[i].is_connected) {
+
+    ASSERT_MSG(vibration_device_handles.size() == vibration_values.size(),
+               "The amount of device handles does not match with the amount of vibration values,"
+               "this is undefined behavior!");
+
+    for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) {
+        const auto npad_index = NPadIdToIndex(vibration_device_handles[i].npad_id);
+        const auto device_index =
+            static_cast<std::size_t>(vibration_device_handles[i].device_index);
+
+        if (!connected_controllers[npad_index].is_connected) {
             continue;
         }
+
         using namespace Settings::NativeButton;
-        const auto& button_state = buttons[i];
-        if (button_state[A - BUTTON_HID_BEGIN]) {
-            if (button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
-                    vibrations[0].amp_high, vibrations[0].amp_low, vibrations[0].freq_high,
-                    vibrations[0].freq_low)) {
-                success = false;
-            }
-        }
-    }
-    if (success) {
-        last_processed_vibration = vibrations.back();
+        const auto& button_state = buttons[npad_index];
+
+        // TODO: Vibrate left/right vibration motors independently if possible.
+        button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
+            vibration_values[i].amp_high, vibration_values[i].amp_low,
+            vibration_values[i].freq_high, vibration_values[i].freq_low);
+
+        latest_vibration_values[npad_index][device_index] = vibration_values[i];
     }
 }
 
-Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
-    return last_processed_vibration;
+Controller_NPad::VibrationValue Controller_NPad::GetLastVibration(
+    const DeviceHandle& vibration_device_handle) const {
+    const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
+    const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
+    return latest_vibration_values[npad_index][device_index];
 }
 
 std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 35dd2bf5f..c1b19103a 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -109,13 +109,13 @@ public:
     };
     static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
 
-    struct Vibration {
+    struct VibrationValue {
         f32 amp_low;
         f32 freq_low;
         f32 amp_high;
         f32 freq_high;
     };
-    static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size");
+    static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size");
 
     struct LedPattern {
         explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
@@ -148,10 +148,10 @@ public:
 
     void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode);
 
-    void VibrateController(const std::vector<u32>& controllers,
-                           const std::vector<Vibration>& vibrations);
+    void VibrateController(const std::vector<DeviceHandle>& vibration_device_handles,
+                           const std::vector<VibrationValue>& vibration_values);
 
-    Vibration GetLastVibration() const;
+    VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const;
 
     std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
     void SignalStyleSetChangedEvent(u32 npad_id) const;
@@ -410,7 +410,7 @@ private:
     NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
     // Each controller should have their own styleset changed event
     std::array<Kernel::EventPair, 10> styleset_changed_events;
-    Vibration last_processed_vibration{};
+    std::array<std::array<VibrationValue, 3>, 10> latest_vibration_values;
     std::array<ControllerHolder, 10> connected_controllers{};
     std::array<bool, 10> unintended_home_button_input_protection{};
     GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index fdac598f0..b0390bdb2 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1012,15 +1012,23 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
 
 void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto controller{rp.Pop<u32>()};
-    const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle vibration_device_handle{};
+        Controller_NPad::VibrationValue vibration_value{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .VibrateController({controller}, {vibration_values});
+        .VibrateController({parameters.vibration_device_handle}, {parameters.vibration_value});
 
-    LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller,
-              applet_resource_user_id);
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.vibration_device_handle.npad_type,
+              parameters.vibration_device_handle.npad_id,
+              parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -1028,16 +1036,24 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
 
 void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-    const auto controller_id{rp.Pop<u32>()};
-    const auto applet_resource_user_id{rp.Pop<u64>()};
+    struct Parameters {
+        Controller_NPad::DeviceHandle vibration_device_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
 
-    LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
-              applet_resource_user_id);
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.vibration_device_handle.npad_type,
+              parameters.vibration_device_handle.npad_id,
+              parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 6};
     rb.Push(RESULT_SUCCESS);
-    rb.PushRaw(
-        applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration());
+    rb.PushRaw(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                   .GetLastVibration(parameters.vibration_device_handle));
 }
 
 void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
@@ -1072,18 +1088,19 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    const auto controllers = ctx.ReadBuffer(0);
+    const auto handles = ctx.ReadBuffer(0);
     const auto vibrations = ctx.ReadBuffer(1);
 
-    std::vector<u32> controller_list(controllers.size() / sizeof(u32));
-    std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() /
-                                                           sizeof(Controller_NPad::Vibration));
+    std::vector<Controller_NPad::DeviceHandle> vibration_device_handles(
+        handles.size() / sizeof(Controller_NPad::DeviceHandle));
+    std::vector<Controller_NPad::VibrationValue> vibration_values(
+        vibrations.size() / sizeof(Controller_NPad::VibrationValue));
 
-    std::memcpy(controller_list.data(), controllers.data(), controllers.size());
-    std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
+    std::memcpy(vibration_device_handles.data(), handles.data(), handles.size());
+    std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size());
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .VibrateController(controller_list, vibration_list);
+        .VibrateController(vibration_device_handles, vibration_values);
 
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 

From e02ef3c3bed2f8e98ec9481cdea1a6253c34e9d1 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Thu, 8 Oct 2020 08:18:50 -0400
Subject: [PATCH 18/37] controllers/npad: Stop games from vibrating incorrect
 controllers

Fixes vibration in 1-2 Switch and potentially other games where they would vibrate both players' joycons at the same time.
---
 src/core/hle/service/hid/controllers/npad.cpp | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 8a5e5abcf..f865e3f5f 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -688,6 +688,16 @@ void Controller_NPad::VibrateController(const std::vector<DeviceHandle>& vibrati
             continue;
         }
 
+        // Some games try to send mismatched parameters in the device handle, block these.
+        if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft &&
+             (vibration_device_handles[i].npad_type == NpadType::JoyconRight ||
+              vibration_device_handles[i].device_index == DeviceIndex::Right)) ||
+            (connected_controllers[npad_index].type == NPadControllerType::JoyRight &&
+             (vibration_device_handles[i].npad_type == NpadType::JoyconLeft ||
+              vibration_device_handles[i].device_index == DeviceIndex::Left))) {
+            continue;
+        }
+
         using namespace Settings::NativeButton;
         const auto& button_state = buttons[npad_index];
 

From 652d6766d55acec6416dccb900a45c6660a86607 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Thu, 8 Oct 2020 23:43:07 -0400
Subject: [PATCH 19/37] configure_input: Hook up the vibration percentage
 spinbox

This allows setting the vibration strength percentage anywhere from 1% to 100%.
Also hooks up the remaining motion button and checkbox in the Controller Applet.
---
 src/core/hle/service/hid/controllers/npad.cpp | 3 ++-
 src/core/settings.cpp                         | 1 +
 src/core/settings.h                           | 1 +
 src/yuzu/applets/controller.cpp               | 4 ++++
 src/yuzu/applets/controller.ui                | 2 +-
 src/yuzu/configuration/config.cpp             | 4 ++++
 src/yuzu/configuration/configure_input.cpp    | 2 ++
 src/yuzu/configuration/configure_input.ui     | 2 +-
 src/yuzu_cmd/config.cpp                       | 2 ++
 src/yuzu_cmd/default_ini.h                    | 7 +++++++
 src/yuzu_tester/config.cpp                    | 1 +
 11 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index f865e3f5f..924f209c0 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -703,7 +703,8 @@ void Controller_NPad::VibrateController(const std::vector<DeviceHandle>& vibrati
 
         // TODO: Vibrate left/right vibration motors independently if possible.
         button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
-            vibration_values[i].amp_high, vibration_values[i].amp_low,
+            vibration_values[i].amp_high * Settings::values.vibration_strength.GetValue() / 100,
+            vibration_values[i].amp_low * Settings::values.vibration_strength.GetValue() / 100,
             vibration_values[i].freq_high, vibration_values[i].freq_low);
 
         latest_vibration_values[npad_index][device_index] = vibration_values[i];
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index aadbc3932..6e39aebb5 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -150,6 +150,7 @@ void RestoreGlobalState() {
     values.players.SetGlobal(true);
     values.use_docked_mode.SetGlobal(true);
     values.vibration_enabled.SetGlobal(true);
+    values.vibration_strength.SetGlobal(true);
     values.motion_enabled.SetGlobal(true);
 }
 
diff --git a/src/core/settings.h b/src/core/settings.h
index edd2a00ca..496f47747 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -170,6 +170,7 @@ struct Values {
     Setting<bool> use_docked_mode;
 
     Setting<bool> vibration_enabled;
+    Setting<int> vibration_strength;
 
     Setting<bool> motion_enabled;
     std::string motion_device;
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index 7697fe434..196b4f163 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -266,6 +266,8 @@ void QtControllerSelectorDialog::ApplyConfiguration() {
     OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue());
 
     Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
+    Settings::values.vibration_strength.SetValue(ui->vibrationSpin->value());
+    Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
 }
 
 void QtControllerSelectorDialog::LoadConfiguration() {
@@ -281,6 +283,8 @@ void QtControllerSelectorDialog::LoadConfiguration() {
     UpdateDockedState(Settings::values.players.GetValue()[8].connected);
 
     ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
+    ui->vibrationSpin->setValue(Settings::values.vibration_strength.GetValue());
+    ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
 }
 
 void QtControllerSelectorDialog::CallConfigureInputDialog() {
diff --git a/src/yuzu/applets/controller.ui b/src/yuzu/applets/controller.ui
index 2ab69a2d3..cc27b8ef4 100644
--- a/src/yuzu/applets/controller.ui
+++ b/src/yuzu/applets/controller.ui
@@ -2349,7 +2349,7 @@
                <number>1</number>
               </property>
               <property name="maximum">
-               <number>200</number>
+               <number>100</number>
               </property>
               <property name="value">
                <number>100</number>
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 296c58f58..820ef4098 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -493,6 +493,8 @@ void Config::ReadControlValues() {
     ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), false);
     ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"),
                       true);
+    ReadSettingGlobal(Settings::values.vibration_strength, QStringLiteral("vibration_strength"),
+                      100);
     ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"), true);
 
     qt_config->endGroup();
@@ -1150,6 +1152,8 @@ void Config::SaveControlValues() {
     WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
     WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled,
                        true);
+    WriteSettingGlobal(QStringLiteral("vibration_strength"), Settings::values.vibration_strength,
+                       100);
     WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true);
     WriteSetting(QStringLiteral("motion_device"),
                  QString::fromStdString(Settings::values.motion_device),
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 9a4de4c5d..84df547b9 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -186,6 +186,7 @@ void ConfigureInput::ApplyConfiguration() {
     OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue());
 
     Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
+    Settings::values.vibration_strength.SetValue(ui->vibrationSpin->value());
     Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
 }
 
@@ -206,6 +207,7 @@ void ConfigureInput::LoadConfiguration() {
     UpdateDockedState(Settings::values.players.GetValue()[8].connected);
 
     ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
+    ui->vibrationSpin->setValue(Settings::values.vibration_strength.GetValue());
     ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
 }
 
diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index b74481bda..cbd67d4c7 100644
--- a/src/yuzu/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
@@ -215,7 +215,7 @@
             <number>1</number>
            </property>
            <property name="maximum">
-            <number>200</number>
+            <number>100</number>
            </property>
            <property name="value">
             <number>100</number>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index feee02fcd..209350837 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -290,6 +290,8 @@ void Config::ReadValues() {
 
     Settings::values.vibration_enabled.SetValue(
         sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true));
+    Settings::values.vibration_strength.SetValue(
+        sdl2_config->GetInteger("ControlsGeneral", "vibration_strength", 100));
     Settings::values.motion_enabled.SetValue(
         sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true));
     Settings::values.touchscreen.enabled =
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 796e27df4..53057c01c 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -65,6 +65,13 @@ button_screenshot=
 lstick=
 rstick=
 
+# Whether to enable or disable vibration
+# 0: Disabled, 1 (default): Enabled
+vibration_enabled=
+
+# Vibration strength percentage (Default: 100)
+vibration_strength=
+
 # for motion input, the following devices are available:
 #  - "motion_emu" (default) for emulating motion input from mouse input. Required parameters:
 #      - "update_period": update period in milliseconds (default to 100)
diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp
index 3a8a333f0..437302520 100644
--- a/src/yuzu_tester/config.cpp
+++ b/src/yuzu_tester/config.cpp
@@ -76,6 +76,7 @@ void Config::ReadValues() {
     }
 
     Settings::values.vibration_enabled.SetValue(true);
+    Settings::values.vibration_strength.SetValue(100);
     Settings::values.motion_enabled.SetValue(true);
     Settings::values.touchscreen.enabled = "";
     Settings::values.touchscreen.device = "";

From 9b501af8e3d0f6457fafb0fdfbcc11f6da4f0e8a Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sat, 10 Oct 2020 09:03:47 -0400
Subject: [PATCH 20/37] controllers/npad: Add heuristics to reduce rumble state
 changes

Sending too many state changes in a short period of time can cause massive performance issues.
As a result, we have to use several heuristics to reduce the number of state changes to minimize/eliminate this performance impact while maintaining the quality of these vibrations as much as possible.
---
 src/core/frontend/input.h                     |  2 +-
 src/core/hle/service/hid/controllers/npad.cpp | 49 +++++++++++++++--
 src/input_common/sdl/sdl_impl.cpp             | 54 +++++++++----------
 3 files changed, 71 insertions(+), 34 deletions(-)

diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index 277b70e53..fb2ce2514 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -33,7 +33,7 @@ public:
     virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const {
         return {};
     }
-    virtual bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const {
+    virtual bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const {
         return {};
     }
 };
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 924f209c0..cc54b164d 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -698,16 +698,57 @@ void Controller_NPad::VibrateController(const std::vector<DeviceHandle>& vibrati
             continue;
         }
 
+        // Filter out vibrations with equivalent values to reduce unnecessary state changes.
+        if (vibration_values[i].amp_low ==
+                latest_vibration_values[npad_index][device_index].amp_low &&
+            vibration_values[i].amp_high ==
+                latest_vibration_values[npad_index][device_index].amp_high) {
+            continue;
+        }
+
+        // Filter out non-zero vibrations that are within 0.015625 absolute amplitude of each other.
+        if ((vibration_values[i].amp_low != 0.0f || vibration_values[i].amp_high != 0.0f) &&
+            (latest_vibration_values[npad_index][device_index].amp_low != 0.0f ||
+             latest_vibration_values[npad_index][device_index].amp_high != 0.0f) &&
+            (abs(vibration_values[i].amp_low -
+                 latest_vibration_values[npad_index][device_index].amp_low) < 0.015625f &&
+             abs(vibration_values[i].amp_high -
+                 latest_vibration_values[npad_index][device_index].amp_high) < 0.015625f)) {
+            continue;
+        }
+
         using namespace Settings::NativeButton;
         const auto& button_state = buttons[npad_index];
 
         // TODO: Vibrate left/right vibration motors independently if possible.
-        button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
-            vibration_values[i].amp_high * Settings::values.vibration_strength.GetValue() / 100,
+        const bool success = button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
             vibration_values[i].amp_low * Settings::values.vibration_strength.GetValue() / 100,
-            vibration_values[i].freq_high, vibration_values[i].freq_low);
+            vibration_values[i].freq_low,
+            vibration_values[i].amp_high * Settings::values.vibration_strength.GetValue() / 100,
+            vibration_values[i].freq_high);
 
-        latest_vibration_values[npad_index][device_index] = vibration_values[i];
+        if (success) {
+            switch (connected_controllers[npad_index].type) {
+            case NPadControllerType::None:
+                UNREACHABLE();
+                break;
+            case NPadControllerType::ProController:
+            case NPadControllerType::Handheld:
+            case NPadControllerType::JoyDual:
+                // Since we can't vibrate motors independently yet, we can reduce state changes by
+                // assigning all 3 device indices the current vibration value.
+                latest_vibration_values[npad_index][0] = vibration_values[i];
+                latest_vibration_values[npad_index][1] = vibration_values[i];
+                latest_vibration_values[npad_index][2] = vibration_values[i];
+                break;
+            case NPadControllerType::JoyLeft:
+            case NPadControllerType::JoyRight:
+            case NPadControllerType::Pokeball:
+            default:
+                latest_vibration_values[npad_index][device_index] = vibration_values[i];
+                break;
+            }
+        }
     }
 }
 
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 10883e2d9..18fb2ac5e 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -80,30 +80,24 @@ public:
         return static_cast<float>(state.axes.at(axis)) / (32767.0f * range);
     }
 
-    bool RumblePlay(f32 amp_low, f32 amp_high, u32 time) {
-        const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF);
-        const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF);
-        // Lower drastically the number of state changes
-        if (raw_amp_low >> 11 == last_state_rumble_low >> 11 &&
-            raw_amp_high >> 11 == last_state_rumble_high >> 11) {
-            if (raw_amp_low + raw_amp_high != 0 ||
-                last_state_rumble_low + last_state_rumble_high == 0) {
-                return false;
-            }
-        }
-        // Don't change state if last vibration was < 20ms
-        const auto now = std::chrono::system_clock::now();
-        if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_vibration) <
-            std::chrono::milliseconds(20)) {
-            return raw_amp_low + raw_amp_high == 0;
+    bool RumblePlay(u16 amp_low, u16 amp_high) {
+        using std::chrono::duration_cast;
+        using std::chrono::milliseconds;
+        using std::chrono::steady_clock;
+
+        // Prevent vibrations less than 10ms apart from each other.
+        if (duration_cast<milliseconds>(steady_clock::now() - last_vibration) < milliseconds(10)) {
+            return false;
+        };
+
+        last_vibration = steady_clock::now();
+
+        if (sdl_controller != nullptr) {
+            return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0;
+        } else if (sdl_joystick != nullptr) {
+            return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0;
         }
 
-        last_vibration = now;
-        last_state_rumble_low = raw_amp_low;
-        last_state_rumble_high = raw_amp_high;
-        if (sdl_joystick) {
-            SDL_JoystickRumble(sdl_joystick.get(), raw_amp_low, raw_amp_high, time);
-        }
         return false;
     }
 
@@ -172,13 +166,13 @@ private:
     } state;
     std::string guid;
     int port;
-    u16 last_state_rumble_high = 0;
-    u16 last_state_rumble_low = 0;
-    std::chrono::time_point<std::chrono::system_clock> last_vibration;
     std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
     std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
     mutable std::mutex mutex;
 
+    // This is the timepoint of the last vibration and is used to ensure vibrations are 10ms apart.
+    std::chrono::steady_clock::time_point last_vibration;
+
     // Motion is initialized without PID values as motion input is not aviable for SDL2
     MotionInput motion{0.0f, 0.0f, 0.0f};
 };
@@ -327,10 +321,12 @@ public:
         return joystick->GetButton(button);
     }
 
-    bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override {
-        const f32 new_amp_low = pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f));
-        const f32 new_amp_high = pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f));
-        return joystick->RumblePlay(new_amp_low, new_amp_high, 250);
+    bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
+        const u16 processed_amp_low =
+            static_cast<u16>(pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f)) * 0xFFFF);
+        const u16 processed_amp_high =
+            static_cast<u16>(pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f)) * 0xFFFF);
+        return joystick->RumblePlay(processed_amp_low, processed_amp_high);
     }
 
 private:

From 70f16f17220a23daead70e9f94f93d1c61d374a1 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 11 Oct 2020 08:35:40 -0400
Subject: [PATCH 21/37] hid: Stub IsVibrationDeviceMounted

- Used in Super Mario Odyssey
---
 src/core/hle/service/hid/hid.cpp | 23 ++++++++++++++++++++++-
 src/core/hle/service/hid/hid.h   |  1 +
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index b0390bdb2..89327cd86 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -249,7 +249,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
         {208, nullptr, "GetActualVibrationGcErmCommand"},
         {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
         {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
-        {211, nullptr, "IsVibrationDeviceMounted"},
+        {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
         {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
         {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
         {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
@@ -1129,6 +1129,27 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
     rb.Push(RESULT_SUCCESS);
 }
 
+void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    struct Parameters {
+        Controller_NPad::DeviceHandle vibration_device_handle{};
+        INSERT_PADDING_WORDS(1);
+        u64 applet_resource_user_id{};
+    };
+
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    LOG_WARNING(
+        Service_HID,
+        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+        parameters.vibration_device_handle.npad_type, parameters.vibration_device_handle.npad_id,
+        parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(RESULT_SUCCESS);
+    rb.Push(true);
+}
+
 void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 57bc93778..c8e4a4b55 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -134,6 +134,7 @@ private:
     void SendVibrationValues(Kernel::HLERequestContext& ctx);
     void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
     void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
+    void IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx);
     void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
     void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
     void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);

From 373408ae8c565cc401770e65776cae55a3545572 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 11 Oct 2020 11:25:17 -0400
Subject: [PATCH 22/37] controllers/npad: Send an empty vibration on
 destruction/deactivation

This stops all controllers from continuously vibrating when emulation is stopped.
---
 src/core/hle/service/hid/controllers/npad.cpp | 42 ++++++++++++-------
 src/core/hle/service/hid/controllers/npad.h   | 14 ++++---
 src/core/hle/service/hid/hid.cpp              |  4 +-
 3 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index cc54b164d..81725efbb 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -117,7 +117,10 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
 }
 
 Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
-Controller_NPad::~Controller_NPad() = default;
+
+Controller_NPad::~Controller_NPad() {
+    OnRelease();
+}
 
 void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
     const auto controller_type = connected_controllers[controller_idx].type;
@@ -274,7 +277,11 @@ void Controller_NPad::OnLoadInputDevices() {
     }
 }
 
-void Controller_NPad::OnRelease() {}
+void Controller_NPad::OnRelease() {
+    for (std::size_t index = 0; index < connected_controllers.size(); ++index) {
+        VibrateControllerAtIndex(index, {});
+    }
+}
 
 void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
     const auto controller_idx = NPadIdToIndex(npad_id);
@@ -667,8 +674,24 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode)
     }
 }
 
-void Controller_NPad::VibrateController(const std::vector<DeviceHandle>& vibration_device_handles,
-                                        const std::vector<VibrationValue>& vibration_values) {
+bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index,
+                                               const VibrationValue& vibration_value) {
+    if (!connected_controllers[npad_index].is_connected) {
+        return false;
+    }
+
+    using namespace Settings::NativeButton;
+    const auto& button_state = buttons[npad_index];
+
+    return button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
+        vibration_value.amp_low * Settings::values.vibration_strength.GetValue() / 100,
+        vibration_value.freq_low,
+        vibration_value.amp_high * Settings::values.vibration_strength.GetValue() / 100,
+        vibration_value.freq_high);
+}
+
+void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
+                                         const std::vector<VibrationValue>& vibration_values) {
     LOG_TRACE(Service_HID, "called");
 
     if (!Settings::values.vibration_enabled.GetValue() || !can_controllers_vibrate) {
@@ -717,17 +740,8 @@ void Controller_NPad::VibrateController(const std::vector<DeviceHandle>& vibrati
             continue;
         }
 
-        using namespace Settings::NativeButton;
-        const auto& button_state = buttons[npad_index];
-
         // TODO: Vibrate left/right vibration motors independently if possible.
-        const bool success = button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
-            vibration_values[i].amp_low * Settings::values.vibration_strength.GetValue() / 100,
-            vibration_values[i].freq_low,
-            vibration_values[i].amp_high * Settings::values.vibration_strength.GetValue() / 100,
-            vibration_values[i].freq_high);
-
-        if (success) {
+        if (VibrateControllerAtIndex(npad_index, vibration_values[i])) {
             switch (connected_controllers[npad_index].type) {
             case NPadControllerType::None:
                 UNREACHABLE();
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index c1b19103a..4dc2a974d 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -110,10 +110,10 @@ public:
     static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
 
     struct VibrationValue {
-        f32 amp_low;
-        f32 freq_low;
-        f32 amp_high;
-        f32 freq_high;
+        f32 amp_low{0.0f};
+        f32 freq_low{160.0f};
+        f32 amp_high{0.0f};
+        f32 freq_high{320.0f};
     };
     static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size");
 
@@ -148,8 +148,10 @@ public:
 
     void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode);
 
-    void VibrateController(const std::vector<DeviceHandle>& vibration_device_handles,
-                           const std::vector<VibrationValue>& vibration_values);
+    bool VibrateControllerAtIndex(std::size_t npad_index, const VibrationValue& vibration_value);
+
+    void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
+                            const std::vector<VibrationValue>& vibration_values);
 
     VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const;
 
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 89327cd86..878f20bd2 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1022,7 +1022,7 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
     const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .VibrateController({parameters.vibration_device_handle}, {parameters.vibration_value});
+        .VibrateControllers({parameters.vibration_device_handle}, {parameters.vibration_value});
 
     LOG_DEBUG(Service_HID,
               "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -1100,7 +1100,7 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
     std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size());
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .VibrateController(vibration_device_handles, vibration_values);
+        .VibrateControllers(vibration_device_handles, vibration_values);
 
     LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 

From 92fa5257c762f631c64cbc8a60870af7deaf2ead Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Thu, 15 Oct 2020 14:35:35 -0400
Subject: [PATCH 23/37] hid: Mark Begin/EndPermitVibrationSession as stubs

The implementation of these commands seem incomplete and causes rumble in Super Mario Party to stop working since only EndPermitVibrationSession is called. Thus, these are better off being marked as a stub until this can be investigated more thoroughly.
---
 src/core/hle/service/hid/controllers/npad.cpp | 10 +---------
 src/core/hle/service/hid/controllers/npad.h   |  3 ---
 src/core/hle/service/hid/hid.cpp              |  9 +++------
 3 files changed, 4 insertions(+), 18 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 81725efbb..1fc06ef3f 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -694,7 +694,7 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat
                                          const std::vector<VibrationValue>& vibration_values) {
     LOG_TRACE(Service_HID, "called");
 
-    if (!Settings::values.vibration_enabled.GetValue() || !can_controllers_vibrate) {
+    if (!Settings::values.vibration_enabled.GetValue()) {
         return;
     }
 
@@ -924,14 +924,6 @@ void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_prot
     unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
 }
 
-void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
-    can_controllers_vibrate = can_vibrate;
-}
-
-bool Controller_NPad::IsVibrationEnabled() const {
-    return can_controllers_vibrate;
-}
-
 void Controller_NPad::ClearAllConnectedControllers() {
     for (auto& controller : connected_controllers) {
         if (controller.is_connected && controller.type != NPadControllerType::None) {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 4dc2a974d..576ef1558 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -173,8 +173,6 @@ public:
     LedPattern GetLedPattern(u32 npad_id);
     bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
     void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
-    void SetVibrationEnabled(bool can_vibrate);
-    bool IsVibrationEnabled() const;
     void ClearAllConnectedControllers();
     void DisconnectAllConnectedControllers();
     void ConnectAllDisconnectedControllers();
@@ -416,7 +414,6 @@ private:
     std::array<ControllerHolder, 10> connected_controllers{};
     std::array<bool, 10> unintended_home_button_input_protection{};
     GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
-    bool can_controllers_vibrate{true};
     bool sixaxis_sensors_enabled{true};
     bool sixaxis_at_rest{true};
     std::array<ControllerPad, 10> npad_pad_states{};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 878f20bd2..e88f30d6a 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1112,18 +1112,15 @@ void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true);
-
-    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+    LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
+                applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
 
 void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
-    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false);
-
-    LOG_DEBUG(Service_HID, "called");
+    LOG_WARNING(Service_HID, "(STUBBED) called");
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);

From d6a41cfc21a75349ca79e73da5ca1dcecd1af901 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Fri, 16 Oct 2020 11:55:45 -0400
Subject: [PATCH 24/37] settings: Remove global vibration strength modifier

This will be replaced in favor of per-player vibration strength modifiers.
---
 src/core/hle/service/hid/controllers/npad.cpp | 4 +---
 src/core/settings.cpp                         | 1 -
 src/core/settings.h                           | 1 -
 src/yuzu/applets/controller.cpp               | 2 --
 src/yuzu/configuration/config.cpp             | 4 ----
 src/yuzu/configuration/configure_input.cpp    | 2 --
 src/yuzu_cmd/config.cpp                       | 2 --
 src/yuzu_cmd/default_ini.h                    | 3 ---
 src/yuzu_tester/config.cpp                    | 1 -
 9 files changed, 1 insertion(+), 19 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 1fc06ef3f..ba20d3f59 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -684,9 +684,7 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index,
     const auto& button_state = buttons[npad_index];
 
     return button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
-        vibration_value.amp_low * Settings::values.vibration_strength.GetValue() / 100,
-        vibration_value.freq_low,
-        vibration_value.amp_high * Settings::values.vibration_strength.GetValue() / 100,
+        vibration_value.amp_low, vibration_value.freq_low, vibration_value.amp_high,
         vibration_value.freq_high);
 }
 
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 6e39aebb5..aadbc3932 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -150,7 +150,6 @@ void RestoreGlobalState() {
     values.players.SetGlobal(true);
     values.use_docked_mode.SetGlobal(true);
     values.vibration_enabled.SetGlobal(true);
-    values.vibration_strength.SetGlobal(true);
     values.motion_enabled.SetGlobal(true);
 }
 
diff --git a/src/core/settings.h b/src/core/settings.h
index 496f47747..edd2a00ca 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -170,7 +170,6 @@ struct Values {
     Setting<bool> use_docked_mode;
 
     Setting<bool> vibration_enabled;
-    Setting<int> vibration_strength;
 
     Setting<bool> motion_enabled;
     std::string motion_device;
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index 196b4f163..0fc713a6e 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -266,7 +266,6 @@ void QtControllerSelectorDialog::ApplyConfiguration() {
     OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue());
 
     Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
-    Settings::values.vibration_strength.SetValue(ui->vibrationSpin->value());
     Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
 }
 
@@ -283,7 +282,6 @@ void QtControllerSelectorDialog::LoadConfiguration() {
     UpdateDockedState(Settings::values.players.GetValue()[8].connected);
 
     ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
-    ui->vibrationSpin->setValue(Settings::values.vibration_strength.GetValue());
     ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
 }
 
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 820ef4098..296c58f58 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -493,8 +493,6 @@ void Config::ReadControlValues() {
     ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), false);
     ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"),
                       true);
-    ReadSettingGlobal(Settings::values.vibration_strength, QStringLiteral("vibration_strength"),
-                      100);
     ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"), true);
 
     qt_config->endGroup();
@@ -1152,8 +1150,6 @@ void Config::SaveControlValues() {
     WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
     WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled,
                        true);
-    WriteSettingGlobal(QStringLiteral("vibration_strength"), Settings::values.vibration_strength,
-                       100);
     WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true);
     WriteSetting(QStringLiteral("motion_device"),
                  QString::fromStdString(Settings::values.motion_device),
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 84df547b9..9a4de4c5d 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -186,7 +186,6 @@ void ConfigureInput::ApplyConfiguration() {
     OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue());
 
     Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
-    Settings::values.vibration_strength.SetValue(ui->vibrationSpin->value());
     Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
 }
 
@@ -207,7 +206,6 @@ void ConfigureInput::LoadConfiguration() {
     UpdateDockedState(Settings::values.players.GetValue()[8].connected);
 
     ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
-    ui->vibrationSpin->setValue(Settings::values.vibration_strength.GetValue());
     ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
 }
 
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 209350837..feee02fcd 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -290,8 +290,6 @@ void Config::ReadValues() {
 
     Settings::values.vibration_enabled.SetValue(
         sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true));
-    Settings::values.vibration_strength.SetValue(
-        sdl2_config->GetInteger("ControlsGeneral", "vibration_strength", 100));
     Settings::values.motion_enabled.SetValue(
         sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true));
     Settings::values.touchscreen.enabled =
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 53057c01c..b6f6a3bb0 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -69,9 +69,6 @@ rstick=
 # 0: Disabled, 1 (default): Enabled
 vibration_enabled=
 
-# Vibration strength percentage (Default: 100)
-vibration_strength=
-
 # for motion input, the following devices are available:
 #  - "motion_emu" (default) for emulating motion input from mouse input. Required parameters:
 #      - "update_period": update period in milliseconds (default to 100)
diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp
index 437302520..3a8a333f0 100644
--- a/src/yuzu_tester/config.cpp
+++ b/src/yuzu_tester/config.cpp
@@ -76,7 +76,6 @@ void Config::ReadValues() {
     }
 
     Settings::values.vibration_enabled.SetValue(true);
-    Settings::values.vibration_strength.SetValue(100);
     Settings::values.motion_enabled.SetValue(true);
     Settings::values.touchscreen.enabled = "";
     Settings::values.touchscreen.device = "";

From 38110dd485e329fa39e2e4c02b91a89dfebcbc88 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sat, 17 Oct 2020 09:38:12 -0400
Subject: [PATCH 25/37] configure_input: Add per-player vibration

Allows for enabling and modifying vibration and vibration strength per player.
Also adds a toggle for enabling/disabling accurate vibrations.

Co-authored-by: Its-Rei <kupfel@gmail.com>
---
 dist/qt_themes/qdarkstyle/style.qss           |  11 +-
 .../qdarkstyle_midnight_blue/style.qss        |  12 +-
 src/core/hle/service/hid/controllers/npad.cpp |  13 +-
 src/core/settings.h                           |   1 +
 src/input_common/settings.h                   |   3 +
 src/yuzu/CMakeLists.txt                       |   3 +
 src/yuzu/applets/controller.cpp               |  16 +
 src/yuzu/applets/controller.h                 |   3 +
 src/yuzu/applets/controller.ui                |  18 +-
 src/yuzu/configuration/config.cpp             |  16 +
 src/yuzu/configuration/configure_input.cpp    |   4 +
 src/yuzu/configuration/configure_input.ui     |  22 +-
 .../configuration/configure_vibration.cpp     |  66 +++
 src/yuzu/configuration/configure_vibration.h  |  40 ++
 src/yuzu/configuration/configure_vibration.ui | 546 ++++++++++++++++++
 src/yuzu_cmd/config.cpp                       |   2 +
 src/yuzu_cmd/default_ini.h                    |   4 +
 src/yuzu_tester/config.cpp                    |   1 +
 18 files changed, 751 insertions(+), 30 deletions(-)
 create mode 100644 src/yuzu/configuration/configure_vibration.cpp
 create mode 100644 src/yuzu/configuration/configure_vibration.h
 create mode 100644 src/yuzu/configuration/configure_vibration.ui

diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index aca6531ac..2a1e8ddeb 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -1293,15 +1293,24 @@ QPushButton#buttonRefreshDevices {
 
 QSpinBox#spinboxLStickRange,
 QSpinBox#spinboxRStickRange,
-QSpinBox#vibrationSpin {
+QSpinBox#vibrationSpinPlayer1,
+QSpinBox#vibrationSpinPlayer2,
+QSpinBox#vibrationSpinPlayer3,
+QSpinBox#vibrationSpinPlayer4,
+QSpinBox#vibrationSpinPlayer5,
+QSpinBox#vibrationSpinPlayer6,
+QSpinBox#vibrationSpinPlayer7,
+QSpinBox#vibrationSpinPlayer8 {
     min-width: 68px;
 }
 
+QDialog#ConfigureVibration QGroupBox::indicator,
 QGroupBox#motionGroup::indicator,
 QGroupBox#vibrationGroup::indicator {
     margin-left: 0px;
 }
 
+QDialog#ConfigureVibration QGroupBox::title,
 QGroupBox#motionGroup::title,
 QGroupBox#vibrationGroup::title {
     spacing: 2px;
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
index ad032a966..70e540b06 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -2200,21 +2200,31 @@ QPushButton#buttonRefreshDevices {
 
 QSpinBox#spinboxLStickRange,
 QSpinBox#spinboxRStickRange,
-QSpinBox#vibrationSpin {
+QSpinBox#vibrationSpinPlayer1,
+QSpinBox#vibrationSpinPlayer2,
+QSpinBox#vibrationSpinPlayer3,
+QSpinBox#vibrationSpinPlayer4,
+QSpinBox#vibrationSpinPlayer5,
+QSpinBox#vibrationSpinPlayer6,
+QSpinBox#vibrationSpinPlayer7,
+QSpinBox#vibrationSpinPlayer8 {
   min-width: 68px;
 }
 
+QDialog#ConfigureVibration QGroupBox::indicator,
 QGroupBox#motionGroup::indicator,
 QGroupBox#vibrationGroup::indicator {
   margin-left: 0px;
 }
 
+QDialog#ConfigureVibration QGroupBox,
 QWidget#bottomPerGameInput QGroupBox#motionGroup,
 QWidget#bottomPerGameInput QGroupBox#vibrationGroup,
 QWidget#bottomPerGameInput QGroupBox#inputConfigGroup {
   padding: 0px;
 }
 
+QDialog#ConfigureVibration QGroupBox::title,
 QGroupBox#motionGroup::title,
 QGroupBox#vibrationGroup::title {
   spacing: 2px;
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ba20d3f59..dc9954377 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -680,11 +680,19 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index,
         return false;
     }
 
+    const auto& player = Settings::values.players.GetValue()[npad_index];
+
+    if (!player.vibration_enabled) {
+        return false;
+    }
+
     using namespace Settings::NativeButton;
     const auto& button_state = buttons[npad_index];
 
     return button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
-        vibration_value.amp_low, vibration_value.freq_low, vibration_value.amp_high,
+        std::min(vibration_value.amp_low * player.vibration_strength / 100.0f, 1.0f),
+        vibration_value.freq_low,
+        std::min(vibration_value.amp_high * player.vibration_strength / 100.0f, 1.0f),
         vibration_value.freq_high);
 }
 
@@ -728,7 +736,8 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat
         }
 
         // Filter out non-zero vibrations that are within 0.015625 absolute amplitude of each other.
-        if ((vibration_values[i].amp_low != 0.0f || vibration_values[i].amp_high != 0.0f) &&
+        if (!Settings::values.enable_accurate_vibrations.GetValue() &&
+            (vibration_values[i].amp_low != 0.0f || vibration_values[i].amp_high != 0.0f) &&
             (latest_vibration_values[npad_index][device_index].amp_low != 0.0f ||
              latest_vibration_values[npad_index][device_index].amp_high != 0.0f) &&
             (abs(vibration_values[i].amp_low -
diff --git a/src/core/settings.h b/src/core/settings.h
index edd2a00ca..476c3fdf3 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -170,6 +170,7 @@ struct Values {
     Setting<bool> use_docked_mode;
 
     Setting<bool> vibration_enabled;
+    Setting<bool> enable_accurate_vibrations;
 
     Setting<bool> motion_enabled;
     std::string motion_device;
diff --git a/src/input_common/settings.h b/src/input_common/settings.h
index f52d28540..2763ed991 100644
--- a/src/input_common/settings.h
+++ b/src/input_common/settings.h
@@ -332,6 +332,9 @@ struct PlayerInput {
     AnalogsRaw analogs;
     MotionRaw motions;
 
+    bool vibration_enabled;
+    int vibration_strength;
+
     u32 body_color_left;
     u32 body_color_right;
     u32 button_color_left;
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 22fe0a2a6..bf1fae9fa 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -105,6 +105,9 @@ add_executable(yuzu
     configuration/configure_ui.cpp
     configuration/configure_ui.h
     configuration/configure_ui.ui
+    configuration/configure_vibration.cpp
+    configuration/configure_vibration.h
+    configuration/configure_vibration.ui
     configuration/configure_web.cpp
     configuration/configure_web.h
     configuration/configure_web.ui
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index 0fc713a6e..c5e671309 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -14,6 +14,7 @@
 #include "ui_controller.h"
 #include "yuzu/applets/controller.h"
 #include "yuzu/configuration/configure_input_dialog.h"
+#include "yuzu/configuration/configure_vibration.h"
 #include "yuzu/main.h"
 
 namespace {
@@ -223,6 +224,9 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
         }
     }
 
+    connect(ui->vibrationButton, &QPushButton::clicked, this,
+            &QtControllerSelectorDialog::CallConfigureVibrationDialog);
+
     connect(ui->inputConfigButton, &QPushButton::clicked, this,
             &QtControllerSelectorDialog::CallConfigureInputDialog);
 
@@ -285,6 +289,18 @@ void QtControllerSelectorDialog::LoadConfiguration() {
     ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
 }
 
+void QtControllerSelectorDialog::CallConfigureVibrationDialog() {
+    ConfigureVibration dialog(this);
+
+    dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
+                          Qt::WindowSystemMenuHint);
+    dialog.setWindowModality(Qt::WindowModal);
+
+    if (dialog.exec() == QDialog::Accepted) {
+        dialog.ApplyConfiguration();
+    }
+}
+
 void QtControllerSelectorDialog::CallConfigureInputDialog() {
     const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
 
diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h
index 8fefecf05..a2ce03c8f 100644
--- a/src/yuzu/applets/controller.h
+++ b/src/yuzu/applets/controller.h
@@ -42,6 +42,9 @@ private:
     // Loads the current input configuration into the frontend applet.
     void LoadConfiguration();
 
+    // Initializes the "Configure Vibration" Dialog.
+    void CallConfigureVibrationDialog();
+
     // Initializes the "Configure Input" Dialog.
     void CallConfigureInputDialog();
 
diff --git a/src/yuzu/applets/controller.ui b/src/yuzu/applets/controller.ui
index cc27b8ef4..8e571ba8f 100644
--- a/src/yuzu/applets/controller.ui
+++ b/src/yuzu/applets/controller.ui
@@ -2329,11 +2329,11 @@
              <number>3</number>
             </property>
             <item>
-             <widget class="QSpinBox" name="vibrationSpin">
+             <widget class="QPushButton" name="vibrationButton">
               <property name="minimumSize">
                <size>
                 <width>68</width>
-                <height>21</height>
+                <height>0</height>
                </size>
               </property>
               <property name="maximumSize">
@@ -2342,17 +2342,11 @@
                 <height>16777215</height>
                </size>
               </property>
-              <property name="suffix">
-               <string>%</string>
+              <property name="styleSheet">
+               <string notr="true">min-width: 68px;</string>
               </property>
-              <property name="minimum">
-               <number>1</number>
-              </property>
-              <property name="maximum">
-               <number>100</number>
-              </property>
-              <property name="value">
-               <number>100</number>
+              <property name="text">
+               <string>Configure</string>
               </property>
              </widget>
             </item>
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 296c58f58..7f66f29aa 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -300,6 +300,14 @@ void Config::ReadPlayerValue(std::size_t player_index) {
                         static_cast<u8>(Settings::ControllerType::ProController))
                 .toUInt());
 
+        player.vibration_enabled =
+            qt_config->value(QStringLiteral("%1vibration_enabled").arg(player_prefix), true)
+                .toBool();
+
+        player.vibration_strength =
+            qt_config->value(QStringLiteral("%1vibration_strength").arg(player_prefix), 100)
+                .toInt();
+
         player.body_color_left = qt_config
                                      ->value(QStringLiteral("%1body_color_left").arg(player_prefix),
                                              Settings::JOYCON_BODY_NEON_BLUE)
@@ -493,6 +501,8 @@ void Config::ReadControlValues() {
     ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), false);
     ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"),
                       true);
+    ReadSettingGlobal(Settings::values.enable_accurate_vibrations,
+                      QStringLiteral("enable_accurate_vibrations"), false);
     ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"), true);
 
     qt_config->endGroup();
@@ -983,6 +993,10 @@ void Config::SavePlayerValue(std::size_t player_index) {
 
     if (!player_prefix.isEmpty()) {
         WriteSetting(QStringLiteral("%1connected").arg(player_prefix), player.connected, false);
+        WriteSetting(QStringLiteral("%1vibration_enabled").arg(player_prefix),
+                     player.vibration_enabled, true);
+        WriteSetting(QStringLiteral("%1vibration_strength").arg(player_prefix),
+                     player.vibration_strength, 100);
         WriteSetting(QStringLiteral("%1body_color_left").arg(player_prefix), player.body_color_left,
                      Settings::JOYCON_BODY_NEON_BLUE);
         WriteSetting(QStringLiteral("%1body_color_right").arg(player_prefix),
@@ -1150,6 +1164,8 @@ void Config::SaveControlValues() {
     WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
     WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled,
                        true);
+    WriteSettingGlobal(QStringLiteral("enable_accurate_vibrations"),
+                       Settings::values.enable_accurate_vibrations, false);
     WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true);
     WriteSetting(QStringLiteral("motion_device"),
                  QString::fromStdString(Settings::values.motion_device),
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 9a4de4c5d..600cc03ae 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -23,6 +23,7 @@
 #include "yuzu/configuration/configure_motion_touch.h"
 #include "yuzu/configuration/configure_mouse_advanced.h"
 #include "yuzu/configuration/configure_touchscreen_advanced.h"
+#include "yuzu/configuration/configure_vibration.h"
 #include "yuzu/configuration/input_profiles.h"
 
 namespace {
@@ -156,6 +157,9 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
                 CallConfigureDialog<ConfigureMotionTouch>(*this, input_subsystem);
             });
 
+    connect(ui->vibrationButton, &QPushButton::clicked,
+            [this] { CallConfigureDialog<ConfigureVibration>(*this); });
+
     connect(ui->motionButton, &QPushButton::clicked, [this, input_subsystem] {
         CallConfigureDialog<ConfigureMotionTouch>(*this, input_subsystem);
     });
diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index cbd67d4c7..2707025e7 100644
--- a/src/yuzu/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>700</width>
+    <width>680</width>
     <height>540</height>
    </rect>
   </property>
@@ -195,11 +195,11 @@
           <number>3</number>
          </property>
          <item>
-          <widget class="QSpinBox" name="vibrationSpin">
+          <widget class="QPushButton" name="vibrationButton">
            <property name="minimumSize">
             <size>
              <width>68</width>
-             <height>21</height>
+             <height>0</height>
             </size>
            </property>
            <property name="maximumSize">
@@ -208,17 +208,11 @@
              <height>16777215</height>
             </size>
            </property>
-           <property name="suffix">
-            <string>%</string>
+           <property name="styleSheet">
+            <string notr="true">min-width: 68px;</string>
            </property>
-           <property name="minimum">
-            <number>1</number>
-           </property>
-           <property name="maximum">
-            <number>100</number>
-           </property>
-           <property name="value">
-            <number>100</number>
+           <property name="text">
+            <string>Configure</string>
            </property>
           </widget>
          </item>
@@ -272,7 +266,7 @@
        </widget>
       </item>
       <item alignment="Qt::AlignVCenter">
-       <widget class="QWidget" name="widget" native="true">
+       <widget class="QWidget" name="connectedControllers" native="true">
         <layout class="QGridLayout" name="gridLayout_2">
          <property name="leftMargin">
           <number>5</number>
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp
new file mode 100644
index 000000000..1c68f28f3
--- /dev/null
+++ b/src/yuzu/configuration/configure_vibration.cpp
@@ -0,0 +1,66 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/settings.h"
+#include "ui_configure_vibration.h"
+#include "yuzu/configuration/configure_vibration.h"
+
+ConfigureVibration::ConfigureVibration(QWidget* parent)
+    : QDialog(parent), ui(std::make_unique<Ui::ConfigureVibration>()) {
+    ui->setupUi(this);
+
+    vibration_groupboxes = {
+        ui->vibrationGroupPlayer1, ui->vibrationGroupPlayer2, ui->vibrationGroupPlayer3,
+        ui->vibrationGroupPlayer4, ui->vibrationGroupPlayer5, ui->vibrationGroupPlayer6,
+        ui->vibrationGroupPlayer7, ui->vibrationGroupPlayer8,
+    };
+
+    vibration_spinboxes = {
+        ui->vibrationSpinPlayer1, ui->vibrationSpinPlayer2, ui->vibrationSpinPlayer3,
+        ui->vibrationSpinPlayer4, ui->vibrationSpinPlayer5, ui->vibrationSpinPlayer6,
+        ui->vibrationSpinPlayer7, ui->vibrationSpinPlayer8,
+    };
+
+    const auto& players = Settings::values.players.GetValue();
+
+    for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
+        vibration_groupboxes[i]->setChecked(players[i].vibration_enabled);
+        vibration_spinboxes[i]->setValue(players[i].vibration_strength);
+    }
+
+    ui->checkBoxAccurateVibration->setChecked(
+        Settings::values.enable_accurate_vibrations.GetValue());
+
+    if (!Settings::IsConfiguringGlobal()) {
+        ui->checkBoxAccurateVibration->setDisabled(true);
+    }
+
+    RetranslateUI();
+}
+
+ConfigureVibration::~ConfigureVibration() = default;
+
+void ConfigureVibration::ApplyConfiguration() {
+    auto& players = Settings::values.players.GetValue();
+
+    for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
+        players[i].vibration_enabled = vibration_groupboxes[i]->isChecked();
+        players[i].vibration_strength = vibration_spinboxes[i]->value();
+    }
+
+    Settings::values.enable_accurate_vibrations.SetValue(
+        ui->checkBoxAccurateVibration->isChecked());
+}
+
+void ConfigureVibration::changeEvent(QEvent* event) {
+    if (event->type() == QEvent::LanguageChange) {
+        RetranslateUI();
+    }
+
+    QDialog::changeEvent(event);
+}
+
+void ConfigureVibration::RetranslateUI() {
+    ui->retranslateUi(this);
+}
diff --git a/src/yuzu/configuration/configure_vibration.h b/src/yuzu/configuration/configure_vibration.h
new file mode 100644
index 000000000..37bbc2653
--- /dev/null
+++ b/src/yuzu/configuration/configure_vibration.h
@@ -0,0 +1,40 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <QDialog>
+
+class QGroupBox;
+class QSpinBox;
+
+namespace Ui {
+class ConfigureVibration;
+}
+
+class ConfigureVibration : public QDialog {
+    Q_OBJECT
+
+public:
+    explicit ConfigureVibration(QWidget* parent);
+    ~ConfigureVibration() override;
+
+    void ApplyConfiguration();
+
+private:
+    void changeEvent(QEvent* event) override;
+    void RetranslateUI();
+
+    std::unique_ptr<Ui::ConfigureVibration> ui;
+
+    static constexpr std::size_t NUM_PLAYERS = 8;
+
+    // Groupboxes encapsulating the vibration strength spinbox.
+    std::array<QGroupBox*, NUM_PLAYERS> vibration_groupboxes;
+
+    // Spinboxes representing the vibration strength percentage.
+    std::array<QSpinBox*, NUM_PLAYERS> vibration_spinboxes;
+};
diff --git a/src/yuzu/configuration/configure_vibration.ui b/src/yuzu/configuration/configure_vibration.ui
new file mode 100644
index 000000000..efdf317a9
--- /dev/null
+++ b/src/yuzu/configuration/configure_vibration.ui
@@ -0,0 +1,546 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureVibration</class>
+ <widget class="QDialog" name="ConfigureVibration">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>364</width>
+    <height>242</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Configure Vibration</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true"/>
+  </property>
+  <layout class="QVBoxLayout">
+   <item>
+    <widget class="QGroupBox" name="vibrationStrengthGroup">
+     <property name="title">
+      <string>Vibration</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0">
+      <property name="leftMargin">
+       <number>9</number>
+      </property>
+      <property name="topMargin">
+       <number>9</number>
+      </property>
+      <property name="rightMargin">
+       <number>9</number>
+      </property>
+      <property name="bottomMargin">
+       <number>9</number>
+      </property>
+      <item>
+       <widget class="QWidget" name="player14Widget" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QGroupBox" name="vibrationGroupPlayer1">
+           <property name="title">
+            <string>Player 1</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_8">
+            <property name="leftMargin">
+             <number>3</number>
+            </property>
+            <property name="topMargin">
+             <number>3</number>
+            </property>
+            <property name="rightMargin">
+             <number>3</number>
+            </property>
+            <property name="bottomMargin">
+             <number>3</number>
+            </property>
+            <item>
+             <widget class="QSpinBox" name="vibrationSpinPlayer1">
+              <property name="minimumSize">
+               <size>
+                <width>68</width>
+                <height>21</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>68</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="suffix">
+               <string>%</string>
+              </property>
+              <property name="minimum">
+               <number>1</number>
+              </property>
+              <property name="maximum">
+               <number>150</number>
+              </property>
+              <property name="value">
+               <number>100</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QGroupBox" name="vibrationGroupPlayer2">
+           <property name="title">
+            <string>Player 2</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_9">
+            <property name="leftMargin">
+             <number>3</number>
+            </property>
+            <property name="topMargin">
+             <number>3</number>
+            </property>
+            <property name="rightMargin">
+             <number>3</number>
+            </property>
+            <property name="bottomMargin">
+             <number>3</number>
+            </property>
+            <item>
+             <widget class="QSpinBox" name="vibrationSpinPlayer2">
+              <property name="minimumSize">
+               <size>
+                <width>68</width>
+                <height>21</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>68</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="suffix">
+               <string>%</string>
+              </property>
+              <property name="minimum">
+               <number>1</number>
+              </property>
+              <property name="maximum">
+               <number>150</number>
+              </property>
+              <property name="value">
+               <number>100</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QGroupBox" name="vibrationGroupPlayer3">
+           <property name="title">
+            <string>Player 3</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_10">
+            <property name="leftMargin">
+             <number>3</number>
+            </property>
+            <property name="topMargin">
+             <number>3</number>
+            </property>
+            <property name="rightMargin">
+             <number>3</number>
+            </property>
+            <property name="bottomMargin">
+             <number>3</number>
+            </property>
+            <item>
+             <widget class="QSpinBox" name="vibrationSpinPlayer3">
+              <property name="minimumSize">
+               <size>
+                <width>68</width>
+                <height>21</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>68</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="suffix">
+               <string>%</string>
+              </property>
+              <property name="minimum">
+               <number>1</number>
+              </property>
+              <property name="maximum">
+               <number>150</number>
+              </property>
+              <property name="value">
+               <number>100</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QGroupBox" name="vibrationGroupPlayer4">
+           <property name="title">
+            <string>Player 4</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_11">
+            <property name="leftMargin">
+             <number>3</number>
+            </property>
+            <property name="topMargin">
+             <number>3</number>
+            </property>
+            <property name="rightMargin">
+             <number>3</number>
+            </property>
+            <property name="bottomMargin">
+             <number>3</number>
+            </property>
+            <item>
+             <widget class="QSpinBox" name="vibrationSpinPlayer4">
+              <property name="minimumSize">
+               <size>
+                <width>68</width>
+                <height>21</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>68</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="suffix">
+               <string>%</string>
+              </property>
+              <property name="minimum">
+               <number>1</number>
+              </property>
+              <property name="maximum">
+               <number>150</number>
+              </property>
+              <property name="value">
+               <number>100</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="player58Widget" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout_6">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QGroupBox" name="vibrationGroupPlayer7">
+           <property name="title">
+            <string>Player 5</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_14">
+            <property name="leftMargin">
+             <number>3</number>
+            </property>
+            <property name="topMargin">
+             <number>3</number>
+            </property>
+            <property name="rightMargin">
+             <number>3</number>
+            </property>
+            <property name="bottomMargin">
+             <number>3</number>
+            </property>
+            <item>
+             <widget class="QSpinBox" name="vibrationSpinPlayer7">
+              <property name="minimumSize">
+               <size>
+                <width>68</width>
+                <height>21</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>68</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="suffix">
+               <string>%</string>
+              </property>
+              <property name="minimum">
+               <number>1</number>
+              </property>
+              <property name="maximum">
+               <number>150</number>
+              </property>
+              <property name="value">
+               <number>100</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QGroupBox" name="vibrationGroupPlayer8">
+           <property name="title">
+            <string>Player 6</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_15">
+            <property name="leftMargin">
+             <number>3</number>
+            </property>
+            <property name="topMargin">
+             <number>3</number>
+            </property>
+            <property name="rightMargin">
+             <number>3</number>
+            </property>
+            <property name="bottomMargin">
+             <number>3</number>
+            </property>
+            <item>
+             <widget class="QSpinBox" name="vibrationSpinPlayer8">
+              <property name="minimumSize">
+               <size>
+                <width>68</width>
+                <height>21</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>68</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="suffix">
+               <string>%</string>
+              </property>
+              <property name="minimum">
+               <number>1</number>
+              </property>
+              <property name="maximum">
+               <number>150</number>
+              </property>
+              <property name="value">
+               <number>100</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QGroupBox" name="vibrationGroupPlayer5">
+           <property name="title">
+            <string>Player 7</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_12">
+            <property name="leftMargin">
+             <number>3</number>
+            </property>
+            <property name="topMargin">
+             <number>3</number>
+            </property>
+            <property name="rightMargin">
+             <number>3</number>
+            </property>
+            <property name="bottomMargin">
+             <number>3</number>
+            </property>
+            <item>
+             <widget class="QSpinBox" name="vibrationSpinPlayer5">
+              <property name="minimumSize">
+               <size>
+                <width>68</width>
+                <height>21</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>68</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="suffix">
+               <string>%</string>
+              </property>
+              <property name="minimum">
+               <number>1</number>
+              </property>
+              <property name="maximum">
+               <number>150</number>
+              </property>
+              <property name="value">
+               <number>100</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QGroupBox" name="vibrationGroupPlayer6">
+           <property name="title">
+            <string>Player 8</string>
+           </property>
+           <property name="checkable">
+            <bool>true</bool>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_13">
+            <property name="leftMargin">
+             <number>3</number>
+            </property>
+            <property name="topMargin">
+             <number>3</number>
+            </property>
+            <property name="rightMargin">
+             <number>3</number>
+            </property>
+            <property name="bottomMargin">
+             <number>3</number>
+            </property>
+            <item>
+             <widget class="QSpinBox" name="vibrationSpinPlayer6">
+              <property name="minimumSize">
+               <size>
+                <width>68</width>
+                <height>21</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>68</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="suffix">
+               <string>%</string>
+              </property>
+              <property name="minimum">
+               <number>1</number>
+              </property>
+              <property name="maximum">
+               <number>150</number>
+              </property>
+              <property name="value">
+               <number>100</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="vibrationSettingsGroup">
+     <property name="title">
+      <string>Settings</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <item>
+       <widget class="QCheckBox" name="checkBoxAccurateVibration">
+        <property name="text">
+         <string>Enable Accurate Vibration</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="spacerVibration">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>167</width>
+       <height>55</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBoxVibration">
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBoxVibration</sender>
+   <signal>accepted()</signal>
+   <receiver>ConfigureVibration</receiver>
+   <slot>accept()</slot>
+  </connection>
+  <connection>
+   <sender>buttonBoxVibration</sender>
+   <signal>rejected()</signal>
+   <receiver>ConfigureVibration</receiver>
+   <slot>reject()</slot>
+  </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index feee02fcd..e1adbbf2b 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -290,6 +290,8 @@ void Config::ReadValues() {
 
     Settings::values.vibration_enabled.SetValue(
         sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true));
+    Settings::values.enable_accurate_vibrations.SetValue(
+        sdl2_config->GetBoolean("ControlsGeneral", "enable_accurate_vibrations", false));
     Settings::values.motion_enabled.SetValue(
         sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true));
     Settings::values.touchscreen.enabled =
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index b6f6a3bb0..bcbbcd4ca 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -69,6 +69,10 @@ rstick=
 # 0: Disabled, 1 (default): Enabled
 vibration_enabled=
 
+# Whether to enable or disable accurate vibrations
+# 0 (default): Disabled, 1: Enabled
+enable_accurate_vibrations=
+
 # for motion input, the following devices are available:
 #  - "motion_emu" (default) for emulating motion input from mouse input. Required parameters:
 #      - "update_period": update period in milliseconds (default to 100)
diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp
index 3a8a333f0..b6cdc7c1c 100644
--- a/src/yuzu_tester/config.cpp
+++ b/src/yuzu_tester/config.cpp
@@ -76,6 +76,7 @@ void Config::ReadValues() {
     }
 
     Settings::values.vibration_enabled.SetValue(true);
+    Settings::values.enable_accurate_vibrations.SetValue(false);
     Settings::values.motion_enabled.SetValue(true);
     Settings::values.touchscreen.enabled = "";
     Settings::values.touchscreen.device = "";

From e9e1876e821b8bd1bb5c8254ec93e2cc479e16dd Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Tue, 20 Oct 2020 13:55:25 -0400
Subject: [PATCH 26/37] input_common: Add VibrationDevice and
 VibrationDeviceFactory

A vibration device is an input device that returns an unsigned byte as status.
It represents whether the vibration device supports vibration or not.
If the status returns 1, it supports vibration. Otherwise, it does not support vibration.
---
 src/core/frontend/input.h                     |  7 ++
 src/core/hle/service/hid/controllers/npad.cpp | 48 +++++------
 src/core/hle/service/hid/controllers/npad.h   | 11 ++-
 src/core/hle/service/hid/hid.cpp              |  1 +
 src/input_common/gcadapter/gc_adapter.cpp     |  6 +-
 src/input_common/gcadapter/gc_adapter.h       |  4 +-
 src/input_common/gcadapter/gc_poller.cpp      | 50 +++++++++---
 src/input_common/gcadapter/gc_poller.h        | 11 +++
 src/input_common/main.cpp                     |  5 ++
 src/input_common/sdl/sdl_impl.cpp             | 74 +++++++++++++----
 src/input_common/sdl/sdl_impl.h               |  2 +
 src/input_common/settings.cpp                 | 21 +++--
 src/input_common/settings.h                   | 32 ++++++--
 src/yuzu/applets/controller.cpp               |  2 +
 src/yuzu/configuration/config.cpp             | 61 +++++++++-----
 .../configuration/configure_input_player.cpp  |  7 ++
 .../configuration/configure_vibration.cpp     | 80 +++++++++++++++++++
 src/yuzu/configuration/configure_vibration.h  |  3 +
 src/yuzu/main.cpp                             |  3 +
 19 files changed, 327 insertions(+), 101 deletions(-)

diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index fb2ce2514..25ac5af46 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -121,6 +121,13 @@ using ButtonDevice = InputDevice<bool>;
  */
 using AnalogDevice = InputDevice<std::tuple<float, float>>;
 
+/**
+ * A vibration device is an input device that returns an unsigned byte as status.
+ * It represents whether the vibration device supports vibration or not.
+ * If the status returns 1, it supports vibration. Otherwise, it does not support vibration.
+ */
+using VibrationDevice = InputDevice<u8>;
+
 /**
  * A motion status is an object that returns a tuple of accelerometer state vector,
  * gyroscope state vector, rotation state vector and orientation state matrix.
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index dc9954377..27099de24 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -271,6 +271,10 @@ void Controller_NPad::OnLoadInputDevices() {
         std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
                        players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
                        sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
+        std::transform(players[i].vibrations.begin() +
+                           Settings::NativeVibration::VIBRATION_HID_BEGIN,
+                       players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END,
+                       vibrations[i].begin(), Input::CreateDevice<Input::VibrationDevice>);
         std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
                        players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,
                        motions[i].begin(), Input::CreateDevice<Input::MotionDevice>);
@@ -278,8 +282,10 @@ void Controller_NPad::OnLoadInputDevices() {
 }
 
 void Controller_NPad::OnRelease() {
-    for (std::size_t index = 0; index < connected_controllers.size(); ++index) {
-        VibrateControllerAtIndex(index, {});
+    for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) {
+        for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) {
+            VibrateControllerAtIndex(npad_idx, device_idx);
+        }
     }
 }
 
@@ -674,9 +680,9 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode)
     }
 }
 
-bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index,
+bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
                                                const VibrationValue& vibration_value) {
-    if (!connected_controllers[npad_index].is_connected) {
+    if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) {
         return false;
     }
 
@@ -686,10 +692,7 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index,
         return false;
     }
 
-    using namespace Settings::NativeButton;
-    const auto& button_state = buttons[npad_index];
-
-    return button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
+    return vibrations[npad_index][device_index]->SetRumblePlay(
         std::min(vibration_value.amp_low * player.vibration_strength / 100.0f, 1.0f),
         vibration_value.freq_low,
         std::min(vibration_value.amp_high * player.vibration_strength / 100.0f, 1.0f),
@@ -717,6 +720,11 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat
             continue;
         }
 
+        if (vibration_device_handles[i].device_index == DeviceIndex::None) {
+            UNREACHABLE_MSG("DeviceIndex should never be None!");
+            continue;
+        }
+
         // Some games try to send mismatched parameters in the device handle, block these.
         if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft &&
              (vibration_device_handles[i].npad_type == NpadType::JoyconRight ||
@@ -747,28 +755,8 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat
             continue;
         }
 
-        // TODO: Vibrate left/right vibration motors independently if possible.
-        if (VibrateControllerAtIndex(npad_index, vibration_values[i])) {
-            switch (connected_controllers[npad_index].type) {
-            case NPadControllerType::None:
-                UNREACHABLE();
-                break;
-            case NPadControllerType::ProController:
-            case NPadControllerType::Handheld:
-            case NPadControllerType::JoyDual:
-                // Since we can't vibrate motors independently yet, we can reduce state changes by
-                // assigning all 3 device indices the current vibration value.
-                latest_vibration_values[npad_index][0] = vibration_values[i];
-                latest_vibration_values[npad_index][1] = vibration_values[i];
-                latest_vibration_values[npad_index][2] = vibration_values[i];
-                break;
-            case NPadControllerType::JoyLeft:
-            case NPadControllerType::JoyRight:
-            case NPadControllerType::Pokeball:
-            default:
-                latest_vibration_values[npad_index][device_index] = vibration_values[i];
-                break;
-            }
+        if (VibrateControllerAtIndex(npad_index, device_index, vibration_values[i])) {
+            latest_vibration_values[npad_index][device_index] = vibration_values[i];
         }
     }
 }
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 576ef1558..3ae9fb8e6 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -148,7 +148,8 @@ public:
 
     void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode);
 
-    bool VibrateControllerAtIndex(std::size_t npad_index, const VibrationValue& vibration_value);
+    bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
+                                  const VibrationValue& vibration_value = {});
 
     void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
                             const std::vector<VibrationValue>& vibration_values);
@@ -399,18 +400,22 @@ private:
     using StickArray = std::array<
         std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
         10>;
+    using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>,
+                                                 Settings::NativeVibration::NUM_VIBRATIONS_HID>,
+                                      10>;
     using MotionArray = std::array<
-        std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>,
+        std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
         10>;
     ButtonArray buttons;
     StickArray sticks;
+    VibrationArray vibrations;
     MotionArray motions;
     std::vector<u32> supported_npad_id_types{};
     NpadHoldType hold_type{NpadHoldType::Vertical};
     NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
     // Each controller should have their own styleset changed event
     std::array<Kernel::EventPair, 10> styleset_changed_events;
-    std::array<std::array<VibrationValue, 3>, 10> latest_vibration_values;
+    std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
     std::array<ControllerHolder, 10> connected_controllers{};
     std::array<bool, 10> unintended_home_button_input_protection{};
     GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index e88f30d6a..1d882a977 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -998,6 +998,7 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
         break;
     case Controller_NPad::DeviceIndex::None:
     default:
+        UNREACHABLE_MSG("DeviceIndex should never be None!");
         vibration_device_info.position = VibrationDevicePosition::None;
         break;
     }
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index b912188b6..d80195c82 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -230,10 +230,8 @@ void Adapter::SendVibrations() {
     vibration_changed = false;
 }
 
-bool Adapter::RumblePlay(std::size_t port, f32 amplitude) {
-    amplitude = std::clamp(amplitude, 0.0f, 1.0f);
-    const auto raw_amp = static_cast<u8>(amplitude * 0x8);
-    pads[port].rumble_amplitude = raw_amp;
+bool Adapter::RumblePlay(std::size_t port, u8 amplitude) {
+    pads[port].rumble_amplitude = amplitude;
 
     return rumble_enabled;
 }
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
index d28dcfad3..f1256c9da 100644
--- a/src/input_common/gcadapter/gc_adapter.h
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -77,8 +77,8 @@ public:
     Adapter();
     ~Adapter();
 
-    /// Request a vibration for a controlelr
-    bool RumblePlay(std::size_t port, f32 amplitude);
+    /// Request a vibration for a controller
+    bool RumblePlay(std::size_t port, u8 amplitude);
 
     /// Used for polling
     void BeginConfiguration();
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index 6bd6f57fc..fe57c13a5 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -15,7 +15,7 @@ namespace InputCommon {
 
 class GCButton final : public Input::ButtonDevice {
 public:
-    explicit GCButton(u32 port_, s32 button_, GCAdapter::Adapter* adapter)
+    explicit GCButton(u32 port_, s32 button_, const GCAdapter::Adapter* adapter)
         : port(port_), button(button_), gcadapter(adapter) {}
 
     ~GCButton() override;
@@ -27,18 +27,10 @@ public:
         return false;
     }
 
-    bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override {
-        const float amplitude = amp_high + amp_low > 2.0f ? 1.0f : (amp_high + amp_low) * 0.5f;
-        const auto new_amp =
-            static_cast<f32>(pow(amplitude, 0.5f) * (3.0f - 2.0f * pow(amplitude, 0.15f)));
-
-        return gcadapter->RumblePlay(port, new_amp);
-    }
-
 private:
     const u32 port;
     const s32 button;
-    GCAdapter::Adapter* gcadapter;
+    const GCAdapter::Adapter* gcadapter;
 };
 
 class GCAxisButton final : public Input::ButtonDevice {
@@ -299,4 +291,42 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() {
     return params;
 }
 
+class GCVibration final : public Input::VibrationDevice {
+public:
+    explicit GCVibration(u32 port_, GCAdapter::Adapter* adapter)
+        : port(port_), gcadapter(adapter) {}
+
+    u8 GetStatus() const override {
+        return gcadapter->RumblePlay(port, 0);
+    }
+
+    bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
+        const auto mean_amplitude = (amp_low + amp_high) * 0.5f;
+        const auto processed_amplitude = static_cast<u8>(
+            pow(mean_amplitude, 0.5f) * (3.0f - 2.0f * pow(mean_amplitude, 0.15f)) * 0x8);
+
+        return gcadapter->RumblePlay(port, processed_amplitude);
+    }
+
+private:
+    const u32 port;
+    GCAdapter::Adapter* gcadapter;
+};
+
+/// An vibration device factory that creates vibration devices from GC Adapter
+GCVibrationFactory::GCVibrationFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
+    : adapter(std::move(adapter_)) {}
+
+/**
+ * Creates a vibration device from a joystick
+ * @param params contains parameters for creating the device:
+ *     - "port": the nth gcpad on the adapter
+ */
+std::unique_ptr<Input::VibrationDevice> GCVibrationFactory::Create(
+    const Common::ParamPackage& params) {
+    const auto port = static_cast<u32>(params.Get("port", 0));
+
+    return std::make_unique<GCVibration>(port, adapter.get());
+}
+
 } // namespace InputCommon
diff --git a/src/input_common/gcadapter/gc_poller.h b/src/input_common/gcadapter/gc_poller.h
index 0527f328f..d1271e3ea 100644
--- a/src/input_common/gcadapter/gc_poller.h
+++ b/src/input_common/gcadapter/gc_poller.h
@@ -64,4 +64,15 @@ private:
     bool polling = false;
 };
 
+/// A vibration device factory creates vibration devices from GC Adapter
+class GCVibrationFactory final : public Input::Factory<Input::VibrationDevice> {
+public:
+    explicit GCVibrationFactory(std::shared_ptr<GCAdapter::Adapter> adapter_);
+
+    std::unique_ptr<Input::VibrationDevice> Create(const Common::ParamPackage& params) override;
+
+private:
+    std::shared_ptr<GCAdapter::Adapter> adapter;
+};
+
 } // namespace InputCommon
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index b438482cc..e59ad4ff5 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -28,6 +28,8 @@ struct InputSubsystem::Impl {
         Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
         gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
         Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
+        gcvibration = std::make_shared<GCVibrationFactory>(gcadapter);
+        Input::RegisterFactory<Input::VibrationDevice>("gcpad", gcvibration);
 
         keyboard = std::make_shared<Keyboard>();
         Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
@@ -64,9 +66,11 @@ struct InputSubsystem::Impl {
 #endif
         Input::UnregisterFactory<Input::ButtonDevice>("gcpad");
         Input::UnregisterFactory<Input::AnalogDevice>("gcpad");
+        Input::UnregisterFactory<Input::VibrationDevice>("gcpad");
 
         gcbuttons.reset();
         gcanalog.reset();
+        gcvibration.reset();
 
         Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
         Input::UnregisterFactory<Input::TouchDevice>("cemuhookudp");
@@ -142,6 +146,7 @@ struct InputSubsystem::Impl {
 #endif
     std::shared_ptr<GCButtonFactory> gcbuttons;
     std::shared_ptr<GCAnalogFactory> gcanalog;
+    std::shared_ptr<GCVibrationFactory> gcvibration;
     std::shared_ptr<UDPMotionFactory> udpmotion;
     std::shared_ptr<UDPTouchFactory> udptouch;
     std::shared_ptr<CemuhookUDP::Client> udp;
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 18fb2ac5e..a2a83cdc9 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -85,16 +85,17 @@ public:
         using std::chrono::milliseconds;
         using std::chrono::steady_clock;
 
-        // Prevent vibrations less than 10ms apart from each other.
-        if (duration_cast<milliseconds>(steady_clock::now() - last_vibration) < milliseconds(10)) {
+        // Block non-zero vibrations less than 10ms apart from each other.
+        if ((amp_low != 0 || amp_high != 0) &&
+            duration_cast<milliseconds>(steady_clock::now() - last_vibration) < milliseconds(10)) {
             return false;
-        };
+        }
 
         last_vibration = steady_clock::now();
 
-        if (sdl_controller != nullptr) {
+        if (sdl_controller) {
             return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0;
-        } else if (sdl_joystick != nullptr) {
+        } else if (sdl_joystick) {
             return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0;
         }
 
@@ -321,14 +322,6 @@ public:
         return joystick->GetButton(button);
     }
 
-    bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
-        const u16 processed_amp_low =
-            static_cast<u16>(pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f)) * 0xFFFF);
-        const u16 processed_amp_high =
-            static_cast<u16>(pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f)) * 0xFFFF);
-        return joystick->RumblePlay(processed_amp_low, processed_amp_high);
-    }
-
 private:
     std::shared_ptr<SDLJoystick> joystick;
     int button;
@@ -412,6 +405,32 @@ private:
     const float range;
 };
 
+class SDLVibration final : public Input::VibrationDevice {
+public:
+    explicit SDLVibration(std::shared_ptr<SDLJoystick> joystick_)
+        : joystick(std::move(joystick_)) {}
+
+    u8 GetStatus() const override {
+        joystick->RumblePlay(1, 1);
+        return joystick->RumblePlay(0, 0);
+    }
+
+    bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
+        const auto process_amplitude = [](f32 amplitude) {
+            return static_cast<u16>(std::pow(amplitude, 0.5f) *
+                                    (3.0f - 2.0f * std::pow(amplitude, 0.15f)) * 0xFFFF);
+        };
+
+        const auto processed_amp_low = process_amplitude(amp_low);
+        const auto processed_amp_high = process_amplitude(amp_high);
+
+        return joystick->RumblePlay(processed_amp_low, processed_amp_high);
+    }
+
+private:
+    std::shared_ptr<SDLJoystick> joystick;
+};
+
 class SDLDirectionMotion final : public Input::MotionDevice {
 public:
     explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
@@ -554,7 +573,7 @@ class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
 public:
     explicit SDLAnalogFactory(SDLState& state_) : state(state_) {}
     /**
-     * Creates analog device from joystick axes
+     * Creates an analog device from joystick axes
      * @param params contains parameters for creating the device:
      *     - "guid": the guid of the joystick to bind
      *     - "port": the nth joystick of the same type
@@ -580,6 +599,26 @@ private:
     SDLState& state;
 };
 
+/// An vibration device factory that creates vibration devices from SDL joystick
+class SDLVibrationFactory final : public Input::Factory<Input::VibrationDevice> {
+public:
+    explicit SDLVibrationFactory(SDLState& state_) : state(state_) {}
+    /**
+     * Creates a vibration device from a joystick
+     * @param params contains parameters for creating the device:
+     *     - "guid": the guid of the joystick to bind
+     *     - "port": the nth joystick of the same type
+     */
+    std::unique_ptr<Input::VibrationDevice> Create(const Common::ParamPackage& params) override {
+        const std::string guid = params.Get("guid", "0");
+        const int port = params.Get("port", 0);
+        return std::make_unique<SDLVibration>(state.GetSDLJoystickByGUID(guid, port));
+    }
+
+private:
+    SDLState& state;
+};
+
 /// A motion device factory that creates motion devices from SDL joystick
 class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
 public:
@@ -646,11 +685,13 @@ private:
 
 SDLState::SDLState() {
     using namespace Input;
-    analog_factory = std::make_shared<SDLAnalogFactory>(*this);
     button_factory = std::make_shared<SDLButtonFactory>(*this);
+    analog_factory = std::make_shared<SDLAnalogFactory>(*this);
+    vibration_factory = std::make_shared<SDLVibrationFactory>(*this);
     motion_factory = std::make_shared<SDLMotionFactory>(*this);
-    RegisterFactory<AnalogDevice>("sdl", analog_factory);
     RegisterFactory<ButtonDevice>("sdl", button_factory);
+    RegisterFactory<AnalogDevice>("sdl", analog_factory);
+    RegisterFactory<VibrationDevice>("sdl", vibration_factory);
     RegisterFactory<MotionDevice>("sdl", motion_factory);
 
     // If the frontend is going to manage the event loop, then we don't start one here
@@ -687,6 +728,7 @@ SDLState::~SDLState() {
     using namespace Input;
     UnregisterFactory<ButtonDevice>("sdl");
     UnregisterFactory<AnalogDevice>("sdl");
+    UnregisterFactory<VibrationDevice>("sdl");
     UnregisterFactory<MotionDevice>("sdl");
 
     CloseJoysticks();
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index b9bb4dc56..08044b00d 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -22,6 +22,7 @@ namespace InputCommon::SDL {
 class SDLAnalogFactory;
 class SDLButtonFactory;
 class SDLMotionFactory;
+class SDLVibrationFactory;
 class SDLJoystick;
 
 class SDLState : public State {
@@ -72,6 +73,7 @@ private:
 
     std::shared_ptr<SDLButtonFactory> button_factory;
     std::shared_ptr<SDLAnalogFactory> analog_factory;
+    std::shared_ptr<SDLVibrationFactory> vibration_factory;
     std::shared_ptr<SDLMotionFactory> motion_factory;
 
     bool start_thread = false;
diff --git a/src/input_common/settings.cpp b/src/input_common/settings.cpp
index b66c05856..557e7a9a0 100644
--- a/src/input_common/settings.cpp
+++ b/src/input_common/settings.cpp
@@ -14,13 +14,6 @@ const std::array<const char*, NumButtons> mapping = {{
 }};
 }
 
-namespace NativeMotion {
-const std::array<const char*, NumMotions> mapping = {{
-    "motionleft",
-    "motionright",
-}};
-}
-
 namespace NativeAnalog {
 const std::array<const char*, NumAnalogs> mapping = {{
     "lstick",
@@ -28,6 +21,20 @@ const std::array<const char*, NumAnalogs> mapping = {{
 }};
 }
 
+namespace NativeVibration {
+const std::array<const char*, NumVibrations> mapping = {{
+    "left_vibration_device",
+    "right_vibration_device",
+}};
+}
+
+namespace NativeMotion {
+const std::array<const char*, NumMotions> mapping = {{
+    "motionleft",
+    "motionright",
+}};
+}
+
 namespace NativeMouseButton {
 const std::array<const char*, NumMouseButtons> mapping = {{
     "left",
diff --git a/src/input_common/settings.h b/src/input_common/settings.h
index 2763ed991..75486554b 100644
--- a/src/input_common/settings.h
+++ b/src/input_common/settings.h
@@ -66,17 +66,32 @@ constexpr int NUM_STICKS_HID = NumAnalogs;
 extern const std::array<const char*, NumAnalogs> mapping;
 } // namespace NativeAnalog
 
+namespace NativeVibration {
+enum Values : int {
+    LeftVibrationDevice,
+    RightVibrationDevice,
+
+    NumVibrations,
+};
+
+constexpr int VIBRATION_HID_BEGIN = LeftVibrationDevice;
+constexpr int VIBRATION_HID_END = NumVibrations;
+constexpr int NUM_VIBRATIONS_HID = NumVibrations;
+
+extern const std::array<const char*, NumVibrations> mapping;
+}; // namespace NativeVibration
+
 namespace NativeMotion {
 enum Values : int {
-    MOTIONLEFT,
-    MOTIONRIGHT,
+    MotionLeft,
+    MotionRight,
 
     NumMotions,
 };
 
-constexpr int MOTION_HID_BEGIN = MOTIONLEFT;
+constexpr int MOTION_HID_BEGIN = MotionLeft;
 constexpr int MOTION_HID_END = NumMotions;
-constexpr int NUM_MOTION_HID = NumMotions;
+constexpr int NUM_MOTIONS_HID = NumMotions;
 
 extern const std::array<const char*, NumMotions> mapping;
 } // namespace NativeMotion
@@ -305,9 +320,11 @@ constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
 
 } // namespace NativeKeyboard
 
-using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
 using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
-using MotionRaw = std::array<std::string, NativeMotion::NumMotions>;
+using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
+using MotionsRaw = std::array<std::string, NativeMotion::NumMotions>;
+using VibrationsRaw = std::array<std::string, NativeVibration::NumVibrations>;
+
 using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
 using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
 using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
@@ -330,7 +347,8 @@ struct PlayerInput {
     ControllerType controller_type;
     ButtonsRaw buttons;
     AnalogsRaw analogs;
-    MotionRaw motions;
+    VibrationsRaw vibrations;
+    MotionsRaw motions;
 
     bool vibration_enabled;
     int vibration_strength;
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index c5e671309..cdcd3d28d 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -478,6 +478,8 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index)
         return;
     }
 
+    ConfigureVibration::SetVibrationDevices(player_index);
+
     // Player 1 and Handheld
     auto& handheld = Settings::values.players.GetValue()[8];
     // If Handheld is selected, copy all the settings from Player 1 to Handheld.
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 7f66f29aa..6fa842cd5 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -344,21 +344,6 @@ void Config::ReadPlayerValue(std::size_t player_index) {
         }
     }
 
-    for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
-        const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
-        auto& player_motions = player.motions[i];
-
-        player_motions = qt_config
-                             ->value(QStringLiteral("%1").arg(player_prefix) +
-                                         QString::fromUtf8(Settings::NativeMotion::mapping[i]),
-                                     QString::fromStdString(default_param))
-                             .toString()
-                             .toStdString();
-        if (player_motions.empty()) {
-            player_motions = default_param;
-        }
-    }
-
     for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
         const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
             default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
@@ -375,6 +360,33 @@ void Config::ReadPlayerValue(std::size_t player_index) {
             player_analogs = default_param;
         }
     }
+
+    for (int i = 0; i < Settings::NativeVibration::NumVibrations; ++i) {
+        auto& player_vibrations = player.vibrations[i];
+
+        player_vibrations =
+            qt_config
+                ->value(QStringLiteral("%1").arg(player_prefix) +
+                            QString::fromUtf8(Settings::NativeVibration::mapping[i]),
+                        QString{})
+                .toString()
+                .toStdString();
+    }
+
+    for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
+        const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
+        auto& player_motions = player.motions[i];
+
+        player_motions = qt_config
+                             ->value(QStringLiteral("%1").arg(player_prefix) +
+                                         QString::fromUtf8(Settings::NativeMotion::mapping[i]),
+                                     QString::fromStdString(default_param))
+                             .toString()
+                             .toStdString();
+        if (player_motions.empty()) {
+            player_motions = default_param;
+        }
+    }
 }
 
 void Config::ReadDebugValues() {
@@ -1014,13 +1026,6 @@ void Config::SavePlayerValue(std::size_t player_index) {
                      QString::fromStdString(player.buttons[i]),
                      QString::fromStdString(default_param));
     }
-    for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
-        const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
-        WriteSetting(QStringLiteral("%1").arg(player_prefix) +
-                         QString::fromStdString(Settings::NativeMotion::mapping[i]),
-                     QString::fromStdString(player.motions[i]),
-                     QString::fromStdString(default_param));
-    }
     for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
         const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
             default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
@@ -1030,6 +1035,18 @@ void Config::SavePlayerValue(std::size_t player_index) {
                      QString::fromStdString(player.analogs[i]),
                      QString::fromStdString(default_param));
     }
+    for (int i = 0; i < Settings::NativeVibration::NumVibrations; ++i) {
+        WriteSetting(QStringLiteral("%1").arg(player_prefix) +
+                         QString::fromStdString(Settings::NativeVibration::mapping[i]),
+                     QString::fromStdString(player.vibrations[i]), QString{});
+    }
+    for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
+        const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
+        WriteSetting(QStringLiteral("%1").arg(player_prefix) +
+                         QString::fromStdString(Settings::NativeMotion::mapping[i]),
+                     QString::fromStdString(player.motions[i]),
+                     QString::fromStdString(default_param));
+    }
 }
 
 void Config::SaveDebugValues() {
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 460ff08a4..3e785c224 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -22,6 +22,7 @@
 #include "ui_configure_input_player.h"
 #include "yuzu/configuration/config.h"
 #include "yuzu/configuration/configure_input_player.h"
+#include "yuzu/configuration/configure_vibration.h"
 #include "yuzu/configuration/input_profiles.h"
 #include "yuzu/util/limitable_input_dialog.h"
 
@@ -39,6 +40,10 @@ namespace {
 
 void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
                       bool connected) {
+    auto& player = Settings::values.players.GetValue()[npad_index];
+    player.controller_type = controller_type;
+    player.connected = connected;
+
     Core::System& system{Core::System::GetInstance()};
     if (!system.IsPoweredOn()) {
         return;
@@ -565,6 +570,8 @@ void ConfigureInputPlayer::ApplyConfiguration() {
         static_cast<Settings::ControllerType>(ui->comboControllerType->currentIndex());
     player.connected = ui->groupConnectedController->isChecked();
 
+    ConfigureVibration::SetVibrationDevices(player_index);
+
     // Player 2-8
     if (player_index != 0) {
         UpdateController(player.controller_type, player_index, player.connected);
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp
index 1c68f28f3..714db5b80 100644
--- a/src/yuzu/configuration/configure_vibration.cpp
+++ b/src/yuzu/configuration/configure_vibration.cpp
@@ -2,6 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <algorithm>
+#include <unordered_map>
+
+#include <fmt/format.h>
+
+#include "common/param_package.h"
 #include "core/settings.h"
 #include "ui_configure_vibration.h"
 #include "yuzu/configuration/configure_vibration.h"
@@ -53,6 +59,80 @@ void ConfigureVibration::ApplyConfiguration() {
         ui->checkBoxAccurateVibration->isChecked());
 }
 
+void ConfigureVibration::SetVibrationDevices(std::size_t player_index) {
+    using namespace Settings::NativeButton;
+    static constexpr std::array<std::array<Settings::NativeButton::Values, 6>, 2> buttons{{
+        {DLeft, DUp, DRight, DDown, L, ZL}, // Left Buttons
+        {A, B, X, Y, R, ZR},                // Right Buttons
+    }};
+
+    auto& player = Settings::values.players.GetValue()[player_index];
+
+    for (std::size_t device_idx = 0; device_idx < buttons.size(); ++device_idx) {
+        std::unordered_map<std::string, int> params_count;
+
+        for (const auto button_index : buttons[device_idx]) {
+            const auto& player_button = player.buttons[button_index];
+
+            if (params_count.find(player_button) != params_count.end()) {
+                ++params_count[player_button];
+                continue;
+            }
+
+            params_count.insert_or_assign(player_button, 1);
+        }
+
+        const auto it = std::max_element(
+            params_count.begin(), params_count.end(),
+            [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
+
+        auto& vibration_param_str = player.vibrations[device_idx];
+        vibration_param_str.clear();
+
+        if (it->first.empty()) {
+            continue;
+        }
+
+        const auto param = Common::ParamPackage(it->first);
+
+        const auto engine = param.Get("engine", "");
+        const auto guid = param.Get("guid", "");
+        const auto port = param.Get("port", "");
+
+        if (engine.empty() || engine == "keyboard") {
+            continue;
+        }
+
+        vibration_param_str += fmt::format("engine:{}", engine);
+
+        if (!port.empty()) {
+            vibration_param_str += fmt::format(",port:{}", port);
+        }
+        if (!guid.empty()) {
+            vibration_param_str += fmt::format(",guid:{}", guid);
+        }
+    }
+
+    if (player.vibrations[0] != player.vibrations[1]) {
+        return;
+    }
+
+    if (!player.vibrations[0].empty() &&
+        player.controller_type != Settings::ControllerType::RightJoycon) {
+        player.vibrations[1].clear();
+    } else if (!player.vibrations[1].empty() &&
+               player.controller_type == Settings::ControllerType::RightJoycon) {
+        player.vibrations[0].clear();
+    }
+}
+
+void ConfigureVibration::SetAllVibrationDevices() {
+    // Set vibration devices for all player indices including handheld
+    for (std::size_t player_idx = 0; player_idx < NUM_PLAYERS + 1; ++player_idx) {
+        SetVibrationDevices(player_idx);
+    }
+}
+
 void ConfigureVibration::changeEvent(QEvent* event) {
     if (event->type() == QEvent::LanguageChange) {
         RetranslateUI();
diff --git a/src/yuzu/configuration/configure_vibration.h b/src/yuzu/configuration/configure_vibration.h
index 37bbc2653..07411a86f 100644
--- a/src/yuzu/configuration/configure_vibration.h
+++ b/src/yuzu/configuration/configure_vibration.h
@@ -24,6 +24,9 @@ public:
 
     void ApplyConfiguration();
 
+    static void SetVibrationDevices(std::size_t player_index);
+    static void SetAllVibrationDevices();
+
 private:
     void changeEvent(QEvent* event) override;
     void RetranslateUI();
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 54a46827f..76a5c32f4 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -18,6 +18,7 @@
 #include "applets/web_browser.h"
 #include "configuration/configure_input.h"
 #include "configuration/configure_per_game.h"
+#include "configuration/configure_vibration.h"
 #include "core/file_sys/vfs.h"
 #include "core/file_sys/vfs_real.h"
 #include "core/frontend/applets/controller.h"
@@ -1096,6 +1097,8 @@ void GMainWindow::BootGame(const QString& filename) {
         Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig);
     }
 
+    ConfigureVibration::SetAllVibrationDevices();
+
     Settings::LogSettings();
 
     if (UISettings::values.select_user_on_boot) {

From 978ca65f59f1388358ce0d45de41816e8b0aa887 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Thu, 22 Oct 2020 06:55:23 -0400
Subject: [PATCH 27/37] hid: Implement InitializeVibrationDevice and
 IsVibrationDeviceMounted

---
 src/core/hle/service/hid/controllers/npad.cpp | 42 ++++++++++++++++++-
 src/core/hle/service/hid/controllers/npad.h   |  7 ++++
 src/core/hle/service/hid/hid.cpp              | 29 ++++++++-----
 3 files changed, 66 insertions(+), 12 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 27099de24..ecc33bc08 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -278,6 +278,9 @@ void Controller_NPad::OnLoadInputDevices() {
         std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
                        players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,
                        motions[i].begin(), Input::CreateDevice<Input::MotionDevice>);
+        for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) {
+            InitializeVibrationDeviceAtIndex(i, device_idx);
+        }
     }
 }
 
@@ -689,6 +692,14 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size
     const auto& player = Settings::values.players.GetValue()[npad_index];
 
     if (!player.vibration_enabled) {
+        if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f ||
+            latest_vibration_values[npad_index][device_index].amp_high != 0.0f) {
+            // Send an empty vibration to stop any vibrations.
+            vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f);
+            // Then reset the vibration value to its default value.
+            latest_vibration_values[npad_index][device_index] = {};
+        }
+
         return false;
     }
 
@@ -716,7 +727,8 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat
         const auto device_index =
             static_cast<std::size_t>(vibration_device_handles[i].device_index);
 
-        if (!connected_controllers[npad_index].is_connected) {
+        if (!vibration_devices_mounted[npad_index][device_index] ||
+            !connected_controllers[npad_index].is_connected) {
             continue;
         }
 
@@ -768,6 +780,28 @@ Controller_NPad::VibrationValue Controller_NPad::GetLastVibration(
     return latest_vibration_values[npad_index][device_index];
 }
 
+void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) {
+    const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
+    const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
+    InitializeVibrationDeviceAtIndex(npad_index, device_index);
+}
+
+void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index,
+                                                       std::size_t device_index) {
+    if (vibrations[npad_index][device_index]) {
+        vibration_devices_mounted[npad_index][device_index] =
+            vibrations[npad_index][device_index]->GetStatus() == 1;
+    } else {
+        vibration_devices_mounted[npad_index][device_index] = false;
+    }
+}
+
+bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const {
+    const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
+    const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
+    return vibration_devices_mounted[npad_index][device_index];
+}
+
 std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
     const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
     return styleset_event.readable;
@@ -809,6 +843,12 @@ void Controller_NPad::DisconnectNpad(u32 npad_id) {
 }
 
 void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
+    for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) {
+        // Send an empty vibration to stop any vibrations.
+        VibrateControllerAtIndex(npad_index, device_idx);
+        vibration_devices_mounted[npad_index][device_idx] = false;
+    }
+
     Settings::values.players.GetValue()[npad_index].connected = false;
     connected_controllers[npad_index].is_connected = false;
 
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 3ae9fb8e6..30e3cb02f 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -156,6 +156,12 @@ public:
 
     VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const;
 
+    void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle);
+
+    void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index);
+
+    bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;
+
     std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
     void SignalStyleSetChangedEvent(u32 npad_id) const;
 
@@ -416,6 +422,7 @@ private:
     // Each controller should have their own styleset changed event
     std::array<Kernel::EventPair, 10> styleset_changed_events;
     std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
+    std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
     std::array<ControllerHolder, 10> connected_controllers{};
     std::array<bool, 10> unintended_home_button_input_protection{};
     GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1d882a977..ecaa847b2 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -139,7 +139,8 @@ void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose
 
 class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
 public:
-    IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") {
+    explicit IActiveVibrationDeviceList(std::shared_ptr<IAppletResource> applet_resource_)
+        : ServiceFramework("IActiveVibrationDeviceList"), applet_resource(applet_resource_) {
         // clang-format off
         static const FunctionInfo functions[] = {
             {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},
@@ -154,13 +155,18 @@ private:
         IPC::RequestParser rp{ctx};
         const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
 
-        LOG_WARNING(Service_HID, "(STUBBED) called, npad_type={}, npad_id={}, device_index={}",
-                    vibration_device_handle.npad_type, vibration_device_handle.npad_id,
-                    vibration_device_handle.device_index);
+        applet_resource->GetController<Controller_NPad>(HidController::NPad)
+            .InitializeVibrationDevice(vibration_device_handle);
+
+        LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
+                  vibration_device_handle.npad_type, vibration_device_handle.npad_id,
+                  vibration_device_handle.device_index);
 
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(RESULT_SUCCESS);
     }
+
+    std::shared_ptr<IAppletResource> applet_resource;
 };
 
 std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
@@ -1062,7 +1068,7 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<IActiveVibrationDeviceList>();
+    rb.PushIpcInterface<IActiveVibrationDeviceList>(applet_resource);
 }
 
 void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
@@ -1137,15 +1143,16 @@ void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) {
 
     const auto parameters{rp.PopRaw<Parameters>()};
 
-    LOG_WARNING(
-        Service_HID,
-        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
-        parameters.vibration_device_handle.npad_type, parameters.vibration_device_handle.npad_id,
-        parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
+    LOG_DEBUG(Service_HID,
+              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+              parameters.vibration_device_handle.npad_type,
+              parameters.vibration_device_handle.npad_id,
+              parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
-    rb.Push(true);
+    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                .IsVibrationDeviceMounted(parameters.vibration_device_handle));
 }
 
 void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {

From 91c06dae1a68efb2d6ae110d0aa28d7b3aafd573 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Fri, 23 Oct 2020 12:09:28 -0400
Subject: [PATCH 28/37] input: Disconnect a controller prior to connecting a
 new one

Some games do not respond to a change in controller type if 1) The controller is not disconnected prior to being reconnected and/or 2) The controller is reconnected instantly after being disconnected.

Since it is not possible to change controllers instantly on hardware and requiring a disconnect prior to connecting a new one, we should emulate this as well with a small delay, fixing the aforementioned issue.
---
 src/yuzu/applets/controller.cpp               | 62 ++++++++++--------
 .../configuration/configure_input_player.cpp  | 63 +++++++++++--------
 2 files changed, 74 insertions(+), 51 deletions(-)

diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index cdcd3d28d..552cb7204 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -19,6 +19,8 @@
 
 namespace {
 
+constexpr std::size_t HANDHELD_INDEX = 8;
+
 constexpr std::array<std::array<bool, 4>, 8> led_patterns{{
     {true, false, false, false},
     {true, true, false, false},
@@ -260,11 +262,6 @@ int QtControllerSelectorDialog::exec() {
 }
 
 void QtControllerSelectorDialog::ApplyConfiguration() {
-    // Update the controller state once more, just to be sure they are properly applied.
-    for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
-        UpdateControllerState(index);
-    }
-
     const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
     Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked());
     OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue());
@@ -275,15 +272,16 @@ void QtControllerSelectorDialog::ApplyConfiguration() {
 
 void QtControllerSelectorDialog::LoadConfiguration() {
     for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
-        const auto connected = Settings::values.players.GetValue()[index].connected ||
-                               (index == 0 && Settings::values.players.GetValue()[8].connected);
+        const auto connected =
+            Settings::values.players.GetValue()[index].connected ||
+            (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
         player_groupboxes[index]->setChecked(connected);
         connected_controller_checkboxes[index]->setChecked(connected);
         emulated_controllers[index]->setCurrentIndex(
             GetIndexFromControllerType(Settings::values.players.GetValue()[index].controller_type));
     }
 
-    UpdateDockedState(Settings::values.players.GetValue()[8].connected);
+    UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
 
     ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
     ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
@@ -468,32 +466,46 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
 void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
     auto& player = Settings::values.players.GetValue()[player_index];
 
-    player.controller_type =
+    const auto controller_type =
         GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex());
-    player.connected = player_groupboxes[player_index]->isChecked();
+    const auto player_connected = player_groupboxes[player_index]->isChecked() &&
+                                  controller_type != Settings::ControllerType::Handheld;
 
-    // Player 2-8
-    if (player_index != 0) {
-        UpdateController(player.controller_type, player_index, player.connected);
+    if (player.controller_type == controller_type && player.connected == player_connected) {
+        // Set vibration devices in the event that the input device has changed.
+        ConfigureVibration::SetVibrationDevices(player_index);
         return;
     }
 
+    // Disconnect the controller first.
+    UpdateController(controller_type, player_index, false);
+
+    player.controller_type = controller_type;
+    player.connected = player_connected;
+
     ConfigureVibration::SetVibrationDevices(player_index);
 
-    // Player 1 and Handheld
-    auto& handheld = Settings::values.players.GetValue()[8];
-    // If Handheld is selected, copy all the settings from Player 1 to Handheld.
-    if (player.controller_type == Settings::ControllerType::Handheld) {
-        handheld = player;
-        handheld.connected = player_groupboxes[player_index]->isChecked();
-        player.connected = false; // Disconnect Player 1
-    } else {
-        player.connected = player_groupboxes[player_index]->isChecked();
-        handheld.connected = false; // Disconnect Handheld
+    // Handheld
+    if (player_index == 0) {
+        auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX];
+        if (controller_type == Settings::ControllerType::Handheld) {
+            handheld = player;
+        }
+        handheld.connected = player_groupboxes[player_index]->isChecked() &&
+                             controller_type == Settings::ControllerType::Handheld;
+        UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected);
     }
 
-    UpdateController(player.controller_type, player_index, player.connected);
-    UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected);
+    if (!player.connected) {
+        return;
+    }
+
+    // This emulates a delay between disconnecting and reconnecting controllers as some games
+    // do not respond to a change in controller type if it was instantaneous.
+    using namespace std::chrono_literals;
+    std::this_thread::sleep_for(20ms);
+
+    UpdateController(controller_type, player_index, player_connected);
 }
 
 void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 3e785c224..1ee4725ef 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -26,8 +26,6 @@
 #include "yuzu/configuration/input_profiles.h"
 #include "yuzu/util/limitable_input_dialog.h"
 
-constexpr std::size_t HANDHELD_INDEX = 8;
-
 const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM>
     ConfigureInputPlayer::analog_sub_buttons{{
         "up",
@@ -38,12 +36,10 @@ const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM>
 
 namespace {
 
+constexpr std::size_t HANDHELD_INDEX = 8;
+
 void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
                       bool connected) {
-    auto& player = Settings::values.players.GetValue()[npad_index];
-    player.controller_type = controller_type;
-    player.connected = connected;
-
     Core::System& system{Core::System::GetInstance()};
     if (!system.IsPoweredOn()) {
         return;
@@ -563,35 +559,50 @@ void ConfigureInputPlayer::ApplyConfiguration() {
     }
 
     auto& motions = player.motions;
+
     std::transform(motions_param.begin(), motions_param.end(), motions.begin(),
                    [](const Common::ParamPackage& param) { return param.Serialize(); });
 
-    player.controller_type =
-        static_cast<Settings::ControllerType>(ui->comboControllerType->currentIndex());
-    player.connected = ui->groupConnectedController->isChecked();
+    const auto controller_type =
+        GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
+    const auto player_connected = ui->groupConnectedController->isChecked() &&
+                                  controller_type != Settings::ControllerType::Handheld;
 
-    ConfigureVibration::SetVibrationDevices(player_index);
-
-    // Player 2-8
-    if (player_index != 0) {
-        UpdateController(player.controller_type, player_index, player.connected);
+    if (player.controller_type == controller_type && player.connected == player_connected) {
+        // Set vibration devices in the event that the input device has changed.
+        ConfigureVibration::SetVibrationDevices(player_index);
         return;
     }
 
-    // Player 1 and Handheld
-    auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX];
-    // If Handheld is selected, copy all the settings from Player 1 to Handheld.
-    if (player.controller_type == Settings::ControllerType::Handheld) {
-        handheld = player;
-        handheld.connected = ui->groupConnectedController->isChecked();
-        player.connected = false; // Disconnect Player 1
-    } else {
-        player.connected = ui->groupConnectedController->isChecked();
-        handheld.connected = false; // Disconnect Handheld
+    // Disconnect the controller first.
+    UpdateController(controller_type, player_index, false);
+
+    player.controller_type = controller_type;
+    player.connected = player_connected;
+
+    ConfigureVibration::SetVibrationDevices(player_index);
+
+    // Handheld
+    if (player_index == 0) {
+        auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX];
+        if (controller_type == Settings::ControllerType::Handheld) {
+            handheld = player;
+        }
+        handheld.connected = ui->groupConnectedController->isChecked() &&
+                             controller_type == Settings::ControllerType::Handheld;
+        UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected);
     }
 
-    UpdateController(player.controller_type, player_index, player.connected);
-    UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected);
+    if (!player.connected) {
+        return;
+    }
+
+    // This emulates a delay between disconnecting and reconnecting controllers as some games
+    // do not respond to a change in controller type if it was instantaneous.
+    using namespace std::chrono_literals;
+    std::this_thread::sleep_for(20ms);
+
+    UpdateController(controller_type, player_index, player_connected);
 }
 
 void ConfigureInputPlayer::showEvent(QShowEvent* event) {

From 30e0d1c973290f4813b040eecf83ff4a2c7432c3 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 25 Oct 2020 07:30:23 -0400
Subject: [PATCH 29/37] controllers/npad: Remove the old vibration filter

Previously we used a vibration filter that filters out amplitudes close to each other. It turns out there are cases where this results into vibrations that are too inaccurate. Remove this and move the 100Hz vibration filter (Only allowing a maximum of 100 vibrations per second) from sdl_impl to npad when enable_accurate_vibrations is set to false.
---
 src/core/hle/service/hid/controllers/npad.cpp | 118 ++++++++++--------
 src/core/hle/service/hid/controllers/npad.h   |   4 +
 src/core/hle/service/hid/hid.cpp              |   2 +-
 src/input_common/sdl/sdl_impl.cpp             |  15 ---
 4 files changed, 69 insertions(+), 70 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ecc33bc08..cfafabbd8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -703,6 +703,23 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size
         return false;
     }
 
+    if (!Settings::values.enable_accurate_vibrations.GetValue()) {
+        using std::chrono::duration_cast;
+        using std::chrono::milliseconds;
+        using std::chrono::steady_clock;
+
+        const auto now = steady_clock::now();
+
+        // Filter out non-zero vibrations that are within 10ms of each other.
+        if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) &&
+            duration_cast<milliseconds>(now - last_vibration_timepoints[npad_index][device_index]) <
+                milliseconds(10)) {
+            return false;
+        }
+
+        last_vibration_timepoints[npad_index][device_index] = now;
+    }
+
     return vibrations[npad_index][device_index]->SetRumblePlay(
         std::min(vibration_value.amp_low * player.vibration_strength / 100.0f, 1.0f),
         vibration_value.freq_low,
@@ -710,66 +727,59 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size
         vibration_value.freq_high);
 }
 
-void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
-                                         const std::vector<VibrationValue>& vibration_values) {
-    LOG_TRACE(Service_HID, "called");
-
+void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle,
+                                        const VibrationValue& vibration_value) {
     if (!Settings::values.vibration_enabled.GetValue()) {
         return;
     }
 
-    ASSERT_MSG(vibration_device_handles.size() == vibration_values.size(),
-               "The amount of device handles does not match with the amount of vibration values,"
-               "this is undefined behavior!");
+    const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
+    const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
+
+    if (!vibration_devices_mounted[npad_index][device_index] ||
+        !connected_controllers[npad_index].is_connected) {
+        return;
+    }
+
+    if (vibration_device_handle.device_index == DeviceIndex::None) {
+        UNREACHABLE_MSG("DeviceIndex should never be None!");
+        return;
+    }
+
+    // Some games try to send mismatched parameters in the device handle, block these.
+    if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft &&
+         (vibration_device_handle.npad_type == NpadType::JoyconRight ||
+          vibration_device_handle.device_index == DeviceIndex::Right)) ||
+        (connected_controllers[npad_index].type == NPadControllerType::JoyRight &&
+         (vibration_device_handle.npad_type == NpadType::JoyconLeft ||
+          vibration_device_handle.device_index == DeviceIndex::Left))) {
+        return;
+    }
+
+    // Filter out vibrations with equivalent values to reduce unnecessary state changes.
+    if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low &&
+        vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) {
+        return;
+    }
+
+    if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) {
+        latest_vibration_values[npad_index][device_index] = vibration_value;
+    }
+}
+
+void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
+                                         const std::vector<VibrationValue>& vibration_values) {
+    if (!Settings::values.vibration_enabled.GetValue()) {
+        return;
+    }
+
+    ASSERT_OR_EXECUTE_MSG(
+        vibration_device_handles.size() == vibration_values.size(), { return; },
+        "The amount of device handles does not match with the amount of vibration values,"
+        "this is undefined behavior!");
 
     for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) {
-        const auto npad_index = NPadIdToIndex(vibration_device_handles[i].npad_id);
-        const auto device_index =
-            static_cast<std::size_t>(vibration_device_handles[i].device_index);
-
-        if (!vibration_devices_mounted[npad_index][device_index] ||
-            !connected_controllers[npad_index].is_connected) {
-            continue;
-        }
-
-        if (vibration_device_handles[i].device_index == DeviceIndex::None) {
-            UNREACHABLE_MSG("DeviceIndex should never be None!");
-            continue;
-        }
-
-        // Some games try to send mismatched parameters in the device handle, block these.
-        if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft &&
-             (vibration_device_handles[i].npad_type == NpadType::JoyconRight ||
-              vibration_device_handles[i].device_index == DeviceIndex::Right)) ||
-            (connected_controllers[npad_index].type == NPadControllerType::JoyRight &&
-             (vibration_device_handles[i].npad_type == NpadType::JoyconLeft ||
-              vibration_device_handles[i].device_index == DeviceIndex::Left))) {
-            continue;
-        }
-
-        // Filter out vibrations with equivalent values to reduce unnecessary state changes.
-        if (vibration_values[i].amp_low ==
-                latest_vibration_values[npad_index][device_index].amp_low &&
-            vibration_values[i].amp_high ==
-                latest_vibration_values[npad_index][device_index].amp_high) {
-            continue;
-        }
-
-        // Filter out non-zero vibrations that are within 0.015625 absolute amplitude of each other.
-        if (!Settings::values.enable_accurate_vibrations.GetValue() &&
-            (vibration_values[i].amp_low != 0.0f || vibration_values[i].amp_high != 0.0f) &&
-            (latest_vibration_values[npad_index][device_index].amp_low != 0.0f ||
-             latest_vibration_values[npad_index][device_index].amp_high != 0.0f) &&
-            (abs(vibration_values[i].amp_low -
-                 latest_vibration_values[npad_index][device_index].amp_low) < 0.015625f &&
-             abs(vibration_values[i].amp_high -
-                 latest_vibration_values[npad_index][device_index].amp_high) < 0.015625f)) {
-            continue;
-        }
-
-        if (VibrateControllerAtIndex(npad_index, device_index, vibration_values[i])) {
-            latest_vibration_values[npad_index][device_index] = vibration_values[i];
-        }
+        VibrateController(vibration_device_handles[i], vibration_values[i]);
     }
 }
 
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 30e3cb02f..f5122124c 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -151,6 +151,9 @@ public:
     bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
                                   const VibrationValue& vibration_value = {});
 
+    void VibrateController(const DeviceHandle& vibration_device_handle,
+                           const VibrationValue& vibration_value);
+
     void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
                             const std::vector<VibrationValue>& vibration_values);
 
@@ -421,6 +424,7 @@ private:
     NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
     // Each controller should have their own styleset changed event
     std::array<Kernel::EventPair, 10> styleset_changed_events;
+    std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints;
     std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
     std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
     std::array<ControllerHolder, 10> connected_controllers{};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index ecaa847b2..2e9682bed 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1029,7 +1029,7 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
     const auto parameters{rp.PopRaw<Parameters>()};
 
     applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .VibrateControllers({parameters.vibration_device_handle}, {parameters.vibration_value});
+        .VibrateController(parameters.vibration_device_handle, parameters.vibration_value);
 
     LOG_DEBUG(Service_HID,
               "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index a2a83cdc9..a9f7e5103 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -81,18 +81,6 @@ public:
     }
 
     bool RumblePlay(u16 amp_low, u16 amp_high) {
-        using std::chrono::duration_cast;
-        using std::chrono::milliseconds;
-        using std::chrono::steady_clock;
-
-        // Block non-zero vibrations less than 10ms apart from each other.
-        if ((amp_low != 0 || amp_high != 0) &&
-            duration_cast<milliseconds>(steady_clock::now() - last_vibration) < milliseconds(10)) {
-            return false;
-        }
-
-        last_vibration = steady_clock::now();
-
         if (sdl_controller) {
             return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0;
         } else if (sdl_joystick) {
@@ -171,9 +159,6 @@ private:
     std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
     mutable std::mutex mutex;
 
-    // This is the timepoint of the last vibration and is used to ensure vibrations are 10ms apart.
-    std::chrono::steady_clock::time_point last_vibration;
-
     // Motion is initialized without PID values as motion input is not aviable for SDL2
     MotionInput motion{0.0f, 0.0f, 0.0f};
 };

From 760a9e869322cbda51416f7001842557b90754af Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Mon, 26 Oct 2020 03:28:03 -0400
Subject: [PATCH 30/37] applets/controller: Change the input button to create
 input profiles

Co-authored-by: Its-Rei <kupfel@gmail.com>
---
 src/yuzu/CMakeLists.txt                       |  6 +--
 src/yuzu/applets/controller.cpp               | 20 ++++------
 src/yuzu/applets/controller.h                 |  8 +++-
 src/yuzu/applets/controller.ui                |  4 +-
 .../configuration/configure_input_dialog.cpp  | 37 ------------------
 .../configuration/configure_input_dialog.h    | 38 ------------------
 .../configuration/configure_input_player.cpp  |  5 ++-
 .../configure_input_profile_dialog.cpp        | 36 +++++++++++++++++
 .../configure_input_profile_dialog.h          | 39 +++++++++++++++++++
 ...g.ui => configure_input_profile_dialog.ui} | 24 +++++++++---
 10 files changed, 117 insertions(+), 100 deletions(-)
 delete mode 100644 src/yuzu/configuration/configure_input_dialog.cpp
 delete mode 100644 src/yuzu/configuration/configure_input_dialog.h
 create mode 100644 src/yuzu/configuration/configure_input_profile_dialog.cpp
 create mode 100644 src/yuzu/configuration/configure_input_profile_dialog.h
 rename src/yuzu/configuration/{configure_input_dialog.ui => configure_input_profile_dialog.ui} (64%)

diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index bf1fae9fa..b16b54032 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -68,12 +68,12 @@ add_executable(yuzu
     configuration/configure_input_advanced.cpp
     configuration/configure_input_advanced.h
     configuration/configure_input_advanced.ui
-    configuration/configure_input_dialog.cpp
-    configuration/configure_input_dialog.h
-    configuration/configure_input_dialog.ui
     configuration/configure_input_player.cpp
     configuration/configure_input_player.h
     configuration/configure_input_player.ui
+    configuration/configure_input_profile_dialog.cpp
+    configuration/configure_input_profile_dialog.h
+    configuration/configure_input_profile_dialog.ui
     configuration/configure_motion_touch.cpp
     configuration/configure_motion_touch.h
     configuration/configure_motion_touch.ui
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index 552cb7204..5112d48d2 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -13,8 +13,10 @@
 #include "core/hle/service/sm/sm.h"
 #include "ui_controller.h"
 #include "yuzu/applets/controller.h"
-#include "yuzu/configuration/configure_input_dialog.h"
+#include "yuzu/configuration/configure_input.h"
+#include "yuzu/configuration/configure_input_profile_dialog.h"
 #include "yuzu/configuration/configure_vibration.h"
+#include "yuzu/configuration/input_profiles.h"
 #include "yuzu/main.h"
 
 namespace {
@@ -109,7 +111,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
     QWidget* parent, Core::Frontend::ControllerParameters parameters_,
     InputCommon::InputSubsystem* input_subsystem_)
     : QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()),
-      parameters(std::move(parameters_)), input_subsystem(input_subsystem_) {
+      parameters(std::move(parameters_)), input_subsystem{input_subsystem_},
+      input_profiles(std::make_unique<InputProfiles>()) {
     ui->setupUi(this);
 
     player_widgets = {
@@ -230,7 +233,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
             &QtControllerSelectorDialog::CallConfigureVibrationDialog);
 
     connect(ui->inputConfigButton, &QPushButton::clicked, this,
-            &QtControllerSelectorDialog::CallConfigureInputDialog);
+            &QtControllerSelectorDialog::CallConfigureInputProfileDialog);
 
     connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
             &QtControllerSelectorDialog::ApplyConfiguration);
@@ -299,20 +302,13 @@ void QtControllerSelectorDialog::CallConfigureVibrationDialog() {
     }
 }
 
-void QtControllerSelectorDialog::CallConfigureInputDialog() {
-    const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
-
-    ConfigureInputDialog dialog(this, max_supported_players, input_subsystem);
+void QtControllerSelectorDialog::CallConfigureInputProfileDialog() {
+    ConfigureInputProfileDialog dialog(this, input_subsystem, input_profiles.get());
 
     dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
                           Qt::WindowSystemMenuHint);
     dialog.setWindowModality(Qt::WindowModal);
     dialog.exec();
-
-    dialog.ApplyConfiguration();
-
-    LoadConfiguration();
-    CheckIfParametersMet();
 }
 
 bool QtControllerSelectorDialog::CheckIfParametersMet() {
diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h
index a2ce03c8f..4344e1dd0 100644
--- a/src/yuzu/applets/controller.h
+++ b/src/yuzu/applets/controller.h
@@ -16,6 +16,8 @@ class QDialogButtonBox;
 class QGroupBox;
 class QLabel;
 
+class InputProfiles;
+
 namespace InputCommon {
 class InputSubsystem;
 }
@@ -45,8 +47,8 @@ private:
     // Initializes the "Configure Vibration" Dialog.
     void CallConfigureVibrationDialog();
 
-    // Initializes the "Configure Input" Dialog.
-    void CallConfigureInputDialog();
+    // Initializes the "Create Input Profile" Dialog.
+    void CallConfigureInputProfileDialog();
 
     // Checks the current configuration against the given parameters.
     // This sets and returns the value of parameters_met.
@@ -83,6 +85,8 @@ private:
 
     InputCommon::InputSubsystem* input_subsystem;
 
+    std::unique_ptr<InputProfiles> input_profiles;
+
     // This is true if and only if all parameters are met. Otherwise, this is false.
     // This determines whether the "OK" button can be clicked to exit the applet.
     bool parameters_met{false};
diff --git a/src/yuzu/applets/controller.ui b/src/yuzu/applets/controller.ui
index 8e571ba8f..c8cb6bcf3 100644
--- a/src/yuzu/applets/controller.ui
+++ b/src/yuzu/applets/controller.ui
@@ -2402,7 +2402,7 @@
          <item>
           <widget class="QGroupBox" name="inputConfigGroup">
            <property name="title">
-            <string>Input Config</string>
+            <string>Profiles</string>
            </property>
            <layout class="QHBoxLayout" name="horizontalLayout_7">
             <property name="leftMargin">
@@ -2429,7 +2429,7 @@
                <string notr="true">min-width: 68px;</string>
               </property>
               <property name="text">
-               <string>Open</string>
+               <string>Create</string>
               </property>
              </widget>
             </item>
diff --git a/src/yuzu/configuration/configure_input_dialog.cpp b/src/yuzu/configuration/configure_input_dialog.cpp
deleted file mode 100644
index 1866003c2..000000000
--- a/src/yuzu/configuration/configure_input_dialog.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2020 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "ui_configure_input_dialog.h"
-#include "yuzu/configuration/configure_input_dialog.h"
-
-ConfigureInputDialog::ConfigureInputDialog(QWidget* parent, std::size_t max_players,
-                                           InputCommon::InputSubsystem* input_subsystem)
-    : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputDialog>()),
-      input_widget(new ConfigureInput(this)) {
-    ui->setupUi(this);
-
-    input_widget->Initialize(input_subsystem, max_players);
-
-    ui->inputLayout->addWidget(input_widget);
-
-    RetranslateUI();
-}
-
-ConfigureInputDialog::~ConfigureInputDialog() = default;
-
-void ConfigureInputDialog::ApplyConfiguration() {
-    input_widget->ApplyConfiguration();
-}
-
-void ConfigureInputDialog::changeEvent(QEvent* event) {
-    if (event->type() == QEvent::LanguageChange) {
-        RetranslateUI();
-    }
-
-    QDialog::changeEvent(event);
-}
-
-void ConfigureInputDialog::RetranslateUI() {
-    ui->retranslateUi(this);
-}
diff --git a/src/yuzu/configuration/configure_input_dialog.h b/src/yuzu/configuration/configure_input_dialog.h
deleted file mode 100644
index d1bd865f9..000000000
--- a/src/yuzu/configuration/configure_input_dialog.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2020 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-#include <QDialog>
-#include "yuzu/configuration/configure_input.h"
-
-class QPushButton;
-
-namespace InputCommon {
-class InputSubsystem;
-}
-
-namespace Ui {
-class ConfigureInputDialog;
-}
-
-class ConfigureInputDialog : public QDialog {
-    Q_OBJECT
-
-public:
-    explicit ConfigureInputDialog(QWidget* parent, std::size_t max_players,
-                                  InputCommon::InputSubsystem* input_subsystem);
-    ~ConfigureInputDialog() override;
-
-    void ApplyConfiguration();
-
-private:
-    void changeEvent(QEvent* event) override;
-    void RetranslateUI();
-
-    std::unique_ptr<Ui::ConfigureInputDialog> ui;
-
-    ConfigureInput* input_widget;
-};
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 1ee4725ef..4ed704793 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -459,11 +459,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
                 });
     }
 
+    if (debug || player_index == 9) {
+        ui->groupConnectedController->setCheckable(false);
+    }
+
     // The Debug Controller can only choose the Pro Controller.
     if (debug) {
         ui->buttonScreenshot->setEnabled(false);
         ui->buttonHome->setEnabled(false);
-        ui->groupConnectedController->setCheckable(false);
         QStringList debug_controller_types = {
             tr("Pro Controller"),
         };
diff --git a/src/yuzu/configuration/configure_input_profile_dialog.cpp b/src/yuzu/configuration/configure_input_profile_dialog.cpp
new file mode 100644
index 000000000..818399b47
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_profile_dialog.cpp
@@ -0,0 +1,36 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "ui_configure_input_profile_dialog.h"
+#include "yuzu/configuration/configure_input_profile_dialog.h"
+
+ConfigureInputProfileDialog::ConfigureInputProfileDialog(
+    QWidget* parent, InputCommon::InputSubsystem* input_subsystem, InputProfiles* profiles)
+    : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputProfileDialog>()),
+      profile_widget(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, false)) {
+    ui->setupUi(this);
+
+    ui->controllerLayout->addWidget(profile_widget);
+
+    connect(ui->clear_all_button, &QPushButton::clicked, this,
+            [this] { profile_widget->ClearAll(); });
+    connect(ui->restore_defaults_button, &QPushButton::clicked, this,
+            [this] { profile_widget->RestoreDefaults(); });
+
+    RetranslateUI();
+}
+
+ConfigureInputProfileDialog::~ConfigureInputProfileDialog() = default;
+
+void ConfigureInputProfileDialog::changeEvent(QEvent* event) {
+    if (event->type() == QEvent::LanguageChange) {
+        RetranslateUI();
+    }
+
+    QDialog::changeEvent(event);
+}
+
+void ConfigureInputProfileDialog::RetranslateUI() {
+    ui->retranslateUi(this);
+}
diff --git a/src/yuzu/configuration/configure_input_profile_dialog.h b/src/yuzu/configuration/configure_input_profile_dialog.h
new file mode 100644
index 000000000..d4a3973d9
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_profile_dialog.h
@@ -0,0 +1,39 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QDialog>
+#include "yuzu/configuration/configure_input_player.h"
+
+class QPushButton;
+
+class InputProfiles;
+
+namespace InputCommon {
+class InputSubsystem;
+}
+
+namespace Ui {
+class ConfigureInputProfileDialog;
+}
+
+class ConfigureInputProfileDialog : public QDialog {
+    Q_OBJECT
+
+public:
+    explicit ConfigureInputProfileDialog(QWidget* parent,
+                                         InputCommon::InputSubsystem* input_subsystem,
+                                         InputProfiles* profiles);
+    ~ConfigureInputProfileDialog() override;
+
+private:
+    void changeEvent(QEvent* event) override;
+    void RetranslateUI();
+
+    std::unique_ptr<Ui::ConfigureInputProfileDialog> ui;
+
+    ConfigureInputPlayer* profile_widget;
+};
diff --git a/src/yuzu/configuration/configure_input_dialog.ui b/src/yuzu/configuration/configure_input_profile_dialog.ui
similarity index 64%
rename from src/yuzu/configuration/configure_input_dialog.ui
rename to src/yuzu/configuration/configure_input_profile_dialog.ui
index b92ddb200..726cf6905 100644
--- a/src/yuzu/configuration/configure_input_dialog.ui
+++ b/src/yuzu/configuration/configure_input_profile_dialog.ui
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <class>ConfigureInputDialog</class>
- <widget class="QDialog" name="ConfigureInputDialog">
+ <class>ConfigureInputProfileDialog</class>
+ <widget class="QDialog" name="ConfigureInputProfileDialog">
   <property name="geometry">
    <rect>
     <x>0</x>
@@ -11,7 +11,7 @@
    </rect>
   </property>
   <property name="windowTitle">
-   <string>Configure Input</string>
+   <string>Create Input Profile</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <property name="spacing">
@@ -30,10 +30,24 @@
     <number>9</number>
    </property>
    <item>
-    <layout class="QHBoxLayout" name="inputLayout"/>
+    <layout class="QHBoxLayout" name="controllerLayout"/>
    </item>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QPushButton" name="clear_all_button">
+       <property name="text">
+        <string>Clear</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="restore_defaults_button">
+       <property name="text">
+        <string>Defaults</string>
+       </property>
+      </widget>
+     </item>
      <item>
       <widget class="QDialogButtonBox" name="buttonBox">
        <property name="standardButtons">
@@ -50,7 +64,7 @@
   <connection>
    <sender>buttonBox</sender>
    <signal>accepted()</signal>
-   <receiver>ConfigureInputDialog</receiver>
+   <receiver>ConfigureInputProfileDialog</receiver>
    <slot>accept()</slot>
   </connection>
  </connections>

From 117bdc71e016629b9355b33a6d64655f0245f833 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Tue, 27 Oct 2020 13:15:57 -0400
Subject: [PATCH 31/37] sdl_impl: Revert to the "old" method of mapping sticks

Not all controllers have a SDL_GameController binding. This caused controllers not present in the SDL GameController database to have buttons mapped instead of axes.

Furthermore, it was not possible to invert the axes when it could be useful such as emulating a horizontal single joycon or other potential cases. This allows us to invert the axes by reversing the order of mapping (vertical, then horizontal).
---
 src/input_common/sdl/sdl_impl.cpp             | 45 ++++++-------------
 .../configuration/configure_input_player.cpp  | 12 +++++
 .../configuration/configure_input_player.h    |  5 ++-
 3 files changed, 29 insertions(+), 33 deletions(-)

diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index a9f7e5103..6024ed97a 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -1068,7 +1068,6 @@ public:
 
     void Start(const std::string& device_id) override {
         SDLPoller::Start(device_id);
-        // Load the game controller
         // Reset stored axes
         analog_x_axis = -1;
         analog_y_axis = -1;
@@ -1081,40 +1080,21 @@ public:
             if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
                 continue;
             }
-            // Simplify controller config by testing if game controller support is enabled.
             if (event.type == SDL_JOYAXISMOTION) {
                 const auto axis = event.jaxis.axis;
-                if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
-                    auto* const controller = joystick->GetSDLGameController()) {
-                    const auto axis_left_x =
-                        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
-                            .value.axis;
-                    const auto axis_left_y =
-                        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)
-                            .value.axis;
-                    const auto axis_right_x =
-                        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX)
-                            .value.axis;
-                    const auto axis_right_y =
-                        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY)
-                            .value.axis;
-
-                    if (axis == axis_left_x || axis == axis_left_y) {
-                        analog_x_axis = axis_left_x;
-                        analog_y_axis = axis_left_y;
-                        break;
-                    } else if (axis == axis_right_x || axis == axis_right_y) {
-                        analog_x_axis = axis_right_x;
-                        analog_y_axis = axis_right_y;
-                        break;
-                    }
+                // In order to return a complete analog param, we need inputs for both axes.
+                // First we take the x-axis (horizontal) input, then the y-axis (vertical) input.
+                if (analog_x_axis == -1) {
+                    analog_x_axis = axis;
+                } else if (analog_y_axis == -1 && analog_x_axis != axis) {
+                    analog_y_axis = axis;
+                }
+            } else {
+                // If the press wasn't accepted as a joy axis, check for a button press
+                auto button_press = button_poller.FromEvent(event);
+                if (button_press) {
+                    return *button_press;
                 }
-            }
-
-            // If the press wasn't accepted as a joy axis, check for a button press
-            auto button_press = button_poller.FromEvent(event);
-            if (button_press) {
-                return *button_press;
             }
         }
 
@@ -1127,6 +1107,7 @@ public:
                 return params;
             }
         }
+
         return {};
     }
 
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 4ed704793..5abf9f0bf 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -370,6 +370,18 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
             }
 
             connect(analog_button, &QPushButton::clicked, [=, this] {
+                if (!map_analog_stick_accepted) {
+                    map_analog_stick_accepted =
+                        QMessageBox::information(
+                            this, tr("Map Analog Stick"),
+                            tr("After pressing OK, first move your joystick horizontally, and then "
+                               "vertically.\nTo invert the axes, first move your joystick "
+                               "vertically, and then horizontally."),
+                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok;
+                    if (!map_analog_stick_accepted) {
+                        return;
+                    }
+                }
                 HandleClick(
                     analog_map_buttons[analog_id][sub_button_id],
                     [=, this](const Common::ParamPackage& params) {
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index 05dee5af5..4895e8850 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -181,9 +181,12 @@ private:
 
     std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
 
+    /// A flag to indicate that the "Map Analog Stick" pop-up has been shown and accepted once.
+    bool map_analog_stick_accepted{};
+
     /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
     /// keyboard events are ignored.
-    bool want_keyboard_mouse = false;
+    bool want_keyboard_mouse{};
 
     /// List of physical devices users can map with. If a SDL backed device is selected, then you
     /// can use this device to get a default mapping.

From 97b2220a822548eed83993fceebe0e611dbec84b Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Tue, 27 Oct 2020 13:33:25 -0400
Subject: [PATCH 32/37] general: Fix compiler warnings on linux and
 miscellaneous changes

---
 src/core/hle/service/hid/controllers/npad.cpp   | 17 ++++++++++-------
 src/core/hle/service/hid/controllers/npad.h     |  2 +-
 src/yuzu/applets/controller.cpp                 |  5 +++--
 .../configure_debug_controller.cpp              |  1 +
 .../configuration/configure_debug_controller.h  |  3 ++-
 src/yuzu/configuration/configure_input.h        |  9 ++++-----
 .../configuration/configure_input_advanced.cpp  |  6 +++---
 .../configuration/configure_input_advanced.h    |  2 +-
 .../configuration/configure_input_player.cpp    |  3 ++-
 .../configure_input_profile_dialog.cpp          |  1 +
 .../configure_input_profile_dialog.h            |  3 ++-
 src/yuzu/main.cpp                               |  1 +
 12 files changed, 31 insertions(+), 22 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index cfafabbd8..30715267c 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -287,7 +287,7 @@ void Controller_NPad::OnLoadInputDevices() {
 void Controller_NPad::OnRelease() {
     for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) {
         for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) {
-            VibrateControllerAtIndex(npad_idx, device_idx);
+            VibrateControllerAtIndex(npad_idx, device_idx, {});
         }
     }
 }
@@ -720,11 +720,14 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size
         last_vibration_timepoints[npad_index][device_index] = now;
     }
 
-    return vibrations[npad_index][device_index]->SetRumblePlay(
-        std::min(vibration_value.amp_low * player.vibration_strength / 100.0f, 1.0f),
-        vibration_value.freq_low,
-        std::min(vibration_value.amp_high * player.vibration_strength / 100.0f, 1.0f),
-        vibration_value.freq_high);
+    auto& vibration = vibrations[npad_index][device_index];
+    const auto player_vibration_strength = static_cast<f32>(player.vibration_strength);
+    const auto amp_low =
+        std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f);
+    const auto amp_high =
+        std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f);
+    return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high,
+                                    vibration_value.freq_high);
 }
 
 void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle,
@@ -855,7 +858,7 @@ void Controller_NPad::DisconnectNpad(u32 npad_id) {
 void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
     for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) {
         // Send an empty vibration to stop any vibrations.
-        VibrateControllerAtIndex(npad_index, device_idx);
+        VibrateControllerAtIndex(npad_index, device_idx, {});
         vibration_devices_mounted[npad_index][device_idx] = false;
     }
 
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index f5122124c..99384524b 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -149,7 +149,7 @@ public:
     void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode);
 
     bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
-                                  const VibrationValue& vibration_value = {});
+                                  const VibrationValue& vibration_value);
 
     void VibrateController(const DeviceHandle& vibration_device_handle,
                            const VibrationValue& vibration_value);
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index 5112d48d2..8ecfec770 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
+#include <thread>
 
 #include "common/assert.h"
 #include "common/string_util.h"
@@ -356,7 +357,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() {
 }
 
 void QtControllerSelectorDialog::SetSupportedControllers() {
-    const QString theme = [this] {
+    const QString theme = [] {
         if (QIcon::themeName().contains(QStringLiteral("dark"))) {
             return QStringLiteral("_dark");
         } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
@@ -445,7 +446,7 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
         }
     }();
 
-    const QString theme = [this] {
+    const QString theme = [] {
         if (QIcon::themeName().contains(QStringLiteral("dark"))) {
             return QStringLiteral("_dark");
         } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
diff --git a/src/yuzu/configuration/configure_debug_controller.cpp b/src/yuzu/configuration/configure_debug_controller.cpp
index 6dc9c5e57..a878ef9c6 100644
--- a/src/yuzu/configuration/configure_debug_controller.cpp
+++ b/src/yuzu/configuration/configure_debug_controller.cpp
@@ -4,6 +4,7 @@
 
 #include "ui_configure_debug_controller.h"
 #include "yuzu/configuration/configure_debug_controller.h"
+#include "yuzu/configuration/configure_input_player.h"
 
 ConfigureDebugController::ConfigureDebugController(QWidget* parent,
                                                    InputCommon::InputSubsystem* input_subsystem,
diff --git a/src/yuzu/configuration/configure_debug_controller.h b/src/yuzu/configuration/configure_debug_controller.h
index 2694b3419..b4f53fad5 100644
--- a/src/yuzu/configuration/configure_debug_controller.h
+++ b/src/yuzu/configuration/configure_debug_controller.h
@@ -6,10 +6,11 @@
 
 #include <memory>
 #include <QDialog>
-#include "yuzu/configuration/configure_input_player.h"
 
 class QPushButton;
 
+class ConfigureInputPlayer;
+
 class InputProfiles;
 
 namespace InputCommon {
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index f135a4299..9eba9b523 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -8,17 +8,16 @@
 #include <memory>
 
 #include <QKeyEvent>
+#include <QList>
 #include <QWidget>
 
-#include "yuzu/configuration/configure_input_advanced.h"
-#include "yuzu/configuration/configure_input_player.h"
-
-#include "ui_configure_input.h"
-
 class QCheckBox;
 class QString;
 class QTimer;
 
+class ConfigureInputAdvanced;
+class ConfigureInputPlayer;
+
 class InputProfiles;
 
 namespace InputCommon {
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index 3074be833..abaf03630 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -68,8 +68,7 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
         for (std::size_t button_idx = 0; button_idx < color_buttons.size(); ++button_idx) {
             connect(color_buttons[button_idx], &QPushButton::clicked, this,
                     [this, player_idx, button_idx] {
-                        OnControllerButtonClick(static_cast<int>(player_idx),
-                                                static_cast<int>(button_idx));
+                        OnControllerButtonClick(player_idx, button_idx);
                     });
         }
     }
@@ -94,7 +93,8 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
 
 ConfigureInputAdvanced::~ConfigureInputAdvanced() = default;
 
-void ConfigureInputAdvanced::OnControllerButtonClick(int player_idx, int button_idx) {
+void ConfigureInputAdvanced::OnControllerButtonClick(std::size_t player_idx,
+                                                     std::size_t button_idx) {
     const QColor new_bg_color = QColorDialog::getColor(controllers_colors[player_idx][button_idx]);
     if (!new_bg_color.isValid()) {
         return;
diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h
index 50bb87768..3083d55c1 100644
--- a/src/yuzu/configuration/configure_input_advanced.h
+++ b/src/yuzu/configuration/configure_input_advanced.h
@@ -35,7 +35,7 @@ private:
     void RetranslateUI();
     void UpdateUIEnabled();
 
-    void OnControllerButtonClick(int player_idx, int button_idx);
+    void OnControllerButtonClick(std::size_t player_idx, std::size_t button_idx);
 
     void LoadConfiguration();
 
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 5abf9f0bf..0d10c1360 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <thread>
 #include <utility>
 #include <QGridLayout>
 #include <QInputDialog>
@@ -857,7 +858,7 @@ void ConfigureInputPlayer::UpdateControllerIcon() {
         }
     }();
 
-    const QString theme = [this] {
+    const QString theme = [] {
         if (QIcon::themeName().contains(QStringLiteral("dark"))) {
             return QStringLiteral("_dark");
         } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
diff --git a/src/yuzu/configuration/configure_input_profile_dialog.cpp b/src/yuzu/configuration/configure_input_profile_dialog.cpp
index 818399b47..1f5cfa75b 100644
--- a/src/yuzu/configuration/configure_input_profile_dialog.cpp
+++ b/src/yuzu/configuration/configure_input_profile_dialog.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "ui_configure_input_profile_dialog.h"
+#include "yuzu/configuration/configure_input_player.h"
 #include "yuzu/configuration/configure_input_profile_dialog.h"
 
 ConfigureInputProfileDialog::ConfigureInputProfileDialog(
diff --git a/src/yuzu/configuration/configure_input_profile_dialog.h b/src/yuzu/configuration/configure_input_profile_dialog.h
index d4a3973d9..e6386bdbb 100644
--- a/src/yuzu/configuration/configure_input_profile_dialog.h
+++ b/src/yuzu/configuration/configure_input_profile_dialog.h
@@ -6,10 +6,11 @@
 
 #include <memory>
 #include <QDialog>
-#include "yuzu/configuration/configure_input_player.h"
 
 class QPushButton;
 
+class ConfigureInputPlayer;
+
 class InputProfiles;
 
 namespace InputCommon {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 76a5c32f4..9dabd8889 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -58,6 +58,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
 #include <QMessageBox>
 #include <QProgressBar>
 #include <QProgressDialog>
+#include <QPushButton>
 #include <QShortcut>
 #include <QStatusBar>
 #include <QSysInfo>

From 6f5b9428971904ad8815a56d50c9aab4805a1c56 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Thu, 29 Oct 2020 12:15:35 -0400
Subject: [PATCH 33/37] configure_input: Update the input profiles for other
 player tabs

---
 src/yuzu/configuration/configure_input.cpp    | 16 +++++++++++++--
 src/yuzu/configuration/configure_input.h      |  1 +
 .../configuration/configure_input_player.cpp  | 20 +++++++++++++------
 .../configuration/configure_input_player.h    | 12 ++++++++---
 4 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 600cc03ae..d9009091b 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -124,8 +124,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
                 }
             }
         });
-        connect(player_controllers[i], &ConfigureInputPlayer::RefreshInputDevices,
-                [this] { UpdateAllInputDevices(); });
+        connect(player_controllers[i], &ConfigureInputPlayer::RefreshInputDevices, this,
+                &ConfigureInput::UpdateAllInputDevices);
+        connect(player_controllers[i], &ConfigureInputPlayer::RefreshInputProfiles, this,
+                &ConfigureInput::UpdateAllInputProfiles, Qt::QueuedConnection);
         connect(player_connected[i], &QCheckBox::stateChanged, [this, i](int state) {
             player_controllers[i]->ConnectPlayer(state == Qt::Checked);
         });
@@ -259,3 +261,13 @@ void ConfigureInput::UpdateAllInputDevices() {
         player->UpdateInputDeviceCombobox();
     }
 }
+
+void ConfigureInput::UpdateAllInputProfiles(std::size_t player_index) {
+    for (std::size_t i = 0; i < player_controllers.size(); ++i) {
+        if (i == player_index) {
+            continue;
+        }
+
+        player_controllers[i]->UpdateInputProfiles();
+    }
+}
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index 9eba9b523..f4eb0d78b 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -52,6 +52,7 @@ private:
 
     void UpdateDockedState(bool is_handheld);
     void UpdateAllInputDevices();
+    void UpdateAllInputProfiles(std::size_t player_index);
 
     /// Load configuration settings.
     void LoadConfiguration();
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 0d10c1360..f65a7fe73 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -541,7 +541,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
         }
     });
 
-    RefreshInputProfiles();
+    UpdateInputProfiles();
 
     connect(ui->buttonProfilesNew, &QPushButton::clicked, this,
             &ConfigureInputPlayer::CreateProfile);
@@ -1132,10 +1132,13 @@ void ConfigureInputPlayer::CreateProfile() {
     if (!profiles->CreateProfile(profile_name.toStdString(), player_index)) {
         QMessageBox::critical(this, tr("Create Input Profile"),
                               tr("Failed to create the input profile \"%1\"").arg(profile_name));
-        RefreshInputProfiles();
+        UpdateInputProfiles();
+        emit RefreshInputProfiles(player_index);
         return;
     }
 
+    emit RefreshInputProfiles(player_index);
+
     ui->comboProfiles->addItem(profile_name);
     ui->comboProfiles->setCurrentIndex(ui->comboProfiles->count() - 1);
 }
@@ -1150,10 +1153,13 @@ void ConfigureInputPlayer::DeleteProfile() {
     if (!profiles->DeleteProfile(profile_name.toStdString())) {
         QMessageBox::critical(this, tr("Delete Input Profile"),
                               tr("Failed to delete the input profile \"%1\"").arg(profile_name));
-        RefreshInputProfiles();
+        UpdateInputProfiles();
+        emit RefreshInputProfiles(player_index);
         return;
     }
 
+    emit RefreshInputProfiles(player_index);
+
     ui->comboProfiles->removeItem(ui->comboProfiles->currentIndex());
     ui->comboProfiles->setCurrentIndex(-1);
 }
@@ -1170,7 +1176,8 @@ void ConfigureInputPlayer::LoadProfile() {
     if (!profiles->LoadProfile(profile_name.toStdString(), player_index)) {
         QMessageBox::critical(this, tr("Load Input Profile"),
                               tr("Failed to load the input profile \"%1\"").arg(profile_name));
-        RefreshInputProfiles();
+        UpdateInputProfiles();
+        emit RefreshInputProfiles(player_index);
         return;
     }
 
@@ -1189,12 +1196,13 @@ void ConfigureInputPlayer::SaveProfile() {
     if (!profiles->SaveProfile(profile_name.toStdString(), player_index)) {
         QMessageBox::critical(this, tr("Save Input Profile"),
                               tr("Failed to save the input profile \"%1\"").arg(profile_name));
-        RefreshInputProfiles();
+        UpdateInputProfiles();
+        emit RefreshInputProfiles(player_index);
         return;
     }
 }
 
-void ConfigureInputPlayer::RefreshInputProfiles() {
+void ConfigureInputPlayer::UpdateInputProfiles() {
     ui->comboProfiles->clear();
 
     for (const auto& profile_name : profiles->GetInputProfileNames()) {
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index 4895e8850..23cf6f958 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -59,6 +59,9 @@ public:
     /// Update the input devices combobox.
     void UpdateInputDeviceCombobox();
 
+    /// Updates the list of controller profiles.
+    void UpdateInputProfiles();
+
     /// Restore all buttons to their default values.
     void RestoreDefaults();
 
@@ -72,6 +75,12 @@ signals:
     void HandheldStateChanged(bool is_handheld);
     /// Emitted when the input devices combobox is being refreshed.
     void RefreshInputDevices();
+    /**
+     * Emitted when the input profiles combobox is being refreshed.
+     * The player_index represents the current player's index, and the profile combobox
+     * will not be updated for this index as they are already updated by other mechanisms.
+     */
+    void RefreshInputProfiles(std::size_t player_index);
 
 protected:
     void showEvent(QShowEvent* event) override;
@@ -130,9 +139,6 @@ private:
     /// Saves the current controller configuration into a selected controller profile.
     void SaveProfile();
 
-    /// Refreshes the list of controller profiles.
-    void RefreshInputProfiles();
-
     std::unique_ptr<Ui::ConfigureInputPlayer> ui;
 
     std::size_t player_index;

From d8ad2f3484af7a10251a7b1ced19433b55de8ce7 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sat, 31 Oct 2020 06:21:10 -0400
Subject: [PATCH 34/37] controllers/npad: Load input devices on init

---
 src/core/hle/service/hid/controllers/npad.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 30715267c..a606ceeec 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -214,6 +214,8 @@ void Controller_NPad::OnInit() {
         return;
     }
 
+    OnLoadInputDevices();
+
     if (style.raw == 0) {
         // We want to support all controllers
         style.handheld.Assign(1);

From ad502093835868d5d3ae43caa9faa28c8cb621f2 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Tue, 10 Nov 2020 12:09:44 -0500
Subject: [PATCH 35/37] hid: Reimplement Begin/EndPermitVibrationSession

Upon further investigation, these commands allow temporary vibrations even when the "Controller Vibration" system setting is disabled. As a result, vibrations are allowed when either the system setting or this flag is set to true. Therefore, we can only block vibrations when both flags are set to false.
---
 src/core/hle/service/hid/controllers/npad.cpp |  8 ++++++--
 src/core/hle/service/hid/controllers/npad.h   |  3 +++
 src/core/hle/service/hid/hid.cpp              | 11 ++++++++---
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index a606ceeec..e2539ded8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -734,7 +734,7 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size
 
 void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle,
                                         const VibrationValue& vibration_value) {
-    if (!Settings::values.vibration_enabled.GetValue()) {
+    if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
         return;
     }
 
@@ -774,7 +774,7 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han
 
 void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
                                          const std::vector<VibrationValue>& vibration_values) {
-    if (!Settings::values.vibration_enabled.GetValue()) {
+    if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
         return;
     }
 
@@ -811,6 +811,10 @@ void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index,
     }
 }
 
+void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
+    permit_vibration_session_enabled = permit_vibration_session;
+}
+
 bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const {
     const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
     const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 99384524b..160dcbbe3 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -163,6 +163,8 @@ public:
 
     void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index);
 
+    void SetPermitVibrationSession(bool permit_vibration_session);
+
     bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;
 
     std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
@@ -426,6 +428,7 @@ private:
     std::array<Kernel::EventPair, 10> styleset_changed_events;
     std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints;
     std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
+    bool permit_vibration_session_enabled{false};
     std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
     std::array<ControllerHolder, 10> connected_controllers{};
     std::array<bool, 10> unintended_home_button_input_protection{};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 2e9682bed..902516b29 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1119,15 +1119,20 @@ void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
-                applet_resource_user_id);
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetPermitVibrationSession(true);
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
 }
 
 void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
-    LOG_WARNING(Service_HID, "(STUBBED) called");
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetPermitVibrationSession(false);
+
+    LOG_DEBUG(Service_HID, "called");
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);

From b254d528bcdd8d826c87ef720b2c247a08cc5049 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Wed, 11 Nov 2020 07:46:41 -0500
Subject: [PATCH 36/37] configure_input: Accommodate for the mouse input device
 engine

---
 .../configuration/configure_input_player.cpp   | 18 +++++++++++++++++-
 src/yuzu/configuration/configure_vibration.cpp |  2 +-
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index f65a7fe73..72640f5e7 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -694,6 +694,8 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() {
     const auto current_guid = button_param->Get("guid", "");
     const auto current_port = button_param->Get("port", "");
 
+    const bool is_keyboard_mouse = current_engine == "keyboard" || current_engine == "mouse";
+
     UpdateInputDevices();
 
     if (buttons_empty) {
@@ -702,13 +704,22 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() {
 
     const bool all_one_device =
         std::all_of(buttons_param.begin(), buttons_param.end(),
-                    [current_engine, current_guid, current_port](const Common::ParamPackage param) {
+                    [current_engine, current_guid, current_port,
+                     is_keyboard_mouse](const Common::ParamPackage param) {
+                        if (is_keyboard_mouse) {
+                            return !param.Has("engine") || param.Get("engine", "") == "keyboard" ||
+                                   param.Get("engine", "") == "mouse";
+                        }
                         return !param.Has("engine") || (param.Get("engine", "") == current_engine &&
                                                         param.Get("guid", "") == current_guid &&
                                                         param.Get("port", "") == current_port);
                     });
 
     if (all_one_device) {
+        if (is_keyboard_mouse) {
+            ui->comboDevices->setCurrentIndex(1);
+            return;
+        }
         const auto devices_it = std::find_if(
             input_devices.begin(), input_devices.end(),
             [current_engine, current_guid, current_port](const Common::ParamPackage param) {
@@ -1073,6 +1084,11 @@ bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params)
         return true;
     }
 
+    // Keyboard/Mouse
+    if (ui->comboDevices->currentIndex() == 1) {
+        return params.Get("engine", "") == "keyboard" || params.Get("engine", "") == "mouse";
+    }
+
     const auto current_input_device = input_devices[ui->comboDevices->currentIndex()];
     return params.Get("engine", "") == current_input_device.Get("class", "") &&
            params.Get("guid", "") == current_input_device.Get("guid", "") &&
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp
index 714db5b80..7dcb2c5b9 100644
--- a/src/yuzu/configuration/configure_vibration.cpp
+++ b/src/yuzu/configuration/configure_vibration.cpp
@@ -99,7 +99,7 @@ void ConfigureVibration::SetVibrationDevices(std::size_t player_index) {
         const auto guid = param.Get("guid", "");
         const auto port = param.Get("port", "");
 
-        if (engine.empty() || engine == "keyboard") {
+        if (engine.empty() || engine == "keyboard" || engine == "mouse") {
             continue;
         }
 

From e7e8a87927899b69bfe9f8e38f26dac08ec37abe Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 15 Nov 2020 23:32:58 -0500
Subject: [PATCH 37/37] sdl_impl: Pump SDL Events at 1000 Hz

---
 src/input_common/sdl/sdl_impl.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 6024ed97a..8c48bb861 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -698,7 +698,7 @@ SDLState::SDLState() {
             using namespace std::chrono_literals;
             while (initialized) {
                 SDL_PumpEvents();
-                std::this_thread::sleep_for(5ms);
+                std::this_thread::sleep_for(1ms);
             }
         });
     }