diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index 5582091f4bd178b2597ad70ab564e8b5aabdfcbf..1ac2fb80c83efe983fb017907a137734fe692e81 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 1acc82497f31ba0d3d91153ebe41b683afd048bb..b9a270a55c98fedaf67edae7ea616960a184fff2 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 2ce742e3598e6f3c1aa2fa5be3b7adeca07daf6e..eb097738a9754c2534c5ba441c728edb43f852a9 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 a0152b4ea1a22afa0e9d2b894e92232f3ca73e61..43b79412e6313377d913f4507500151252167628 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 25a886238c8d5877c673b14edff30bc8e25d6be4..ce993bad3072a84006498c38e2b9754ec7eb17b0 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 c4b26196a6e784623c84f080d68cde104c9cdb6e..15d5fa6e8d11edff4f9adc7b3a26c1891c2c96f4 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 50f709b259a5fe5a742318983b86cd5773f96ef4..fb57dec02e375c0d2d945f3c0609d6ad4ed26add 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 5b0e371fe9f043d37230ffa6b8a2adbdd1f0bbf7..55e00dd93b90dca12814c473c9462d9243a9d899 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 0587b93744dc1d5c3e44d1714426bab8e270e6d5..aadbc3932d28325e9bc628609bf3724e96c41165 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 28616a5749299ce608e653bfc5adf2822be49935..edd2a00ca41d31f246abb4d5d58113fdf43ca53c 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;
+
+    Setting<bool> use_docked_mode;
 
-    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 ebc19e18ab2402ec58d3f1df51b48ad71f547271..e0908186b2454fd480fe8a3fcf9d6e5ac50ec332 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 ee770f3152fd004e0f8a5e0a3a5c43cf21607752..7697fe4341bd902027b2f46bc3419cc818c07749 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 618f991b05cc0d0555ac7e292e04ec0604e9908c..296c58f58b3595cfd75bc943f64f56006ee0325e 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 523ece426683b1950ea13f591788038d1e1d4e45..9a4de4c5d5edbd3559c9f10d686ed8a04a1092dd 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 3715db0abec3819379b4fbc5aa34392b4c693708..3074be833e977ffcefb397639277d70ee3493661 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 b4de2f6afdf29872bc8ade3961087f705e557b8e..213a76224605fe7a846f4d1271eb1f342e0d010b 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 4a3dea2a5810891d08939a3df2311a44a58aaa33..54a46827fc1c6ac96bc7405ed75b253e028f760c 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 334038ef938809693b9f47609e19c6dafb6644ec..feee02fcdcc5bb5c296c0572a4093eeaa42de9aa 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 bc273fb517bdb4cb71b12fe6e378b58b04039ea8..3a8a333f0196dc5707c5c0ba68587d03d4d70426 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 =