diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs
index e9c163cf2..0cb49ca8c 100644
--- a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs
+++ b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs
@@ -1,7 +1,5 @@
 namespace Ryujinx.Common.Configuration.Hid
 {
-    // NOTE: Please don't change this to struct.
-    //       This breaks Avalonia's TwoWay binding, which makes us unable to save new KeyboardHotkeys.
     public class KeyboardHotkeys
     {
         public Key ToggleVsync { get; set; }
diff --git a/src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs b/src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs
new file mode 100644
index 000000000..5a8ca96a1
--- /dev/null
+++ b/src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs
@@ -0,0 +1,158 @@
+using Ryujinx.Common.Configuration.Hid.Controller;
+using Ryujinx.Input;
+using System;
+using System.Collections.Generic;
+using Key = Ryujinx.Common.Configuration.Hid.Key;
+using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
+
+namespace Ryujinx.UI.Helper
+{
+    public static class ButtonHelper
+    {
+        private static readonly Dictionary<Key, string> _keysMap = new()
+        {
+            { Key.Unknown, "Unknown" },
+            { Key.ShiftLeft, "ShiftLeft" },
+            { Key.ShiftRight, "ShiftRight" },
+            { Key.ControlLeft, "CtrlLeft" },
+            { Key.ControlRight, "CtrlRight" },
+            { Key.AltLeft, OperatingSystem.IsMacOS() ? "OptLeft" : "AltLeft" },
+            { Key.AltRight, OperatingSystem.IsMacOS() ? "OptRight" : "AltRight" },
+            { Key.WinLeft, OperatingSystem.IsMacOS() ? "CmdLeft" : "WinLeft" },
+            { Key.WinRight, OperatingSystem.IsMacOS() ? "CmdRight" : "WinRight" },
+            { Key.Up, "Up" },
+            { Key.Down, "Down" },
+            { Key.Left, "Left" },
+            { Key.Right, "Right" },
+            { Key.Enter, "Enter" },
+            { Key.Escape, "Escape" },
+            { Key.Space, "Space" },
+            { Key.Tab, "Tab" },
+            { Key.BackSpace, "Backspace" },
+            { Key.Insert, "Insert" },
+            { Key.Delete, "Delete" },
+            { Key.PageUp, "PageUp" },
+            { Key.PageDown, "PageDown" },
+            { Key.Home, "Home" },
+            { Key.End, "End" },
+            { Key.CapsLock, "CapsLock" },
+            { Key.ScrollLock, "ScrollLock" },
+            { Key.PrintScreen, "PrintScreen" },
+            { Key.Pause, "Pause" },
+            { Key.NumLock, "NumLock" },
+            { Key.Clear, "Clear" },
+            { Key.Keypad0, "Keypad0" },
+            { Key.Keypad1, "Keypad1" },
+            { Key.Keypad2, "Keypad2" },
+            { Key.Keypad3, "Keypad3" },
+            { Key.Keypad4, "Keypad4" },
+            { Key.Keypad5, "Keypad5" },
+            { Key.Keypad6, "Keypad6" },
+            { Key.Keypad7, "Keypad7" },
+            { Key.Keypad8, "Keypad8" },
+            { Key.Keypad9, "Keypad9" },
+            { Key.KeypadDivide, "KeypadDivide" },
+            { Key.KeypadMultiply, "KeypadMultiply" },
+            { Key.KeypadSubtract, "KeypadSubtract" },
+            { Key.KeypadAdd, "KeypadAdd" },
+            { Key.KeypadDecimal, "KeypadDecimal" },
+            { Key.KeypadEnter, "KeypadEnter" },
+            { Key.Number0, "0" },
+            { Key.Number1, "1" },
+            { Key.Number2, "2" },
+            { Key.Number3, "3" },
+            { Key.Number4, "4" },
+            { Key.Number5, "5" },
+            { Key.Number6, "6" },
+            { Key.Number7, "7" },
+            { Key.Number8, "8" },
+            { Key.Number9, "9" },
+            { Key.Tilde, "~" },
+            { Key.Grave, "`" },
+            { Key.Minus, "-" },
+            { Key.Plus, "+" },
+            { Key.BracketLeft, "[" },
+            { Key.BracketRight, "]" },
+            { Key.Semicolon, ";" },
+            { Key.Quote, "'" },
+            { Key.Comma, "," },
+            { Key.Period, "." },
+            { Key.Slash, "/" },
+            { Key.BackSlash, "\\" },
+            { Key.Unbound, "Unbound" },
+        };
+
+        private static readonly Dictionary<GamepadInputId, string> _gamepadInputIdMap = new()
+        {
+            { GamepadInputId.LeftStick, "LeftStick" },
+            { GamepadInputId.RightStick, "RightStick" },
+            { GamepadInputId.LeftShoulder, "LeftShoulder" },
+            { GamepadInputId.RightShoulder, "RightShoulder" },
+            { GamepadInputId.LeftTrigger, "LeftTrigger" },
+            { GamepadInputId.RightTrigger, "RightTrigger" },
+            { GamepadInputId.DpadUp, "DpadUp" },
+            { GamepadInputId.DpadDown, "DpadDown" },
+            { GamepadInputId.DpadLeft, "DpadLeft" },
+            { GamepadInputId.DpadRight, "DpadRight" },
+            { GamepadInputId.Minus, "Minus" },
+            { GamepadInputId.Plus, "Plus" },
+            { GamepadInputId.Guide, "Guide" },
+            { GamepadInputId.Misc1, "Misc1" },
+            { GamepadInputId.Paddle1, "Paddle1" },
+            { GamepadInputId.Paddle2, "Paddle2" },
+            { GamepadInputId.Paddle3, "Paddle3" },
+            { GamepadInputId.Paddle4, "Paddle4" },
+            { GamepadInputId.Touchpad, "Touchpad" },
+            { GamepadInputId.SingleLeftTrigger0, "SingleLeftTrigger0" },
+            { GamepadInputId.SingleRightTrigger0, "SingleRightTrigger0" },
+            { GamepadInputId.SingleLeftTrigger1, "SingleLeftTrigger1" },
+            { GamepadInputId.SingleRightTrigger1, "SingleRightTrigger1" },
+            { GamepadInputId.Unbound, "Unbound" },
+        };
+
+        private static readonly Dictionary<StickInputId, string> _stickInputIdMap = new()
+        {
+            { StickInputId.Left, "StickLeft" },
+            { StickInputId.Right, "StickRight" },
+            { StickInputId.Unbound, "Unbound" },
+        };
+
+        public static string ToString(Button button)
+        {
+            string keyString = "";
+
+            switch (button.Type)
+            {
+                case ButtonType.Key:
+                    var key = button.AsHidType<Key>();
+
+                    if (!_keysMap.TryGetValue(button.AsHidType<Key>(), out keyString))
+                    {
+                        keyString = key.ToString();
+                    }
+
+                    break;
+                case ButtonType.GamepadButtonInputId:
+                    var gamepadButton = button.AsHidType<GamepadInputId>();
+
+                    if (!_gamepadInputIdMap.TryGetValue(button.AsHidType<GamepadInputId>(), out keyString))
+                    {
+                        keyString = gamepadButton.ToString();
+                    }
+
+                    break;
+                case ButtonType.StickId:
+                    var stickInput = button.AsHidType<StickInputId>();
+
+                    if (!_stickInputIdMap.TryGetValue(button.AsHidType<StickInputId>(), out keyString))
+                    {
+                        keyString = stickInput.ToString();
+                    }
+
+                    break;
+            }
+
+            return keyString;
+        }
+    }
+}
diff --git a/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs b/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs
index 6712657f8..d0b8266f4 100644
--- a/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs
+++ b/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs
@@ -10,6 +10,7 @@ using Ryujinx.Input;
 using Ryujinx.Input.Assigner;
 using Ryujinx.Input.GTK3;
 using Ryujinx.UI.Common.Configuration;
+using Ryujinx.UI.Helper;
 using Ryujinx.UI.Widgets;
 using System;
 using System.Collections.Generic;
@@ -17,6 +18,7 @@ using System.IO;
 using System.Reflection;
 using System.Text.Json;
 using System.Threading;
+using Button = Ryujinx.Input.Button;
 using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
 using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
 using GUI = Gtk.Builder.ObjectAttribute;
@@ -887,13 +889,13 @@ namespace Ryujinx.UI.Windows
                     Thread.Sleep(10);
                     assigner.ReadInput();
 
-                    if (_mousePressed || keyboard.IsPressed(Ryujinx.Input.Key.Escape) || assigner.HasAnyButtonPressed() || assigner.ShouldCancel())
+                    if (_mousePressed || keyboard.IsPressed(Ryujinx.Input.Key.Escape) || assigner.IsAnyButtonPressed() || assigner.ShouldCancel())
                     {
                         break;
                     }
                 }
 
-                string pressedButton = assigner.GetPressedButton();
+                string pressedButton = ButtonHelper.ToString(assigner.GetPressedButton() ?? new Button(Input.Key.Unknown));
 
                 Application.Invoke(delegate
                 {
diff --git a/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs b/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs
index 388ebcc07..80fed2b82 100644
--- a/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs
+++ b/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs
@@ -49,9 +49,9 @@ namespace Ryujinx.Input.Assigner
             CollectButtonStats();
         }
 
-        public bool HasAnyButtonPressed()
+        public bool IsAnyButtonPressed()
         {
-            return _detector.HasAnyButtonPressed();
+            return _detector.IsAnyButtonPressed();
         }
 
         public bool ShouldCancel()
@@ -59,16 +59,11 @@ namespace Ryujinx.Input.Assigner
             return _gamepad == null || !_gamepad.IsConnected;
         }
 
-        public string GetPressedButton()
+        public Button? GetPressedButton()
         {
             IEnumerable<GamepadButtonInputId> pressedButtons = _detector.GetPressedButtons();
 
-            if (pressedButtons.Any())
-            {
-                return !_forStick ? pressedButtons.First().ToString() : ((StickInputId)pressedButtons.First()).ToString();
-            }
-
-            return "";
+            return !_forStick ? new(pressedButtons.FirstOrDefault()) : new((StickInputId)pressedButtons.FirstOrDefault());
         }
 
         private void CollectButtonStats()
@@ -123,7 +118,7 @@ namespace Ryujinx.Input.Assigner
                 _stats = new Dictionary<GamepadButtonInputId, InputSummary>();
             }
 
-            public bool HasAnyButtonPressed()
+            public bool IsAnyButtonPressed()
             {
                 return _stats.Values.Any(CheckButtonPressed);
             }
diff --git a/src/Ryujinx.Input/Assigner/IButtonAssigner.cs b/src/Ryujinx.Input/Assigner/IButtonAssigner.cs
index 76a9fece4..688fbddb4 100644
--- a/src/Ryujinx.Input/Assigner/IButtonAssigner.cs
+++ b/src/Ryujinx.Input/Assigner/IButtonAssigner.cs
@@ -19,7 +19,7 @@ namespace Ryujinx.Input.Assigner
         /// Check if a button was pressed.
         /// </summary>
         /// <returns>True if a button was pressed</returns>
-        bool HasAnyButtonPressed();
+        bool IsAnyButtonPressed();
 
         /// <summary>
         /// Indicate if the user of this API should cancel operations. This is triggered for example when a gamepad get disconnected or when a user cancel assignation operations.
@@ -31,6 +31,6 @@ namespace Ryujinx.Input.Assigner
         /// Get the pressed button that was read in <see cref="ReadInput"/> by the button assigner.
         /// </summary>
         /// <returns>The pressed button that was read</returns>
-        string GetPressedButton();
+        Button? GetPressedButton();
     }
 }
diff --git a/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs b/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs
index e52ef4a2c..3c011a63b 100644
--- a/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs
+++ b/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs
@@ -21,9 +21,9 @@ namespace Ryujinx.Input.Assigner
             _keyboardState = _keyboard.GetKeyboardStateSnapshot();
         }
 
-        public bool HasAnyButtonPressed()
+        public bool IsAnyButtonPressed()
         {
-            return GetPressedButton().Length != 0;
+            return GetPressedButton() is not null;
         }
 
         public bool ShouldCancel()
@@ -31,20 +31,20 @@ namespace Ryujinx.Input.Assigner
             return _keyboardState.IsPressed(Key.Escape);
         }
 
-        public string GetPressedButton()
+        public Button? GetPressedButton()
         {
-            string keyPressed = "";
+            Button? keyPressed = null;
 
             for (Key key = Key.Unknown; key < Key.Count; key++)
             {
                 if (_keyboardState.IsPressed(key))
                 {
-                    keyPressed = key.ToString();
+                    keyPressed = new(key);
                     break;
                 }
             }
 
-            return !ShouldCancel() ? keyPressed : "";
+            return !ShouldCancel() ? keyPressed : null;
         }
     }
 }
diff --git a/src/Ryujinx.Input/Button.cs b/src/Ryujinx.Input/Button.cs
new file mode 100644
index 000000000..4289901ce
--- /dev/null
+++ b/src/Ryujinx.Input/Button.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Ryujinx.Input
+{
+    public readonly struct Button
+    {
+        public readonly ButtonType Type;
+        private readonly uint _rawValue;
+
+        public Button(Key key)
+        {
+            Type = ButtonType.Key;
+            _rawValue = (uint)key;
+        }
+
+        public Button(GamepadButtonInputId gamepad)
+        {
+            Type = ButtonType.GamepadButtonInputId;
+            _rawValue = (uint)gamepad;
+        }
+
+        public Button(StickInputId stick)
+        {
+            Type = ButtonType.StickId;
+            _rawValue = (uint)stick;
+        }
+
+        public T AsHidType<T>() where T : Enum
+        {
+            return (T)Enum.ToObject(typeof(T), _rawValue);
+        }
+    }
+}
diff --git a/src/Ryujinx.Input/ButtonType.cs b/src/Ryujinx.Input/ButtonType.cs
new file mode 100644
index 000000000..25ef5eea8
--- /dev/null
+++ b/src/Ryujinx.Input/ButtonType.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Input
+{
+    public enum ButtonType
+    {
+        Key,
+        GamepadButtonInputId,
+        StickId,
+    }
+}
diff --git a/src/Ryujinx.Input/HLE/NpadController.cs b/src/Ryujinx.Input/HLE/NpadController.cs
index 8411c10a7..cde20f5d0 100644
--- a/src/Ryujinx.Input/HLE/NpadController.cs
+++ b/src/Ryujinx.Input/HLE/NpadController.cs
@@ -203,8 +203,6 @@ namespace Ryujinx.Input.HLE
             new(Key.NumLock,      10),
         };
 
-        private bool _isValid;
-
         private MotionInput _leftMotionInput;
         private MotionInput _rightMotionInput;
 
@@ -222,7 +220,6 @@ namespace Ryujinx.Input.HLE
         {
             State = default;
             Id = null;
-            _isValid = false;
             _cemuHookClient = cemuHookClient;
         }
 
@@ -234,11 +231,10 @@ namespace Ryujinx.Input.HLE
 
             Id = config.Id;
             _gamepad = GamepadDriver.GetGamepad(Id);
-            _isValid = _gamepad != null;
 
             UpdateUserConfiguration(config);
 
-            return _isValid;
+            return _gamepad != null;
         }
 
         public void UpdateUserConfiguration(InputConfig config)
@@ -262,10 +258,7 @@ namespace Ryujinx.Input.HLE
 
             _config = config;
 
-            if (_isValid)
-            {
-                _gamepad.SetConfiguration(config);
-            }
+            _gamepad?.SetConfiguration(config);
         }
 
         private void UpdateMotionInput(MotionConfigController motionConfig)
@@ -282,18 +275,21 @@ namespace Ryujinx.Input.HLE
 
         public void Update()
         {
-            if (_isValid && GamepadDriver != null)
+            // _gamepad may be altered by other threads
+            var gamepad = _gamepad;
+
+            if (gamepad != null && GamepadDriver != null)
             {
-                State = _gamepad.GetMappedStateSnapshot();
+                State = gamepad.GetMappedStateSnapshot();
 
                 if (_config is StandardControllerInputConfig controllerConfig && controllerConfig.Motion.EnableMotion)
                 {
                     if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.GamepadDriver)
                     {
-                        if (_gamepad.Features.HasFlag(GamepadFeaturesFlag.Motion))
+                        if (gamepad.Features.HasFlag(GamepadFeaturesFlag.Motion))
                         {
-                            Vector3 accelerometer = _gamepad.GetMotionData(MotionInputId.Accelerometer);
-                            Vector3 gyroscope = _gamepad.GetMotionData(MotionInputId.Gyroscope);
+                            Vector3 accelerometer = gamepad.GetMotionData(MotionInputId.Accelerometer);
+                            Vector3 gyroscope = gamepad.GetMotionData(MotionInputId.Gyroscope);
 
                             accelerometer = new Vector3(accelerometer.X, -accelerometer.Z, accelerometer.Y);
                             gyroscope = new Vector3(gyroscope.X, -gyroscope.Z, gyroscope.Y);
diff --git a/src/Ryujinx/Assets/Locales/en_US.json b/src/Ryujinx/Assets/Locales/en_US.json
index ef40fd5b2..77ad7d1f8 100644
--- a/src/Ryujinx/Assets/Locales/en_US.json
+++ b/src/Ryujinx/Assets/Locales/en_US.json
@@ -266,6 +266,107 @@
   "ControllerSettingsMotionGyroDeadzone": "Gyro Deadzone:",
   "ControllerSettingsSave": "Save",
   "ControllerSettingsClose": "Close",
+  "KeyUnknown": "Unknown",
+  "KeyShiftLeft": "Shift Left",
+  "KeyShiftRight": "Shift Right",
+  "KeyControlLeft": "Ctrl Left",
+  "KeyMacControlLeft": "⌃ Left",
+  "KeyControlRight": "Ctrl Right",
+  "KeyMacControlRight": "⌃ Right",
+  "KeyAltLeft": "Alt Left",
+  "KeyMacAltLeft": "⌥ Left",
+  "KeyAltRight": "Alt Right",
+  "KeyMacAltRight": "⌥ Right",
+  "KeyWinLeft": "⊞ Left",
+  "KeyMacWinLeft": "⌘ Left",
+  "KeyWinRight": "⊞ Right",
+  "KeyMacWinRight": "⌘ Right",
+  "KeyMenu": "Menu",
+  "KeyUp": "Up",
+  "KeyDown": "Down",
+  "KeyLeft": "Left",
+  "KeyRight": "Right",
+  "KeyEnter": "Enter",
+  "KeyEscape": "Escape",
+  "KeySpace": "Space",
+  "KeyTab": "Tab",
+  "KeyBackSpace": "Backspace",
+  "KeyInsert": "Insert",
+  "KeyDelete": "Delete",
+  "KeyPageUp": "Page Up",
+  "KeyPageDown": "Page Down",
+  "KeyHome": "Home",
+  "KeyEnd": "End",
+  "KeyCapsLock": "Caps Lock",
+  "KeyScrollLock": "Scroll Lock",
+  "KeyPrintScreen": "Print Screen",
+  "KeyPause": "Pause",
+  "KeyNumLock": "Num Lock",
+  "KeyClear": "Clear",
+  "KeyKeypad0": "Keypad 0",
+  "KeyKeypad1": "Keypad 1",
+  "KeyKeypad2": "Keypad 2",
+  "KeyKeypad3": "Keypad 3",
+  "KeyKeypad4": "Keypad 4",
+  "KeyKeypad5": "Keypad 5",
+  "KeyKeypad6": "Keypad 6",
+  "KeyKeypad7": "Keypad 7",
+  "KeyKeypad8": "Keypad 8",
+  "KeyKeypad9": "Keypad 9",
+  "KeyKeypadDivide": "Keypad Divide",
+  "KeyKeypadMultiply": "Keypad Multiply",
+  "KeyKeypadSubtract": "Keypad Subtract",
+  "KeyKeypadAdd": "Keypad Add",
+  "KeyKeypadDecimal": "Keypad Decimal",
+  "KeyKeypadEnter": "Keypad Enter",
+  "KeyNumber0": "0",
+  "KeyNumber1": "1",
+  "KeyNumber2": "2",
+  "KeyNumber3": "3",
+  "KeyNumber4": "4",
+  "KeyNumber5": "5",
+  "KeyNumber6": "6",
+  "KeyNumber7": "7",
+  "KeyNumber8": "8",
+  "KeyNumber9": "9",
+  "KeyTilde": "~",
+  "KeyGrave": "`",
+  "KeyMinus": "-",
+  "KeyPlus": "+",
+  "KeyBracketLeft": "[",
+  "KeyBracketRight": "]",
+  "KeySemicolon": ";",
+  "KeyQuote": "\"",
+  "KeyComma": ",",
+  "KeyPeriod": ".",
+  "KeySlash": "/",
+  "KeyBackSlash": "\\",
+  "KeyUnbound": "Unbound",
+  "GamepadLeftStick": "L Stick Button",
+  "GamepadRightStick": "R Stick Button",
+  "GamepadLeftShoulder": "Left Shoulder",
+  "GamepadRightShoulder": "Right Shoulder",
+  "GamepadLeftTrigger": "Left Trigger",
+  "GamepadRightTrigger": "Right Trigger",
+  "GamepadDpadUp": "Up",
+  "GamepadDpadDown": "Down",
+  "GamepadDpadLeft": "Left",
+  "GamepadDpadRight": "Right",
+  "GamepadMinus": "-",
+  "GamepadPlus": "+",
+  "GamepadGuide": "Guide",
+  "GamepadMisc1": "Misc",
+  "GamepadPaddle1": "Paddle 1",
+  "GamepadPaddle2": "Paddle 2",
+  "GamepadPaddle3": "Paddle 3",
+  "GamepadPaddle4": "Paddle 4",
+  "GamepadTouchpad": "Touchpad",
+  "GamepadSingleLeftTrigger0": "Left Trigger 0",
+  "GamepadSingleRightTrigger0": "Right Trigger 0",
+  "GamepadSingleLeftTrigger1": "Left Trigger 1",
+  "GamepadSingleRightTrigger1": "Right Trigger 1",
+  "StickLeft": "Left Stick",
+  "StickRight": "Right Stick",
   "UserProfilesSelectedUserProfile": "Selected User Profile:",
   "UserProfilesSaveProfileName": "Save Profile Name",
   "UserProfilesChangeProfileImage": "Change Profile Image",
diff --git a/src/Ryujinx/Assets/Styles/Styles.xaml b/src/Ryujinx/Assets/Styles/Styles.xaml
index f7f64be22..b3a6f59c8 100644
--- a/src/Ryujinx/Assets/Styles/Styles.xaml
+++ b/src/Ryujinx/Assets/Styles/Styles.xaml
@@ -15,8 +15,7 @@
                             <MenuItem Header="Test 2" />
                             <MenuItem Header="Test 3">
                                 <MenuItem.Icon>
-                                    <CheckBox Margin="0"
-                                              IsChecked="{ReflectionBinding Checkbox, Mode=TwoWay}" />
+                                    <CheckBox Margin="0" />
                                 </MenuItem.Icon>
                             </MenuItem>
                         </MenuItem>
@@ -393,4 +392,4 @@
         <x:Double x:Key="ContentDialogMaxWidth">600</x:Double>
         <x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
     </Styles.Resources>
-</Styles>
\ No newline at end of file
+</Styles>
diff --git a/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs b/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs
index 7e8ba7342..4f2b8daae 100644
--- a/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs
+++ b/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs
@@ -1,11 +1,8 @@
-using Avalonia.Controls;
 using Avalonia.Controls.Primitives;
-using Avalonia.LogicalTree;
 using Avalonia.Threading;
 using Ryujinx.Input;
 using Ryujinx.Input.Assigner;
 using System;
-using System.Linq;
 using System.Threading.Tasks;
 
 namespace Ryujinx.Ava.UI.Helpers
@@ -15,12 +12,12 @@ namespace Ryujinx.Ava.UI.Helpers
         internal class ButtonAssignedEventArgs : EventArgs
         {
             public ToggleButton Button { get; }
-            public bool IsAssigned { get; }
+            public Button? ButtonValue { get; }
 
-            public ButtonAssignedEventArgs(ToggleButton button, bool isAssigned)
+            public ButtonAssignedEventArgs(ToggleButton button, Button? buttonValue)
             {
                 Button = button;
-                IsAssigned = isAssigned;
+                ButtonValue = buttonValue;
             }
         }
 
@@ -69,7 +66,7 @@ namespace Ryujinx.Ava.UI.Helpers
 
                     assigner.ReadInput();
 
-                    if (assigner.HasAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape)))
+                    if (assigner.IsAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape)))
                     {
                         break;
                     }
@@ -78,15 +75,11 @@ namespace Ryujinx.Ava.UI.Helpers
 
             await Dispatcher.UIThread.InvokeAsync(() =>
             {
-                string pressedButton = assigner.GetPressedButton();
+                Button? pressedButton = assigner.GetPressedButton();
 
                 if (_shouldUnbind)
                 {
-                    SetButtonText(ToggledButton, "Unbound");
-                }
-                else if (pressedButton != "")
-                {
-                    SetButtonText(ToggledButton, pressedButton);
+                    pressedButton = null;
                 }
 
                 _shouldUnbind = false;
@@ -94,17 +87,8 @@ namespace Ryujinx.Ava.UI.Helpers
 
                 ToggledButton.IsChecked = false;
 
-                ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton != null));
+                ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton));
 
-                static void SetButtonText(ToggleButton button, string text)
-                {
-                    ILogical textBlock = button.GetLogicalDescendants().First(x => x is TextBlock);
-
-                    if (textBlock != null && textBlock is TextBlock block)
-                    {
-                        block.Text = text;
-                    }
-                }
             });
         }
 
diff --git a/src/Ryujinx/UI/Helpers/KeyValueConverter.cs b/src/Ryujinx/UI/Helpers/KeyValueConverter.cs
index 028ed6bf4..cbcf16ab3 100644
--- a/src/Ryujinx/UI/Helpers/KeyValueConverter.cs
+++ b/src/Ryujinx/UI/Helpers/KeyValueConverter.cs
@@ -1,7 +1,9 @@
 using Avalonia.Data.Converters;
+using Ryujinx.Ava.Common.Locale;
 using Ryujinx.Common.Configuration.Hid;
 using Ryujinx.Common.Configuration.Hid.Controller;
 using System;
+using System.Collections.Generic;
 using System.Globalization;
 
 namespace Ryujinx.Ava.UI.Helpers
@@ -10,37 +12,173 @@ namespace Ryujinx.Ava.UI.Helpers
     {
         public static KeyValueConverter Instance = new();
 
+        private static readonly Dictionary<Key, LocaleKeys> _keysMap = new()
+        {
+            { Key.Unknown, LocaleKeys.KeyUnknown },
+            { Key.ShiftLeft, LocaleKeys.KeyShiftLeft },
+            { Key.ShiftRight, LocaleKeys.KeyShiftRight },
+            { Key.ControlLeft, LocaleKeys.KeyControlLeft },
+            { Key.ControlRight, LocaleKeys.KeyControlRight },
+            { Key.AltLeft, LocaleKeys.KeyControlLeft },
+            { Key.AltRight, LocaleKeys.KeyControlRight },
+            { Key.WinLeft, LocaleKeys.KeyWinLeft },
+            { Key.WinRight, LocaleKeys.KeyWinRight },
+            { Key.Up, LocaleKeys.KeyUp },
+            { Key.Down, LocaleKeys.KeyDown },
+            { Key.Left, LocaleKeys.KeyLeft },
+            { Key.Right, LocaleKeys.KeyRight },
+            { Key.Enter, LocaleKeys.KeyEnter },
+            { Key.Escape, LocaleKeys.KeyEscape },
+            { Key.Space, LocaleKeys.KeySpace },
+            { Key.Tab, LocaleKeys.KeyTab },
+            { Key.BackSpace, LocaleKeys.KeyBackSpace },
+            { Key.Insert, LocaleKeys.KeyInsert },
+            { Key.Delete, LocaleKeys.KeyDelete },
+            { Key.PageUp, LocaleKeys.KeyPageUp },
+            { Key.PageDown, LocaleKeys.KeyPageDown },
+            { Key.Home, LocaleKeys.KeyHome },
+            { Key.End, LocaleKeys.KeyEnd },
+            { Key.CapsLock, LocaleKeys.KeyCapsLock },
+            { Key.ScrollLock, LocaleKeys.KeyScrollLock },
+            { Key.PrintScreen, LocaleKeys.KeyPrintScreen },
+            { Key.Pause, LocaleKeys.KeyPause },
+            { Key.NumLock, LocaleKeys.KeyNumLock },
+            { Key.Clear, LocaleKeys.KeyClear },
+            { Key.Keypad0, LocaleKeys.KeyKeypad0 },
+            { Key.Keypad1, LocaleKeys.KeyKeypad1 },
+            { Key.Keypad2, LocaleKeys.KeyKeypad2 },
+            { Key.Keypad3, LocaleKeys.KeyKeypad3 },
+            { Key.Keypad4, LocaleKeys.KeyKeypad4 },
+            { Key.Keypad5, LocaleKeys.KeyKeypad5 },
+            { Key.Keypad6, LocaleKeys.KeyKeypad6 },
+            { Key.Keypad7, LocaleKeys.KeyKeypad7 },
+            { Key.Keypad8, LocaleKeys.KeyKeypad8 },
+            { Key.Keypad9, LocaleKeys.KeyKeypad9 },
+            { Key.KeypadDivide, LocaleKeys.KeyKeypadDivide },
+            { Key.KeypadMultiply, LocaleKeys.KeyKeypadMultiply },
+            { Key.KeypadSubtract, LocaleKeys.KeyKeypadSubtract },
+            { Key.KeypadAdd, LocaleKeys.KeyKeypadAdd },
+            { Key.KeypadDecimal, LocaleKeys.KeyKeypadDecimal },
+            { Key.KeypadEnter, LocaleKeys.KeyKeypadEnter },
+            { Key.Number0, LocaleKeys.KeyNumber0 },
+            { Key.Number1, LocaleKeys.KeyNumber1 },
+            { Key.Number2, LocaleKeys.KeyNumber2 },
+            { Key.Number3, LocaleKeys.KeyNumber3 },
+            { Key.Number4, LocaleKeys.KeyNumber4 },
+            { Key.Number5, LocaleKeys.KeyNumber5 },
+            { Key.Number6, LocaleKeys.KeyNumber6 },
+            { Key.Number7, LocaleKeys.KeyNumber7 },
+            { Key.Number8, LocaleKeys.KeyNumber8 },
+            { Key.Number9, LocaleKeys.KeyNumber9 },
+            { Key.Tilde, LocaleKeys.KeyTilde },
+            { Key.Grave, LocaleKeys.KeyGrave },
+            { Key.Minus, LocaleKeys.KeyMinus },
+            { Key.Plus, LocaleKeys.KeyPlus },
+            { Key.BracketLeft, LocaleKeys.KeyBracketLeft },
+            { Key.BracketRight, LocaleKeys.KeyBracketRight },
+            { Key.Semicolon, LocaleKeys.KeySemicolon },
+            { Key.Quote, LocaleKeys.KeyQuote },
+            { Key.Comma, LocaleKeys.KeyComma },
+            { Key.Period, LocaleKeys.KeyPeriod },
+            { Key.Slash, LocaleKeys.KeySlash },
+            { Key.BackSlash, LocaleKeys.KeyBackSlash },
+            { Key.Unbound, LocaleKeys.KeyUnbound },
+        };
+
+        private static readonly Dictionary<GamepadInputId, LocaleKeys> _gamepadInputIdMap = new()
+        {
+            { GamepadInputId.LeftStick, LocaleKeys.GamepadLeftStick },
+            { GamepadInputId.RightStick, LocaleKeys.GamepadRightStick },
+            { GamepadInputId.LeftShoulder, LocaleKeys.GamepadLeftShoulder },
+            { GamepadInputId.RightShoulder, LocaleKeys.GamepadRightShoulder },
+            { GamepadInputId.LeftTrigger, LocaleKeys.GamepadLeftTrigger },
+            { GamepadInputId.RightTrigger, LocaleKeys.GamepadRightTrigger },
+            { GamepadInputId.DpadUp, LocaleKeys.GamepadDpadUp},
+            { GamepadInputId.DpadDown, LocaleKeys.GamepadDpadDown},
+            { GamepadInputId.DpadLeft, LocaleKeys.GamepadDpadLeft},
+            { GamepadInputId.DpadRight, LocaleKeys.GamepadDpadRight},
+            { GamepadInputId.Minus, LocaleKeys.GamepadMinus},
+            { GamepadInputId.Plus, LocaleKeys.GamepadPlus},
+            { GamepadInputId.Guide, LocaleKeys.GamepadGuide},
+            { GamepadInputId.Misc1, LocaleKeys.GamepadMisc1},
+            { GamepadInputId.Paddle1, LocaleKeys.GamepadPaddle1},
+            { GamepadInputId.Paddle2, LocaleKeys.GamepadPaddle2},
+            { GamepadInputId.Paddle3, LocaleKeys.GamepadPaddle3},
+            { GamepadInputId.Paddle4, LocaleKeys.GamepadPaddle4},
+            { GamepadInputId.Touchpad, LocaleKeys.GamepadTouchpad},
+            { GamepadInputId.SingleLeftTrigger0, LocaleKeys.GamepadSingleLeftTrigger0},
+            { GamepadInputId.SingleRightTrigger0, LocaleKeys.GamepadSingleRightTrigger0},
+            { GamepadInputId.SingleLeftTrigger1, LocaleKeys.GamepadSingleLeftTrigger1},
+            { GamepadInputId.SingleRightTrigger1, LocaleKeys.GamepadSingleRightTrigger1},
+            { GamepadInputId.Unbound, LocaleKeys.KeyUnbound},
+        };
+
+        private static readonly Dictionary<StickInputId, LocaleKeys> _stickInputIdMap = new()
+        {
+            { StickInputId.Left, LocaleKeys.StickLeft},
+            { StickInputId.Right, LocaleKeys.StickRight},
+            { StickInputId.Unbound, LocaleKeys.KeyUnbound},
+        };
+
         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            if (value == null)
+            string keyString = "";
+            LocaleKeys localeKey;
+
+            switch (value)
             {
-                return null;
+                case Key key:
+                    if (_keysMap.TryGetValue(key, out localeKey))
+                    {
+                        if (OperatingSystem.IsMacOS())
+                        {
+                            localeKey = localeKey switch
+                            {
+                                LocaleKeys.KeyControlLeft => LocaleKeys.KeyMacControlLeft,
+                                LocaleKeys.KeyControlRight => LocaleKeys.KeyMacControlRight,
+                                LocaleKeys.KeyAltLeft => LocaleKeys.KeyMacAltLeft,
+                                LocaleKeys.KeyAltRight => LocaleKeys.KeyMacAltRight,
+                                LocaleKeys.KeyWinLeft => LocaleKeys.KeyMacWinLeft,
+                                LocaleKeys.KeyWinRight => LocaleKeys.KeyMacWinRight,
+                                _ => localeKey
+                            };
+                        }
+
+                        keyString = LocaleManager.Instance[localeKey];
+                    }
+                    else
+                    {
+                        keyString = key.ToString();
+                    }
+                    break;
+                case GamepadInputId gamepadInputId:
+                    if (_gamepadInputIdMap.TryGetValue(gamepadInputId, out localeKey))
+                    {
+                        keyString = LocaleManager.Instance[localeKey];
+                    }
+                    else
+                    {
+                        keyString = gamepadInputId.ToString();
+                    }
+                    break;
+                case StickInputId stickInputId:
+                    if (_stickInputIdMap.TryGetValue(stickInputId, out localeKey))
+                    {
+                        keyString = LocaleManager.Instance[localeKey];
+                    }
+                    else
+                    {
+                        keyString = stickInputId.ToString();
+                    }
+                    break;
             }
 
-            return value.ToString();
+            return keyString;
         }
 
         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            object key = null;
-
-            if (value != null)
-            {
-                if (targetType == typeof(Key))
-                {
-                    key = Enum.Parse<Key>(value.ToString());
-                }
-                else if (targetType == typeof(GamepadInputId))
-                {
-                    key = Enum.Parse<GamepadInputId>(value.ToString());
-                }
-                else if (targetType == typeof(StickInputId))
-                {
-                    key = Enum.Parse<StickInputId>(value.ToString());
-                }
-            }
-
-            return key;
+            throw new NotSupportedException();
         }
     }
 }
diff --git a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
new file mode 100644
index 000000000..833670bdc
--- /dev/null
+++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
@@ -0,0 +1,580 @@
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Common.Configuration.Hid;
+using Ryujinx.Common.Configuration.Hid.Controller;
+using Ryujinx.Common.Configuration.Hid.Controller.Motion;
+using System;
+
+namespace Ryujinx.Ava.UI.Models.Input
+{
+    public class GamepadInputConfig : BaseModel
+    {
+        public bool EnableCemuHookMotion { get; set; }
+        public string DsuServerHost { get; set; }
+        public int DsuServerPort { get; set; }
+        public int Slot { get; set; }
+        public int AltSlot { get; set; }
+        public bool MirrorInput { get; set; }
+        public int Sensitivity { get; set; }
+        public double GyroDeadzone { get; set; }
+
+        public float WeakRumble { get; set; }
+        public float StrongRumble { get; set; }
+
+        public string Id { get; set; }
+        public ControllerType ControllerType { get; set; }
+        public PlayerIndex PlayerIndex { get; set; }
+
+        private StickInputId _leftJoystick;
+        public StickInputId LeftJoystick
+        {
+            get => _leftJoystick;
+            set
+            {
+                _leftJoystick = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _leftInvertStickX;
+        public bool LeftInvertStickX
+        {
+            get => _leftInvertStickX;
+            set
+            {
+                _leftInvertStickX = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _leftInvertStickY;
+        public bool LeftInvertStickY
+        {
+            get => _leftInvertStickY;
+            set
+            {
+                _leftInvertStickY = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _leftRotate90;
+        public bool LeftRotate90
+        {
+            get => _leftRotate90;
+            set
+            {
+                _leftRotate90 = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _leftStickButton;
+        public GamepadInputId LeftStickButton
+        {
+            get => _leftStickButton;
+            set
+            {
+                _leftStickButton = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private StickInputId _rightJoystick;
+        public StickInputId RightJoystick
+        {
+            get => _rightJoystick;
+            set
+            {
+                _rightJoystick = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _rightInvertStickX;
+        public bool RightInvertStickX
+        {
+            get => _rightInvertStickX;
+            set
+            {
+                _rightInvertStickX = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _rightInvertStickY;
+        public bool RightInvertStickY
+        {
+            get => _rightInvertStickY;
+            set
+            {
+                _rightInvertStickY = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _rightRotate90;
+        public bool RightRotate90
+        {
+            get => _rightRotate90;
+            set
+            {
+                _rightRotate90 = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _rightStickButton;
+        public GamepadInputId RightStickButton
+        {
+            get => _rightStickButton;
+            set
+            {
+                _rightStickButton = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _dpadUp;
+        public GamepadInputId DpadUp
+        {
+            get => _dpadUp;
+            set
+            {
+                _dpadUp = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _dpadDown;
+        public GamepadInputId DpadDown
+        {
+            get => _dpadDown;
+            set
+            {
+                _dpadDown = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _dpadLeft;
+        public GamepadInputId DpadLeft
+        {
+            get => _dpadLeft;
+            set
+            {
+                _dpadLeft = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _dpadRight;
+        public GamepadInputId DpadRight
+        {
+            get => _dpadRight;
+            set
+            {
+                _dpadRight = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonL;
+        public GamepadInputId ButtonL
+        {
+            get => _buttonL;
+            set
+            {
+                _buttonL = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonMinus;
+        public GamepadInputId ButtonMinus
+        {
+            get => _buttonMinus;
+            set
+            {
+                _buttonMinus = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _leftButtonSl;
+        public GamepadInputId LeftButtonSl
+        {
+            get => _leftButtonSl;
+            set
+            {
+                _leftButtonSl = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _leftButtonSr;
+        public GamepadInputId LeftButtonSr
+        {
+            get => _leftButtonSr;
+            set
+            {
+                _leftButtonSr = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonZl;
+        public GamepadInputId ButtonZl
+        {
+            get => _buttonZl;
+            set
+            {
+                _buttonZl = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonA;
+        public GamepadInputId ButtonA
+        {
+            get => _buttonA;
+            set
+            {
+                _buttonA = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonB;
+        public GamepadInputId ButtonB
+        {
+            get => _buttonB;
+            set
+            {
+                _buttonB = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonX;
+        public GamepadInputId ButtonX
+        {
+            get => _buttonX;
+            set
+            {
+                _buttonX = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonY;
+        public GamepadInputId ButtonY
+        {
+            get => _buttonY;
+            set
+            {
+                _buttonY = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonR;
+        public GamepadInputId ButtonR
+        {
+            get => _buttonR;
+            set
+            {
+                _buttonR = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonPlus;
+        public GamepadInputId ButtonPlus
+        {
+            get => _buttonPlus;
+            set
+            {
+                _buttonPlus = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _rightButtonSl;
+        public GamepadInputId RightButtonSl
+        {
+            get => _rightButtonSl;
+            set
+            {
+                _rightButtonSl = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _rightButtonSr;
+        public GamepadInputId RightButtonSr
+        {
+            get => _rightButtonSr;
+            set
+            {
+                _rightButtonSr = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private GamepadInputId _buttonZr;
+        public GamepadInputId ButtonZr
+        {
+            get => _buttonZr;
+            set
+            {
+                _buttonZr = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private float _deadzoneLeft;
+        public float DeadzoneLeft
+        {
+            get => _deadzoneLeft;
+            set
+            {
+                _deadzoneLeft = MathF.Round(value, 3);
+                OnPropertyChanged();
+            }
+        }
+
+        private float _deadzoneRight;
+        public float DeadzoneRight
+        {
+            get => _deadzoneRight;
+            set
+            {
+                _deadzoneRight = MathF.Round(value, 3);
+                OnPropertyChanged();
+            }
+        }
+
+        private float _rangeLeft;
+        public float RangeLeft
+        {
+            get => _rangeLeft;
+            set
+            {
+                _rangeLeft = MathF.Round(value, 3);
+                OnPropertyChanged();
+            }
+        }
+
+        private float _rangeRight;
+        public float RangeRight
+        {
+            get => _rangeRight;
+            set
+            {
+                _rangeRight = MathF.Round(value, 3);
+                OnPropertyChanged();
+            }
+        }
+
+        private float _triggerThreshold;
+        public float TriggerThreshold
+        {
+            get => _triggerThreshold;
+            set
+            {
+                _triggerThreshold = MathF.Round(value, 3);
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _enableMotion;
+        public bool EnableMotion
+        {
+            get => _enableMotion;
+            set
+            {
+                _enableMotion = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _enableRumble;
+        public bool EnableRumble
+        {
+            get => _enableRumble;
+            set
+            {
+                _enableRumble = value;
+                OnPropertyChanged();
+            }
+        }
+
+        public GamepadInputConfig(InputConfig config)
+        {
+            if (config != null)
+            {
+                Id = config.Id;
+                ControllerType = config.ControllerType;
+                PlayerIndex = config.PlayerIndex;
+
+                if (config is not StandardControllerInputConfig controllerInput)
+                {
+                    return;
+                }
+
+                LeftJoystick = controllerInput.LeftJoyconStick.Joystick;
+                LeftInvertStickX = controllerInput.LeftJoyconStick.InvertStickX;
+                LeftInvertStickY = controllerInput.LeftJoyconStick.InvertStickY;
+                LeftRotate90 = controllerInput.LeftJoyconStick.Rotate90CW;
+                LeftStickButton = controllerInput.LeftJoyconStick.StickButton;
+
+                RightJoystick = controllerInput.RightJoyconStick.Joystick;
+                RightInvertStickX = controllerInput.RightJoyconStick.InvertStickX;
+                RightInvertStickY = controllerInput.RightJoyconStick.InvertStickY;
+                RightRotate90 = controllerInput.RightJoyconStick.Rotate90CW;
+                RightStickButton = controllerInput.RightJoyconStick.StickButton;
+
+                DpadUp = controllerInput.LeftJoycon.DpadUp;
+                DpadDown = controllerInput.LeftJoycon.DpadDown;
+                DpadLeft = controllerInput.LeftJoycon.DpadLeft;
+                DpadRight = controllerInput.LeftJoycon.DpadRight;
+                ButtonL = controllerInput.LeftJoycon.ButtonL;
+                ButtonMinus = controllerInput.LeftJoycon.ButtonMinus;
+                LeftButtonSl = controllerInput.LeftJoycon.ButtonSl;
+                LeftButtonSr = controllerInput.LeftJoycon.ButtonSr;
+                ButtonZl = controllerInput.LeftJoycon.ButtonZl;
+
+                ButtonA = controllerInput.RightJoycon.ButtonA;
+                ButtonB = controllerInput.RightJoycon.ButtonB;
+                ButtonX = controllerInput.RightJoycon.ButtonX;
+                ButtonY = controllerInput.RightJoycon.ButtonY;
+                ButtonR = controllerInput.RightJoycon.ButtonR;
+                ButtonPlus = controllerInput.RightJoycon.ButtonPlus;
+                RightButtonSl = controllerInput.RightJoycon.ButtonSl;
+                RightButtonSr = controllerInput.RightJoycon.ButtonSr;
+                ButtonZr = controllerInput.RightJoycon.ButtonZr;
+
+                DeadzoneLeft = controllerInput.DeadzoneLeft;
+                DeadzoneRight = controllerInput.DeadzoneRight;
+                RangeLeft = controllerInput.RangeLeft;
+                RangeRight = controllerInput.RangeRight;
+                TriggerThreshold = controllerInput.TriggerThreshold;
+
+                if (controllerInput.Motion != null)
+                {
+                    EnableMotion = controllerInput.Motion.EnableMotion;
+                    GyroDeadzone = controllerInput.Motion.GyroDeadzone;
+                    Sensitivity = controllerInput.Motion.Sensitivity;
+
+                    if (controllerInput.Motion is CemuHookMotionConfigController cemuHook)
+                    {
+                        EnableCemuHookMotion = true;
+                        DsuServerHost = cemuHook.DsuServerHost;
+                        DsuServerPort = cemuHook.DsuServerPort;
+                        Slot = cemuHook.Slot;
+                        AltSlot = cemuHook.AltSlot;
+                        MirrorInput = cemuHook.MirrorInput;
+                    }
+                }
+
+                if (controllerInput.Rumble != null)
+                {
+                    EnableRumble = controllerInput.Rumble.EnableRumble;
+                    WeakRumble = controllerInput.Rumble.WeakRumble;
+                    StrongRumble = controllerInput.Rumble.StrongRumble;
+                }
+            }
+        }
+
+        public InputConfig GetConfig()
+        {
+            var config = new StandardControllerInputConfig
+            {
+                Id = Id,
+                Backend = InputBackendType.GamepadSDL2,
+                PlayerIndex = PlayerIndex,
+                ControllerType = ControllerType,
+                LeftJoycon = new LeftJoyconCommonConfig<GamepadInputId>
+                {
+                    DpadUp = DpadUp,
+                    DpadDown = DpadDown,
+                    DpadLeft = DpadLeft,
+                    DpadRight = DpadRight,
+                    ButtonL = ButtonL,
+                    ButtonMinus = ButtonMinus,
+                    ButtonSl = LeftButtonSl,
+                    ButtonSr = LeftButtonSr,
+                    ButtonZl = ButtonZl,
+                },
+                RightJoycon = new RightJoyconCommonConfig<GamepadInputId>
+                {
+                    ButtonA = ButtonA,
+                    ButtonB = ButtonB,
+                    ButtonX = ButtonX,
+                    ButtonY = ButtonY,
+                    ButtonPlus = ButtonPlus,
+                    ButtonSl = RightButtonSl,
+                    ButtonSr = RightButtonSr,
+                    ButtonR = ButtonR,
+                    ButtonZr = ButtonZr,
+                },
+                LeftJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>
+                {
+                    Joystick = LeftJoystick,
+                    InvertStickX = LeftInvertStickX,
+                    InvertStickY = LeftInvertStickY,
+                    Rotate90CW = LeftRotate90,
+                    StickButton = LeftStickButton,
+                },
+                RightJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>
+                {
+                    Joystick = RightJoystick,
+                    InvertStickX = RightInvertStickX,
+                    InvertStickY = RightInvertStickY,
+                    Rotate90CW = RightRotate90,
+                    StickButton = RightStickButton,
+                },
+                Rumble = new RumbleConfigController
+                {
+                    EnableRumble = EnableRumble,
+                    WeakRumble = WeakRumble,
+                    StrongRumble = StrongRumble,
+                },
+                Version = InputConfig.CurrentVersion,
+                DeadzoneLeft = DeadzoneLeft,
+                DeadzoneRight = DeadzoneRight,
+                RangeLeft = RangeLeft,
+                RangeRight = RangeRight,
+                TriggerThreshold = TriggerThreshold,
+            };
+
+            if (EnableCemuHookMotion)
+            {
+                config.Motion = new CemuHookMotionConfigController
+                {
+                    EnableMotion = EnableMotion,
+                    MotionBackend = MotionInputBackendType.CemuHook,
+                    GyroDeadzone = GyroDeadzone,
+                    Sensitivity = Sensitivity,
+                    DsuServerHost = DsuServerHost,
+                    DsuServerPort = DsuServerPort,
+                    Slot = Slot,
+                    AltSlot = AltSlot,
+                    MirrorInput = MirrorInput,
+                };
+            }
+            else
+            {
+                config.Motion = new StandardMotionConfigController
+                {
+                    EnableMotion = EnableMotion,
+                    MotionBackend = MotionInputBackendType.GamepadDriver,
+                    GyroDeadzone = GyroDeadzone,
+                    Sensitivity = Sensitivity,
+                };
+            }
+
+            return config;
+        }
+    }
+}
diff --git a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs
new file mode 100644
index 000000000..b5f53508b
--- /dev/null
+++ b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs
@@ -0,0 +1,141 @@
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Common.Configuration.Hid;
+
+namespace Ryujinx.Ava.UI.Models.Input
+{
+    public class HotkeyConfig : BaseModel
+    {
+        private Key _toggleVsync;
+        public Key ToggleVsync
+        {
+            get => _toggleVsync;
+            set
+            {
+                _toggleVsync = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _screenshot;
+        public Key Screenshot
+        {
+            get => _screenshot;
+            set
+            {
+                _screenshot = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _showUI;
+        public Key ShowUI
+        {
+            get => _showUI;
+            set
+            {
+                _showUI = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _pause;
+        public Key Pause
+        {
+            get => _pause;
+            set
+            {
+                _pause = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _toggleMute;
+        public Key ToggleMute
+        {
+            get => _toggleMute;
+            set
+            {
+                _toggleMute = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _resScaleUp;
+        public Key ResScaleUp
+        {
+            get => _resScaleUp;
+            set
+            {
+                _resScaleUp = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _resScaleDown;
+        public Key ResScaleDown
+        {
+            get => _resScaleDown;
+            set
+            {
+                _resScaleDown = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _volumeUp;
+        public Key VolumeUp
+        {
+            get => _volumeUp;
+            set
+            {
+                _volumeUp = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _volumeDown;
+        public Key VolumeDown
+        {
+            get => _volumeDown;
+            set
+            {
+                _volumeDown = value;
+                OnPropertyChanged();
+            }
+        }
+
+        public HotkeyConfig(KeyboardHotkeys config)
+        {
+            if (config != null)
+            {
+                ToggleVsync = config.ToggleVsync;
+                Screenshot = config.Screenshot;
+                ShowUI = config.ShowUI;
+                Pause = config.Pause;
+                ToggleMute = config.ToggleMute;
+                ResScaleUp = config.ResScaleUp;
+                ResScaleDown = config.ResScaleDown;
+                VolumeUp = config.VolumeUp;
+                VolumeDown = config.VolumeDown;
+            }
+        }
+
+        public KeyboardHotkeys GetConfig()
+        {
+            var config = new KeyboardHotkeys
+            {
+                ToggleVsync = ToggleVsync,
+                Screenshot = Screenshot,
+                ShowUI = ShowUI,
+                Pause = Pause,
+                ToggleMute = ToggleMute,
+                ResScaleUp = ResScaleUp,
+                ResScaleDown = ResScaleDown,
+                VolumeUp = VolumeUp,
+                VolumeDown = VolumeDown,
+            };
+
+            return config;
+        }
+    }
+}
diff --git a/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs b/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs
new file mode 100644
index 000000000..66f1f62a2
--- /dev/null
+++ b/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs
@@ -0,0 +1,422 @@
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Common.Configuration.Hid;
+using Ryujinx.Common.Configuration.Hid.Keyboard;
+
+namespace Ryujinx.Ava.UI.Models.Input
+{
+    public class KeyboardInputConfig : BaseModel
+    {
+        public string Id { get; set; }
+        public ControllerType ControllerType { get; set; }
+        public PlayerIndex PlayerIndex { get; set; }
+
+        private Key _leftStickUp;
+        public Key LeftStickUp
+        {
+            get => _leftStickUp;
+            set
+            {
+                _leftStickUp = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _leftStickDown;
+        public Key LeftStickDown
+        {
+            get => _leftStickDown;
+            set
+            {
+                _leftStickDown = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _leftStickLeft;
+        public Key LeftStickLeft
+        {
+            get => _leftStickLeft;
+            set
+            {
+                _leftStickLeft = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _leftStickRight;
+        public Key LeftStickRight
+        {
+            get => _leftStickRight;
+            set
+            {
+                _leftStickRight = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _leftStickButton;
+        public Key LeftStickButton
+        {
+            get => _leftStickButton;
+            set
+            {
+                _leftStickButton = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _rightStickUp;
+        public Key RightStickUp
+        {
+            get => _rightStickUp;
+            set
+            {
+                _rightStickUp = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _rightStickDown;
+        public Key RightStickDown
+        {
+            get => _rightStickDown;
+            set
+            {
+                _rightStickDown = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _rightStickLeft;
+        public Key RightStickLeft
+        {
+            get => _rightStickLeft;
+            set
+            {
+                _rightStickLeft = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _rightStickRight;
+        public Key RightStickRight
+        {
+            get => _rightStickRight;
+            set
+            {
+                _rightStickRight = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _rightStickButton;
+        public Key RightStickButton
+        {
+            get => _rightStickButton;
+            set
+            {
+                _rightStickButton = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _dpadUp;
+        public Key DpadUp
+        {
+            get => _dpadUp;
+            set
+            {
+                _dpadUp = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _dpadDown;
+        public Key DpadDown
+        {
+            get => _dpadDown;
+            set
+            {
+                _dpadDown = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _dpadLeft;
+        public Key DpadLeft
+        {
+            get => _dpadLeft;
+            set
+            {
+                _dpadLeft = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _dpadRight;
+        public Key DpadRight
+        {
+            get => _dpadRight;
+            set
+            {
+                _dpadRight = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonL;
+        public Key ButtonL
+        {
+            get => _buttonL;
+            set
+            {
+                _buttonL = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonMinus;
+        public Key ButtonMinus
+        {
+            get => _buttonMinus;
+            set
+            {
+                _buttonMinus = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _leftButtonSl;
+        public Key LeftButtonSl
+        {
+            get => _leftButtonSl;
+            set
+            {
+                _leftButtonSl = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _leftButtonSr;
+        public Key LeftButtonSr
+        {
+            get => _leftButtonSr;
+            set
+            {
+                _leftButtonSr = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonZl;
+        public Key ButtonZl
+        {
+            get => _buttonZl;
+            set
+            {
+                _buttonZl = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonA;
+        public Key ButtonA
+        {
+            get => _buttonA;
+            set
+            {
+                _buttonA = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonB;
+        public Key ButtonB
+        {
+            get => _buttonB;
+            set
+            {
+                _buttonB = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonX;
+        public Key ButtonX
+        {
+            get => _buttonX;
+            set
+            {
+                _buttonX = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonY;
+        public Key ButtonY
+        {
+            get => _buttonY;
+            set
+            {
+                _buttonY = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonR;
+        public Key ButtonR
+        {
+            get => _buttonR;
+            set
+            {
+                _buttonR = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonPlus;
+        public Key ButtonPlus
+        {
+            get => _buttonPlus;
+            set
+            {
+                _buttonPlus = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _rightButtonSl;
+        public Key RightButtonSl
+        {
+            get => _rightButtonSl;
+            set
+            {
+                _rightButtonSl = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _rightButtonSr;
+        public Key RightButtonSr
+        {
+            get => _rightButtonSr;
+            set
+            {
+                _rightButtonSr = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private Key _buttonZr;
+        public Key ButtonZr
+        {
+            get => _buttonZr;
+            set
+            {
+                _buttonZr = value;
+                OnPropertyChanged();
+            }
+        }
+
+        public KeyboardInputConfig(InputConfig config)
+        {
+            if (config != null)
+            {
+                Id = config.Id;
+                ControllerType = config.ControllerType;
+                PlayerIndex = config.PlayerIndex;
+
+                if (config is not StandardKeyboardInputConfig keyboardConfig)
+                {
+                    return;
+                }
+
+                LeftStickUp = keyboardConfig.LeftJoyconStick.StickUp;
+                LeftStickDown = keyboardConfig.LeftJoyconStick.StickDown;
+                LeftStickLeft = keyboardConfig.LeftJoyconStick.StickLeft;
+                LeftStickRight = keyboardConfig.LeftJoyconStick.StickRight;
+                LeftStickButton = keyboardConfig.LeftJoyconStick.StickButton;
+
+                RightStickUp = keyboardConfig.RightJoyconStick.StickUp;
+                RightStickDown = keyboardConfig.RightJoyconStick.StickDown;
+                RightStickLeft = keyboardConfig.RightJoyconStick.StickLeft;
+                RightStickRight = keyboardConfig.RightJoyconStick.StickRight;
+                RightStickButton = keyboardConfig.RightJoyconStick.StickButton;
+
+                DpadUp = keyboardConfig.LeftJoycon.DpadUp;
+                DpadDown = keyboardConfig.LeftJoycon.DpadDown;
+                DpadLeft = keyboardConfig.LeftJoycon.DpadLeft;
+                DpadRight = keyboardConfig.LeftJoycon.DpadRight;
+                ButtonL = keyboardConfig.LeftJoycon.ButtonL;
+                ButtonMinus = keyboardConfig.LeftJoycon.ButtonMinus;
+                LeftButtonSl = keyboardConfig.LeftJoycon.ButtonSl;
+                LeftButtonSr = keyboardConfig.LeftJoycon.ButtonSr;
+                ButtonZl = keyboardConfig.LeftJoycon.ButtonZl;
+
+                ButtonA = keyboardConfig.RightJoycon.ButtonA;
+                ButtonB = keyboardConfig.RightJoycon.ButtonB;
+                ButtonX = keyboardConfig.RightJoycon.ButtonX;
+                ButtonY = keyboardConfig.RightJoycon.ButtonY;
+                ButtonR = keyboardConfig.RightJoycon.ButtonR;
+                ButtonPlus = keyboardConfig.RightJoycon.ButtonPlus;
+                RightButtonSl = keyboardConfig.RightJoycon.ButtonSl;
+                RightButtonSr = keyboardConfig.RightJoycon.ButtonSr;
+                ButtonZr = keyboardConfig.RightJoycon.ButtonZr;
+            }
+        }
+
+        public InputConfig GetConfig()
+        {
+            var config = new StandardKeyboardInputConfig
+            {
+                Id = Id,
+                Backend = InputBackendType.WindowKeyboard,
+                PlayerIndex = PlayerIndex,
+                ControllerType = ControllerType,
+                LeftJoycon = new LeftJoyconCommonConfig<Key>
+                {
+                    DpadUp = DpadUp,
+                    DpadDown = DpadDown,
+                    DpadLeft = DpadLeft,
+                    DpadRight = DpadRight,
+                    ButtonL = ButtonL,
+                    ButtonMinus = ButtonMinus,
+                    ButtonZl = ButtonZl,
+                    ButtonSl = LeftButtonSl,
+                    ButtonSr = LeftButtonSr,
+                },
+                RightJoycon = new RightJoyconCommonConfig<Key>
+                {
+                    ButtonA = ButtonA,
+                    ButtonB = ButtonB,
+                    ButtonX = ButtonX,
+                    ButtonY = ButtonY,
+                    ButtonPlus = ButtonPlus,
+                    ButtonSl = RightButtonSl,
+                    ButtonSr = RightButtonSr,
+                    ButtonR = ButtonR,
+                    ButtonZr = ButtonZr,
+                },
+                LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
+                {
+                    StickUp = LeftStickUp,
+                    StickDown = LeftStickDown,
+                    StickRight = LeftStickRight,
+                    StickLeft = LeftStickLeft,
+                    StickButton = LeftStickButton,
+                },
+                RightJoyconStick = new JoyconConfigKeyboardStick<Key>
+                {
+                    StickUp = RightStickUp,
+                    StickDown = RightStickDown,
+                    StickLeft = RightStickLeft,
+                    StickRight = RightStickRight,
+                    StickButton = RightStickButton,
+                },
+                Version = InputConfig.CurrentVersion,
+            };
+
+            return config;
+        }
+    }
+}
diff --git a/src/Ryujinx/UI/Models/InputConfiguration.cs b/src/Ryujinx/UI/Models/InputConfiguration.cs
deleted file mode 100644
index f1352c6d8..000000000
--- a/src/Ryujinx/UI/Models/InputConfiguration.cs
+++ /dev/null
@@ -1,456 +0,0 @@
-using Ryujinx.Ava.UI.ViewModels;
-using Ryujinx.Common.Configuration.Hid;
-using Ryujinx.Common.Configuration.Hid.Controller;
-using Ryujinx.Common.Configuration.Hid.Controller.Motion;
-using Ryujinx.Common.Configuration.Hid.Keyboard;
-using System;
-
-namespace Ryujinx.Ava.UI.Models
-{
-    internal class InputConfiguration<TKey, TStick> : BaseModel
-    {
-        private float _deadzoneRight;
-        private float _triggerThreshold;
-        private float _deadzoneLeft;
-        private double _gyroDeadzone;
-        private int _sensitivity;
-        private bool _enableMotion;
-        private float _weakRumble;
-        private float _strongRumble;
-        private float _rangeLeft;
-        private float _rangeRight;
-
-        public InputBackendType Backend { get; set; }
-
-        /// <summary>
-        /// Controller id
-        /// </summary>
-        public string Id { get; set; }
-
-        /// <summary>
-        ///  Controller's Type
-        /// </summary>
-        public ControllerType ControllerType { get; set; }
-
-        /// <summary>
-        ///  Player's Index for the controller
-        /// </summary>
-        public PlayerIndex PlayerIndex { get; set; }
-
-        public TStick LeftJoystick { get; set; }
-        public bool LeftInvertStickX { get; set; }
-        public bool LeftInvertStickY { get; set; }
-        public bool RightRotate90 { get; set; }
-        public TKey LeftControllerStickButton { get; set; }
-
-        public TStick RightJoystick { get; set; }
-        public bool RightInvertStickX { get; set; }
-        public bool RightInvertStickY { get; set; }
-        public bool LeftRotate90 { get; set; }
-        public TKey RightControllerStickButton { get; set; }
-
-        public float DeadzoneLeft
-        {
-            get => _deadzoneLeft;
-            set
-            {
-                _deadzoneLeft = MathF.Round(value, 3);
-
-                OnPropertyChanged();
-            }
-        }
-
-        public float RangeLeft
-        {
-            get => _rangeLeft;
-            set
-            {
-                _rangeLeft = MathF.Round(value, 3);
-
-                OnPropertyChanged();
-            }
-        }
-
-        public float DeadzoneRight
-        {
-            get => _deadzoneRight;
-            set
-            {
-                _deadzoneRight = MathF.Round(value, 3);
-
-                OnPropertyChanged();
-            }
-        }
-
-        public float RangeRight
-        {
-            get => _rangeRight;
-            set
-            {
-                _rangeRight = MathF.Round(value, 3);
-
-                OnPropertyChanged();
-            }
-        }
-
-        public float TriggerThreshold
-        {
-            get => _triggerThreshold;
-            set
-            {
-                _triggerThreshold = MathF.Round(value, 3);
-
-                OnPropertyChanged();
-            }
-        }
-
-        public MotionInputBackendType MotionBackend { get; set; }
-
-        public TKey ButtonMinus { get; set; }
-        public TKey ButtonL { get; set; }
-        public TKey ButtonZl { get; set; }
-        public TKey LeftButtonSl { get; set; }
-        public TKey LeftButtonSr { get; set; }
-        public TKey DpadUp { get; set; }
-        public TKey DpadDown { get; set; }
-        public TKey DpadLeft { get; set; }
-        public TKey DpadRight { get; set; }
-
-        public TKey ButtonPlus { get; set; }
-        public TKey ButtonR { get; set; }
-        public TKey ButtonZr { get; set; }
-        public TKey RightButtonSl { get; set; }
-        public TKey RightButtonSr { get; set; }
-        public TKey ButtonX { get; set; }
-        public TKey ButtonB { get; set; }
-        public TKey ButtonY { get; set; }
-        public TKey ButtonA { get; set; }
-
-        public TKey LeftStickUp { get; set; }
-        public TKey LeftStickDown { get; set; }
-        public TKey LeftStickLeft { get; set; }
-        public TKey LeftStickRight { get; set; }
-        public TKey LeftKeyboardStickButton { get; set; }
-
-        public TKey RightStickUp { get; set; }
-        public TKey RightStickDown { get; set; }
-        public TKey RightStickLeft { get; set; }
-        public TKey RightStickRight { get; set; }
-        public TKey RightKeyboardStickButton { get; set; }
-
-        public int Sensitivity
-        {
-            get => _sensitivity;
-            set
-            {
-                _sensitivity = value;
-
-                OnPropertyChanged();
-            }
-        }
-
-        public double GyroDeadzone
-        {
-            get => _gyroDeadzone;
-            set
-            {
-                _gyroDeadzone = Math.Round(value, 3);
-
-                OnPropertyChanged();
-            }
-        }
-
-        public bool EnableMotion
-        {
-            get => _enableMotion; set
-            {
-                _enableMotion = value;
-
-                OnPropertyChanged();
-            }
-        }
-
-        public bool EnableCemuHookMotion { get; set; }
-        public int Slot { get; set; }
-        public int AltSlot { get; set; }
-        public bool MirrorInput { get; set; }
-        public string DsuServerHost { get; set; }
-        public int DsuServerPort { get; set; }
-
-        public bool EnableRumble { get; set; }
-        public float WeakRumble
-        {
-            get => _weakRumble; set
-            {
-                _weakRumble = value;
-
-                OnPropertyChanged();
-            }
-        }
-        public float StrongRumble
-        {
-            get => _strongRumble; set
-            {
-                _strongRumble = value;
-
-                OnPropertyChanged();
-            }
-        }
-
-        public InputConfiguration(InputConfig config)
-        {
-            if (config != null)
-            {
-                Backend = config.Backend;
-                Id = config.Id;
-                ControllerType = config.ControllerType;
-                PlayerIndex = config.PlayerIndex;
-
-                if (config is StandardKeyboardInputConfig keyboardConfig)
-                {
-                    LeftStickUp = (TKey)(object)keyboardConfig.LeftJoyconStick.StickUp;
-                    LeftStickDown = (TKey)(object)keyboardConfig.LeftJoyconStick.StickDown;
-                    LeftStickLeft = (TKey)(object)keyboardConfig.LeftJoyconStick.StickLeft;
-                    LeftStickRight = (TKey)(object)keyboardConfig.LeftJoyconStick.StickRight;
-                    LeftKeyboardStickButton = (TKey)(object)keyboardConfig.LeftJoyconStick.StickButton;
-
-                    RightStickUp = (TKey)(object)keyboardConfig.RightJoyconStick.StickUp;
-                    RightStickDown = (TKey)(object)keyboardConfig.RightJoyconStick.StickDown;
-                    RightStickLeft = (TKey)(object)keyboardConfig.RightJoyconStick.StickLeft;
-                    RightStickRight = (TKey)(object)keyboardConfig.RightJoyconStick.StickRight;
-                    RightKeyboardStickButton = (TKey)(object)keyboardConfig.RightJoyconStick.StickButton;
-
-                    ButtonA = (TKey)(object)keyboardConfig.RightJoycon.ButtonA;
-                    ButtonB = (TKey)(object)keyboardConfig.RightJoycon.ButtonB;
-                    ButtonX = (TKey)(object)keyboardConfig.RightJoycon.ButtonX;
-                    ButtonY = (TKey)(object)keyboardConfig.RightJoycon.ButtonY;
-                    ButtonR = (TKey)(object)keyboardConfig.RightJoycon.ButtonR;
-                    RightButtonSl = (TKey)(object)keyboardConfig.RightJoycon.ButtonSl;
-                    RightButtonSr = (TKey)(object)keyboardConfig.RightJoycon.ButtonSr;
-                    ButtonZr = (TKey)(object)keyboardConfig.RightJoycon.ButtonZr;
-                    ButtonPlus = (TKey)(object)keyboardConfig.RightJoycon.ButtonPlus;
-
-                    DpadUp = (TKey)(object)keyboardConfig.LeftJoycon.DpadUp;
-                    DpadDown = (TKey)(object)keyboardConfig.LeftJoycon.DpadDown;
-                    DpadLeft = (TKey)(object)keyboardConfig.LeftJoycon.DpadLeft;
-                    DpadRight = (TKey)(object)keyboardConfig.LeftJoycon.DpadRight;
-                    ButtonMinus = (TKey)(object)keyboardConfig.LeftJoycon.ButtonMinus;
-                    LeftButtonSl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSl;
-                    LeftButtonSr = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSr;
-                    ButtonZl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonZl;
-                    ButtonL = (TKey)(object)keyboardConfig.LeftJoycon.ButtonL;
-                }
-                else if (config is StandardControllerInputConfig controllerConfig)
-                {
-                    LeftJoystick = (TStick)(object)controllerConfig.LeftJoyconStick.Joystick;
-                    LeftInvertStickX = controllerConfig.LeftJoyconStick.InvertStickX;
-                    LeftInvertStickY = controllerConfig.LeftJoyconStick.InvertStickY;
-                    LeftRotate90 = controllerConfig.LeftJoyconStick.Rotate90CW;
-                    LeftControllerStickButton = (TKey)(object)controllerConfig.LeftJoyconStick.StickButton;
-
-                    RightJoystick = (TStick)(object)controllerConfig.RightJoyconStick.Joystick;
-                    RightInvertStickX = controllerConfig.RightJoyconStick.InvertStickX;
-                    RightInvertStickY = controllerConfig.RightJoyconStick.InvertStickY;
-                    RightRotate90 = controllerConfig.RightJoyconStick.Rotate90CW;
-                    RightControllerStickButton = (TKey)(object)controllerConfig.RightJoyconStick.StickButton;
-
-                    ButtonA = (TKey)(object)controllerConfig.RightJoycon.ButtonA;
-                    ButtonB = (TKey)(object)controllerConfig.RightJoycon.ButtonB;
-                    ButtonX = (TKey)(object)controllerConfig.RightJoycon.ButtonX;
-                    ButtonY = (TKey)(object)controllerConfig.RightJoycon.ButtonY;
-                    ButtonR = (TKey)(object)controllerConfig.RightJoycon.ButtonR;
-                    RightButtonSl = (TKey)(object)controllerConfig.RightJoycon.ButtonSl;
-                    RightButtonSr = (TKey)(object)controllerConfig.RightJoycon.ButtonSr;
-                    ButtonZr = (TKey)(object)controllerConfig.RightJoycon.ButtonZr;
-                    ButtonPlus = (TKey)(object)controllerConfig.RightJoycon.ButtonPlus;
-
-                    DpadUp = (TKey)(object)controllerConfig.LeftJoycon.DpadUp;
-                    DpadDown = (TKey)(object)controllerConfig.LeftJoycon.DpadDown;
-                    DpadLeft = (TKey)(object)controllerConfig.LeftJoycon.DpadLeft;
-                    DpadRight = (TKey)(object)controllerConfig.LeftJoycon.DpadRight;
-                    ButtonMinus = (TKey)(object)controllerConfig.LeftJoycon.ButtonMinus;
-                    LeftButtonSl = (TKey)(object)controllerConfig.LeftJoycon.ButtonSl;
-                    LeftButtonSr = (TKey)(object)controllerConfig.LeftJoycon.ButtonSr;
-                    ButtonZl = (TKey)(object)controllerConfig.LeftJoycon.ButtonZl;
-                    ButtonL = (TKey)(object)controllerConfig.LeftJoycon.ButtonL;
-
-                    DeadzoneLeft = controllerConfig.DeadzoneLeft;
-                    DeadzoneRight = controllerConfig.DeadzoneRight;
-                    RangeLeft = controllerConfig.RangeLeft;
-                    RangeRight = controllerConfig.RangeRight;
-                    TriggerThreshold = controllerConfig.TriggerThreshold;
-
-                    if (controllerConfig.Motion != null)
-                    {
-                        EnableMotion = controllerConfig.Motion.EnableMotion;
-                        MotionBackend = controllerConfig.Motion.MotionBackend;
-                        GyroDeadzone = controllerConfig.Motion.GyroDeadzone;
-                        Sensitivity = controllerConfig.Motion.Sensitivity;
-
-                        if (controllerConfig.Motion is CemuHookMotionConfigController cemuHook)
-                        {
-                            EnableCemuHookMotion = true;
-                            DsuServerHost = cemuHook.DsuServerHost;
-                            DsuServerPort = cemuHook.DsuServerPort;
-                            Slot = cemuHook.Slot;
-                            AltSlot = cemuHook.AltSlot;
-                            MirrorInput = cemuHook.MirrorInput;
-                        }
-
-                        if (controllerConfig.Rumble != null)
-                        {
-                            EnableRumble = controllerConfig.Rumble.EnableRumble;
-                            WeakRumble = controllerConfig.Rumble.WeakRumble;
-                            StrongRumble = controllerConfig.Rumble.StrongRumble;
-                        }
-                    }
-                }
-            }
-        }
-
-        public InputConfiguration()
-        {
-        }
-
-        public InputConfig GetConfig()
-        {
-            if (Backend == InputBackendType.WindowKeyboard)
-            {
-                return new StandardKeyboardInputConfig
-                {
-                    Id = Id,
-                    Backend = Backend,
-                    PlayerIndex = PlayerIndex,
-                    ControllerType = ControllerType,
-                    LeftJoycon = new LeftJoyconCommonConfig<Key>
-                    {
-                        DpadUp = (Key)(object)DpadUp,
-                        DpadDown = (Key)(object)DpadDown,
-                        DpadLeft = (Key)(object)DpadLeft,
-                        DpadRight = (Key)(object)DpadRight,
-                        ButtonL = (Key)(object)ButtonL,
-                        ButtonZl = (Key)(object)ButtonZl,
-                        ButtonSl = (Key)(object)LeftButtonSl,
-                        ButtonSr = (Key)(object)LeftButtonSr,
-                        ButtonMinus = (Key)(object)ButtonMinus,
-                    },
-                    RightJoycon = new RightJoyconCommonConfig<Key>
-                    {
-                        ButtonA = (Key)(object)ButtonA,
-                        ButtonB = (Key)(object)ButtonB,
-                        ButtonX = (Key)(object)ButtonX,
-                        ButtonY = (Key)(object)ButtonY,
-                        ButtonPlus = (Key)(object)ButtonPlus,
-                        ButtonSl = (Key)(object)RightButtonSl,
-                        ButtonSr = (Key)(object)RightButtonSr,
-                        ButtonR = (Key)(object)ButtonR,
-                        ButtonZr = (Key)(object)ButtonZr,
-                    },
-                    LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
-                    {
-                        StickUp = (Key)(object)LeftStickUp,
-                        StickDown = (Key)(object)LeftStickDown,
-                        StickRight = (Key)(object)LeftStickRight,
-                        StickLeft = (Key)(object)LeftStickLeft,
-                        StickButton = (Key)(object)LeftKeyboardStickButton,
-                    },
-                    RightJoyconStick = new JoyconConfigKeyboardStick<Key>
-                    {
-                        StickUp = (Key)(object)RightStickUp,
-                        StickDown = (Key)(object)RightStickDown,
-                        StickLeft = (Key)(object)RightStickLeft,
-                        StickRight = (Key)(object)RightStickRight,
-                        StickButton = (Key)(object)RightKeyboardStickButton,
-                    },
-                    Version = InputConfig.CurrentVersion,
-                };
-
-            }
-
-            if (Backend == InputBackendType.GamepadSDL2)
-            {
-                var config = new StandardControllerInputConfig
-                {
-                    Id = Id,
-                    Backend = Backend,
-                    PlayerIndex = PlayerIndex,
-                    ControllerType = ControllerType,
-                    LeftJoycon = new LeftJoyconCommonConfig<GamepadInputId>
-                    {
-                        DpadUp = (GamepadInputId)(object)DpadUp,
-                        DpadDown = (GamepadInputId)(object)DpadDown,
-                        DpadLeft = (GamepadInputId)(object)DpadLeft,
-                        DpadRight = (GamepadInputId)(object)DpadRight,
-                        ButtonL = (GamepadInputId)(object)ButtonL,
-                        ButtonZl = (GamepadInputId)(object)ButtonZl,
-                        ButtonSl = (GamepadInputId)(object)LeftButtonSl,
-                        ButtonSr = (GamepadInputId)(object)LeftButtonSr,
-                        ButtonMinus = (GamepadInputId)(object)ButtonMinus,
-                    },
-                    RightJoycon = new RightJoyconCommonConfig<GamepadInputId>
-                    {
-                        ButtonA = (GamepadInputId)(object)ButtonA,
-                        ButtonB = (GamepadInputId)(object)ButtonB,
-                        ButtonX = (GamepadInputId)(object)ButtonX,
-                        ButtonY = (GamepadInputId)(object)ButtonY,
-                        ButtonPlus = (GamepadInputId)(object)ButtonPlus,
-                        ButtonSl = (GamepadInputId)(object)RightButtonSl,
-                        ButtonSr = (GamepadInputId)(object)RightButtonSr,
-                        ButtonR = (GamepadInputId)(object)ButtonR,
-                        ButtonZr = (GamepadInputId)(object)ButtonZr,
-                    },
-                    LeftJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>
-                    {
-                        Joystick = (StickInputId)(object)LeftJoystick,
-                        InvertStickX = LeftInvertStickX,
-                        InvertStickY = LeftInvertStickY,
-                        Rotate90CW = LeftRotate90,
-                        StickButton = (GamepadInputId)(object)LeftControllerStickButton,
-                    },
-                    RightJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>
-                    {
-                        Joystick = (StickInputId)(object)RightJoystick,
-                        InvertStickX = RightInvertStickX,
-                        InvertStickY = RightInvertStickY,
-                        Rotate90CW = RightRotate90,
-                        StickButton = (GamepadInputId)(object)RightControllerStickButton,
-                    },
-                    Rumble = new RumbleConfigController
-                    {
-                        EnableRumble = EnableRumble,
-                        WeakRumble = WeakRumble,
-                        StrongRumble = StrongRumble,
-                    },
-                    Version = InputConfig.CurrentVersion,
-                    DeadzoneLeft = DeadzoneLeft,
-                    DeadzoneRight = DeadzoneRight,
-                    RangeLeft = RangeLeft,
-                    RangeRight = RangeRight,
-                    TriggerThreshold = TriggerThreshold,
-                    Motion = EnableCemuHookMotion
-                        ? new CemuHookMotionConfigController
-                        {
-                            DsuServerHost = DsuServerHost,
-                            DsuServerPort = DsuServerPort,
-                            Slot = Slot,
-                            AltSlot = AltSlot,
-                            MirrorInput = MirrorInput,
-                            MotionBackend = MotionInputBackendType.CemuHook,
-                        }
-                        : new StandardMotionConfigController
-                        {
-                            MotionBackend = MotionInputBackendType.GamepadDriver,
-                        },
-                };
-
-                config.Motion.Sensitivity = Sensitivity;
-                config.Motion.EnableMotion = EnableMotion;
-                config.Motion.GyroDeadzone = GyroDeadzone;
-
-                return config;
-            }
-
-            return null;
-        }
-    }
-}
diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs
new file mode 100644
index 000000000..6ee79a371
--- /dev/null
+++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs
@@ -0,0 +1,84 @@
+using Avalonia.Svg.Skia;
+using Ryujinx.Ava.UI.Models.Input;
+using Ryujinx.Ava.UI.Views.Input;
+
+namespace Ryujinx.Ava.UI.ViewModels.Input
+{
+    public class ControllerInputViewModel : BaseModel
+    {
+        private GamepadInputConfig _config;
+        public GamepadInputConfig Config
+        {
+            get => _config;
+            set
+            {
+                _config = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _isLeft;
+        public bool IsLeft
+        {
+            get => _isLeft;
+            set
+            {
+                _isLeft = value;
+                OnPropertyChanged();
+                OnPropertyChanged(nameof(HasSides));
+            }
+        }
+
+        private bool _isRight;
+        public bool IsRight
+        {
+            get => _isRight;
+            set
+            {
+                _isRight = value;
+                OnPropertyChanged();
+                OnPropertyChanged(nameof(HasSides));
+            }
+        }
+
+        public bool HasSides => IsLeft ^ IsRight;
+
+        private SvgImage _image;
+        public SvgImage Image
+        {
+            get => _image;
+            set
+            {
+                _image = value;
+                OnPropertyChanged();
+            }
+        }
+
+        public readonly InputViewModel ParentModel;
+
+        public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config)
+        {
+            ParentModel = model;
+            model.NotifyChangesEvent += OnParentModelChanged;
+            OnParentModelChanged();
+            Config = config;
+        }
+
+        public async void ShowMotionConfig()
+        {
+            await MotionInputView.Show(this);
+        }
+
+        public async void ShowRumbleConfig()
+        {
+            await RumbleInputView.Show(this);
+        }
+
+        public void OnParentModelChanged()
+        {
+            IsLeft = ParentModel.IsLeft;
+            IsRight = ParentModel.IsRight;
+            Image = ParentModel.Image;
+        }
+    }
+}
diff --git a/src/Ryujinx/UI/ViewModels/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
similarity index 92%
rename from src/Ryujinx/UI/ViewModels/ControllerInputViewModel.cs
rename to src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
index 71ad2c127..74da45979 100644
--- a/src/Ryujinx/UI/ViewModels/ControllerInputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
@@ -8,7 +8,7 @@ using Ryujinx.Ava.Common.Locale;
 using Ryujinx.Ava.Input;
 using Ryujinx.Ava.UI.Helpers;
 using Ryujinx.Ava.UI.Models;
-using Ryujinx.Ava.UI.Views.Input;
+using Ryujinx.Ava.UI.Models.Input;
 using Ryujinx.Ava.UI.Windows;
 using Ryujinx.Common;
 using Ryujinx.Common.Configuration;
@@ -30,9 +30,9 @@ using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.Gamepad
 using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
 using Key = Ryujinx.Common.Configuration.Hid.Key;
 
-namespace Ryujinx.Ava.UI.ViewModels
+namespace Ryujinx.Ava.UI.ViewModels.Input
 {
-    public class ControllerInputViewModel : BaseModel, IDisposable
+    public class InputViewModel : BaseModel, IDisposable
     {
         private const string Disabled = "disabled";
         private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg";
@@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.ViewModels
         private int _controllerNumber;
         private string _controllerImage;
         private int _device;
-        private object _configuration;
+        private object _configViewModel;
         private string _profileName;
         private bool _isLoaded;
 
@@ -71,13 +71,14 @@ namespace Ryujinx.Ava.UI.ViewModels
         public bool IsLeft { get; set; }
 
         public bool IsModified { get; set; }
+        public event Action NotifyChangesEvent;
 
-        public object Configuration
+        public object ConfigViewModel
         {
-            get => _configuration;
+            get => _configViewModel;
             set
             {
-                _configuration = value;
+                _configViewModel = value;
 
                 OnPropertyChanged();
             }
@@ -232,7 +233,7 @@ namespace Ryujinx.Ava.UI.ViewModels
 
         public InputConfig Config { get; set; }
 
-        public ControllerInputViewModel(UserControl owner) : this()
+        public InputViewModel(UserControl owner) : this()
         {
             if (Program.PreviewerDetached)
             {
@@ -255,7 +256,7 @@ namespace Ryujinx.Ava.UI.ViewModels
             }
         }
 
-        public ControllerInputViewModel()
+        public InputViewModel()
         {
             PlayerIndexes = new ObservableCollection<PlayerModel>();
             Controllers = new ObservableCollection<ControllerModel>();
@@ -282,12 +283,12 @@ namespace Ryujinx.Ava.UI.ViewModels
 
             if (Config is StandardKeyboardInputConfig keyboardInputConfig)
             {
-                Configuration = new InputConfiguration<Key, ConfigStickInputId>(keyboardInputConfig);
+                ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig));
             }
 
             if (Config is StandardControllerInputConfig controllerInputConfig)
             {
-                Configuration = new InputConfiguration<ConfigGamepadInputId, ConfigStickInputId>(controllerInputConfig);
+                ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig));
             }
         }
 
@@ -323,16 +324,6 @@ namespace Ryujinx.Ava.UI.ViewModels
             }
         }
 
-        public async void ShowMotionConfig()
-        {
-            await MotionInputView.Show(this);
-        }
-
-        public async void ShowRumbleConfig()
-        {
-            await RumbleInputView.Show(this);
-        }
-
         private void LoadInputDriver()
         {
             if (_device < 0)
@@ -740,7 +731,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                 return;
             }
 
-            if (Configuration == null)
+            if (ConfigViewModel == null)
             {
                 return;
             }
@@ -751,35 +742,37 @@ namespace Ryujinx.Ava.UI.ViewModels
 
                 return;
             }
-
-            bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
-
-            if (validFileName)
-            {
-                string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
-
-                InputConfig config = null;
-
-                if (IsKeyboard)
-                {
-                    config = (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig();
-                }
-                else if (IsController)
-                {
-                    config = (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig();
-                }
-
-                config.ControllerType = Controllers[_controller].Type;
-
-                string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
-
-                await File.WriteAllTextAsync(path, jsonString);
-
-                LoadProfiles();
-            }
             else
             {
-                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
+                bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
+
+                if (validFileName)
+                {
+                    string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
+
+                    InputConfig config = null;
+
+                    if (IsKeyboard)
+                    {
+                        config = (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig();
+                    }
+                    else if (IsController)
+                    {
+                        config = (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
+                    }
+
+                    config.ControllerType = Controllers[_controller].Type;
+
+                    string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
+
+                    await File.WriteAllTextAsync(path, jsonString);
+
+                    LoadProfiles();
+                }
+                else
+                {
+                    await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
+                }
             }
         }
 
@@ -830,18 +823,18 @@ namespace Ryujinx.Ava.UI.ViewModels
 
                 if (device.Type == DeviceType.Keyboard)
                 {
-                    var inputConfig = Configuration as InputConfiguration<Key, ConfigStickInputId>;
+                    var inputConfig = (ConfigViewModel as KeyboardInputViewModel).Config;
                     inputConfig.Id = device.Id;
                 }
                 else
                 {
-                    var inputConfig = Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>;
+                    var inputConfig = (ConfigViewModel as ControllerInputViewModel).Config;
                     inputConfig.Id = device.Id.Split(" ")[0];
                 }
 
                 var config = !IsController
-                    ? (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig()
-                    : (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig();
+                    ? (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig()
+                    : (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
                 config.ControllerType = Controllers[_controller].Type;
                 config.PlayerIndex = _playerId;
 
@@ -872,12 +865,13 @@ namespace Ryujinx.Ava.UI.ViewModels
 
         public void NotifyChanges()
         {
-            OnPropertyChanged(nameof(Configuration));
+            OnPropertyChanged(nameof(ConfigViewModel));
             OnPropertyChanged(nameof(IsController));
             OnPropertyChanged(nameof(ShowSettings));
             OnPropertyChanged(nameof(IsKeyboard));
             OnPropertyChanged(nameof(IsRight));
             OnPropertyChanged(nameof(IsLeft));
+            NotifyChangesEvent?.Invoke();
         }
 
         public void Dispose()
diff --git a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs
new file mode 100644
index 000000000..0b530eb09
--- /dev/null
+++ b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs
@@ -0,0 +1,73 @@
+using Avalonia.Svg.Skia;
+using Ryujinx.Ava.UI.Models.Input;
+
+namespace Ryujinx.Ava.UI.ViewModels.Input
+{
+    public class KeyboardInputViewModel : BaseModel
+    {
+        private KeyboardInputConfig _config;
+        public KeyboardInputConfig Config
+        {
+            get => _config;
+            set
+            {
+                _config = value;
+                OnPropertyChanged();
+            }
+        }
+
+        private bool _isLeft;
+        public bool IsLeft
+        {
+            get => _isLeft;
+            set
+            {
+                _isLeft = value;
+                OnPropertyChanged();
+                OnPropertyChanged(nameof(HasSides));
+            }
+        }
+
+        private bool _isRight;
+        public bool IsRight
+        {
+            get => _isRight;
+            set
+            {
+                _isRight = value;
+                OnPropertyChanged();
+                OnPropertyChanged(nameof(HasSides));
+            }
+        }
+
+        public bool HasSides => IsLeft ^ IsRight;
+
+        private SvgImage _image;
+        public SvgImage Image
+        {
+            get => _image;
+            set
+            {
+                _image = value;
+                OnPropertyChanged();
+            }
+        }
+
+        public readonly InputViewModel ParentModel;
+
+        public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config)
+        {
+            ParentModel = model;
+            model.NotifyChangesEvent += OnParentModelChanged;
+            OnParentModelChanged();
+            Config = config;
+        }
+
+        public void OnParentModelChanged()
+        {
+            IsLeft = ParentModel.IsLeft;
+            IsRight = ParentModel.IsRight;
+            Image = ParentModel.Image;
+        }
+    }
+}
diff --git a/src/Ryujinx/UI/ViewModels/MotionInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs
similarity index 97%
rename from src/Ryujinx/UI/ViewModels/MotionInputViewModel.cs
rename to src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs
index 0b12a51f6..c9ed8f2d4 100644
--- a/src/Ryujinx/UI/ViewModels/MotionInputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Ava.UI.ViewModels
+namespace Ryujinx.Ava.UI.ViewModels.Input
 {
     public class MotionInputViewModel : BaseModel
     {
diff --git a/src/Ryujinx/UI/ViewModels/RumbleInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs
similarity index 92%
rename from src/Ryujinx/UI/ViewModels/RumbleInputViewModel.cs
rename to src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs
index 49de19937..8ad33cf4c 100644
--- a/src/Ryujinx/UI/ViewModels/RumbleInputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Ava.UI.ViewModels
+namespace Ryujinx.Ava.UI.ViewModels.Input
 {
     public class RumbleInputViewModel : BaseModel
     {
diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
index fde8f74ae..6074a5fdb 100644
--- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
@@ -7,9 +7,9 @@ using Ryujinx.Audio.Backends.SDL2;
 using Ryujinx.Audio.Backends.SoundIo;
 using Ryujinx.Ava.Common.Locale;
 using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.Models.Input;
 using Ryujinx.Ava.UI.Windows;
 using Ryujinx.Common.Configuration;
-using Ryujinx.Common.Configuration.Hid;
 using Ryujinx.Common.Configuration.Multiplayer;
 using Ryujinx.Common.GraphicsDriver;
 using Ryujinx.Common.Logging;
@@ -46,7 +46,6 @@ namespace Ryujinx.Ava.UI.ViewModels
         private bool _isVulkanAvailable = true;
         private bool _directoryChanged;
         private readonly List<string> _gpuIds = new();
-        private KeyboardHotkeys _keyboardHotkeys;
         private int _graphicsBackendIndex;
         private int _scalingFilter;
         private int _scalingFilterLevel;
@@ -237,16 +236,7 @@ namespace Ryujinx.Ava.UI.ViewModels
             get => new(_networkInterfaces.Keys);
         }
 
-        public KeyboardHotkeys KeyboardHotkeys
-        {
-            get => _keyboardHotkeys;
-            set
-            {
-                _keyboardHotkeys = value;
-
-                OnPropertyChanged();
-            }
-        }
+        public HotkeyConfig KeyboardHotkey { get; set; }
 
         public int NetworkInterfaceIndex
         {
@@ -413,7 +403,7 @@ namespace Ryujinx.Ava.UI.ViewModels
             EnableMouse = config.Hid.EnableMouse;
 
             // Keyboard Hotkeys
-            KeyboardHotkeys = config.Hid.Hotkeys.Value;
+            KeyboardHotkey = new HotkeyConfig(config.Hid.Hotkeys.Value);
 
             // System
             Region = (int)config.System.Region.Value;
@@ -500,7 +490,7 @@ namespace Ryujinx.Ava.UI.ViewModels
             config.Hid.EnableMouse.Value = EnableMouse;
 
             // Keyboard Hotkeys
-            config.Hid.Hotkeys.Value = KeyboardHotkeys;
+            config.Hid.Hotkeys.Value = KeyboardHotkey.GetConfig();
 
             // System
             config.System.Region.Value = (Region)Region;
diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml
index 99f2b6b69..08bdf90f4 100644
--- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml
+++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml
@@ -1,13 +1,11 @@
 <UserControl
     xmlns="https://github.com/avaloniaui"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
     xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
-    xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
-    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input"
     xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
     HorizontalAlignment="Stretch"
     VerticalAlignment="Stretch"
@@ -15,6 +13,7 @@
     d:DesignWidth="800"
     x:Class="Ryujinx.Ava.UI.Views.Input.ControllerInputView"
     x:DataType="viewModels:ControllerInputViewModel"
+    x:CompileBindings="True"
     mc:Ignorable="d"
     Focusable="True">
     <Design.DataContext>
@@ -34,192 +33,10 @@
         HorizontalAlignment="Stretch"
         VerticalAlignment="Stretch"
         Orientation="Vertical">
-        <StackPanel
-            Margin="0 0 0 5"
-            Orientation="Vertical"
-            Spacing="5">
-            <Grid>
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition Width="*" />
-                    <ColumnDefinition Width="10" />
-                    <ColumnDefinition Width="*" />
-                </Grid.ColumnDefinitions>
-                <!-- Player Selection -->
-                <Grid
-                    Grid.Column="0"
-                    Margin="2"
-                    HorizontalAlignment="Stretch"
-                    VerticalAlignment="Center">
-                    <Grid.ColumnDefinitions>
-                        <ColumnDefinition Width="Auto"/>
-                        <ColumnDefinition Width="*" />
-                    </Grid.ColumnDefinitions>
-                    <TextBlock
-                        Margin="5,0,10,0"
-                        Width="90"
-                        HorizontalAlignment="Left"
-                        VerticalAlignment="Center"
-                        Text="{locale:Locale ControllerSettingsPlayer}" />
-                    <ComboBox
-                        Grid.Column="1"
-                        Name="PlayerIndexBox"
-                        HorizontalAlignment="Stretch"
-                        VerticalAlignment="Center"
-                        SelectionChanged="PlayerIndexBox_OnSelectionChanged"
-                        ItemsSource="{Binding PlayerIndexes}"
-                        SelectedIndex="{Binding PlayerId}">
-                        <ComboBox.ItemTemplate>
-                            <DataTemplate>
-                                <TextBlock Text="{Binding Name}" />
-                            </DataTemplate>
-                        </ComboBox.ItemTemplate>
-                    </ComboBox>
-                </Grid>
-                <!-- Profile Selection -->
-                <Grid
-                    Grid.Column="2"
-                    Margin="2"
-                    HorizontalAlignment="Stretch"
-                    VerticalAlignment="Center">
-                    <Grid.ColumnDefinitions>
-                        <ColumnDefinition Width="Auto"/>
-                        <ColumnDefinition Width="*" />
-                        <ColumnDefinition Width="Auto"/>
-                        <ColumnDefinition Width="Auto"/>
-                        <ColumnDefinition Width="Auto"/>
-                    </Grid.ColumnDefinitions>
-                    <TextBlock
-                        Margin="5,0,10,0"
-                        Width="90"
-                        HorizontalAlignment="Left"
-                        VerticalAlignment="Center"
-                        Text="{locale:Locale ControllerSettingsProfile}" />
-                    <ui:FAComboBox
-                        Grid.Column="1"
-                        IsEditable="True"
-                        Name="ProfileBox"
-                        HorizontalAlignment="Stretch"
-                        VerticalAlignment="Center"
-                        SelectedIndex="0"
-                        ItemsSource="{Binding ProfilesList}"
-                        Text="{Binding ProfileName, Mode=TwoWay}" />
-                    <Button
-                        Grid.Column="2"
-                        MinWidth="0"
-                        Margin="5,0,0,0"
-                        VerticalAlignment="Center"
-                        ToolTip.Tip="{locale:Locale ControllerSettingsLoadProfileToolTip}"
-                        Command="{ReflectionBinding LoadProfile}">
-                        <ui:SymbolIcon
-                            Symbol="Upload"
-                            FontSize="15"
-                            Height="20" />
-                    </Button>
-                    <Button
-                        Grid.Column="3"
-                            MinWidth="0"
-                            Margin="5,0,0,0"
-                            VerticalAlignment="Center"
-                            ToolTip.Tip="{locale:Locale ControllerSettingsSaveProfileToolTip}"
-                            Command="{ReflectionBinding SaveProfile}">
-                        <ui:SymbolIcon
-                            Symbol="Save"
-                            FontSize="15"
-                            Height="20" />
-                    </Button>
-                    <Button
-                        Grid.Column="4"
-                            MinWidth="0"
-                            Margin="5,0,0,0"
-                            VerticalAlignment="Center"
-                            ToolTip.Tip="{locale:Locale ControllerSettingsRemoveProfileToolTip}"
-                            Command="{ReflectionBinding RemoveProfile}">
-                        <ui:SymbolIcon
-                            Symbol="Delete"
-                            FontSize="15"
-                            Height="20" />
-                    </Button>
-                </Grid>
-            </Grid>
-            <Separator />
-            <Grid>
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition Width="*" />
-                    <ColumnDefinition Width="10" />
-                    <ColumnDefinition Width="*" />
-                </Grid.ColumnDefinitions>
-                <!-- Input Device -->
-                <Grid
-                    Grid.Column="0"
-                    Margin="2"
-                    HorizontalAlignment="Stretch">
-                    <Grid.ColumnDefinitions>
-                        <ColumnDefinition Width="Auto"/>
-                        <ColumnDefinition Width="*"/>
-                        <ColumnDefinition Width="Auto" />
-                    </Grid.ColumnDefinitions>
-                    <TextBlock
-                        Grid.Column="0"
-                        Margin="5,0,10,0"
-                        Width="90"
-                        HorizontalAlignment="Left"
-                        VerticalAlignment="Center"
-                        Text="{locale:Locale ControllerSettingsInputDevice}" />
-                    <ComboBox
-                        Grid.Column="1"
-                        Name="DeviceBox"
-                        HorizontalAlignment="Stretch"
-                        VerticalAlignment="Center"
-                        ItemsSource="{Binding DeviceList}"
-                        SelectedIndex="{Binding Device}" />
-                    <Button
-                        Grid.Column="2"
-                        MinWidth="0"
-                        Margin="5,0,0,0"
-                        VerticalAlignment="Center"
-                        Command="{ReflectionBinding LoadDevices}">
-                        <ui:SymbolIcon
-                            Symbol="Refresh"
-                            FontSize="15"
-                            Height="20"/>
-                    </Button>
-                </Grid>
-                <!-- Controller Type -->
-                <Grid
-                    Grid.Column="2"
-                    Margin="2"
-                    HorizontalAlignment="Stretch"
-                    VerticalAlignment="Center">
-                    <Grid.ColumnDefinitions>
-                        <ColumnDefinition Width="Auto"/>
-                        <ColumnDefinition Width="*" />
-                    </Grid.ColumnDefinitions>
-                    <TextBlock
-                        Margin="5,0,10,0"
-                        Width="90"
-                        HorizontalAlignment="Left"
-                        VerticalAlignment="Center"
-                        Text="{locale:Locale ControllerSettingsControllerType}" />
-                    <ComboBox
-                        Grid.Column="1"
-                        HorizontalAlignment="Stretch"
-                        ItemsSource="{Binding Controllers}"
-                        SelectedIndex="{Binding Controller}">
-                        <ComboBox.ItemTemplate>
-                            <DataTemplate DataType="models:ControllerModel">
-                                <TextBlock Text="{Binding Name}" />
-                            </DataTemplate>
-                        </ComboBox.ItemTemplate>
-                    </ComboBox>
-                </Grid>
-            </Grid>
-        </StackPanel>
         <!-- Button / JoyStick Settings -->
         <Grid
             Name="SettingButtons"
-            MinHeight="450"
-            FlowDirection="LeftToRight"
-            IsVisible="{Binding ShowSettings}">
+            MinHeight="450">
             <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="Auto" />
                 <ColumnDefinition Width="*" />
@@ -258,9 +75,9 @@
                                 VerticalAlignment="Center"
                                 Text="{locale:Locale ControllerSettingsTriggerZL}"
                                 TextAlignment="Center" />
-                            <ToggleButton>
+                            <ToggleButton Name="ButtonZl">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.ButtonZl, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Text="{Binding Config.ButtonZl, Converter={StaticResource Key}}"
                                     TextAlignment="Center" />
                             </ToggleButton>
                         </StackPanel>
@@ -274,9 +91,9 @@
                                 VerticalAlignment="Center"
                                 Text="{locale:Locale ControllerSettingsTriggerL}"
                                 TextAlignment="Center" />
-                            <ToggleButton>
+                            <ToggleButton Name="ButtonL">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.ButtonL, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Text="{Binding Config.ButtonL, Converter={StaticResource Key}}"
                                     TextAlignment="Center" />
                             </ToggleButton>
                         </StackPanel>
@@ -290,9 +107,9 @@
                                 VerticalAlignment="Center"
                                 Text="{locale:Locale ControllerSettingsButtonMinus}"
                                 TextAlignment="Center" />
-                            <ToggleButton>
+                            <ToggleButton Name="ButtonMinus">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.ButtonMinus, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Text="{Binding Config.ButtonMinus, Converter={StaticResource Key}}"
                                     TextAlignment="Center" />
                             </ToggleButton>
                         </StackPanel>
@@ -312,100 +129,8 @@
                             Margin="0,0,0,10"
                             HorizontalAlignment="Center"
                             Text="{locale:Locale ControllerSettingsLStick}" />
-                        <!-- Left Joystick Keyboard -->
-                        <StackPanel
-                            IsVisible="{Binding !IsController}"
-                            Orientation="Vertical">
-                            <!-- Left Joystick Button -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickButton}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.LeftKeyboardStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                            <!-- Left Joystick Up -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickUp}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.LeftStickUp, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                            <!-- Left Joystick Down -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickDown}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.LeftStickDown, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                            <!-- Left Joystick Left -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickLeft}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.LeftStickLeft, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                            <!-- Left Joystick Right -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickRight}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.LeftStickRight, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                        </StackPanel>
                         <!-- Left Joystick Controller -->
-                        <StackPanel
-                            IsVisible="{Binding IsController}"
-                            Orientation="Vertical">
+                        <StackPanel Orientation="Vertical">
                             <!-- Left Joystick Button -->
                             <StackPanel
                                 Orientation="Horizontal">
@@ -416,9 +141,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsStickButton}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="LeftStickButton">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.LeftControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.LeftStickButton, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -433,22 +158,22 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsStickStick}"
                                     TextAlignment="Center" />
-                                <ToggleButton Tag="stick">
+                                <ToggleButton Name="LeftJoystick" Tag="stick">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.LeftJoystick, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.LeftJoystick, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
                             <Separator
                                 Margin="0,8,0,8"
                                 Height="1" />
-                            <CheckBox IsChecked="{ReflectionBinding Configuration.LeftInvertStickX}">
+                            <CheckBox IsChecked="{Binding Config.LeftInvertStickX}">
                                 <TextBlock Text="{locale:Locale ControllerSettingsStickInvertXAxis}" />
                             </CheckBox>
-                            <CheckBox IsChecked="{ReflectionBinding Configuration.LeftInvertStickY}">
+                            <CheckBox IsChecked="{Binding Config.LeftInvertStickY}">
                                 <TextBlock Text="{locale:Locale ControllerSettingsStickInvertYAxis}" />
                             </CheckBox>
-                            <CheckBox IsChecked="{ReflectionBinding Configuration.LeftRotate90}">
+                            <CheckBox IsChecked="{Binding Config.LeftRotate90}">
                                 <TextBlock Text="{locale:Locale ControllerSettingsRotate90}" />
                             </CheckBox>
                             <Separator
@@ -469,11 +194,11 @@
                                         IsSnapToTickEnabled="True"
                                         SmallChange="0.01"
                                         Minimum="0"
-                                        Value="{ReflectionBinding Configuration.DeadzoneLeft, Mode=TwoWay}" />
+                                        Value="{Binding Config.DeadzoneLeft, Mode=TwoWay}" />
                                     <TextBlock
                                         VerticalAlignment="Center"
                                         Width="25"
-                                        Text="{ReflectionBinding Configuration.DeadzoneLeft, StringFormat=\{0:0.00\}}" />
+                                        Text="{Binding Config.DeadzoneLeft, StringFormat=\{0:0.00\}}" />
                                 </StackPanel>
                                 <TextBlock
                                     HorizontalAlignment="Center"
@@ -489,11 +214,11 @@
                                         IsSnapToTickEnabled="True"
                                         SmallChange="0.01"
                                         Minimum="0"
-                                        Value="{ReflectionBinding Configuration.RangeLeft, Mode=TwoWay}" />
+                                        Value="{Binding Config.RangeLeft, Mode=TwoWay}" />
                                     <TextBlock
                                         VerticalAlignment="Center"
                                         Width="25"
-                                        Text="{ReflectionBinding Configuration.RangeLeft, StringFormat=\{0:0.00\}}" />
+                                        Text="{Binding Config.RangeLeft, StringFormat=\{0:0.00\}}" />
                                 </StackPanel>
                             </StackPanel>
                         </StackPanel>
@@ -526,9 +251,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsDPadUp}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="DpadUp">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.DpadUp, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.DpadUp, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -543,9 +268,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsDPadDown}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="DpadDown">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.DpadDown, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.DpadDown, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -560,9 +285,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsDPadLeft}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="DpadLeft">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.DpadLeft, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.DpadLeft, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -577,9 +302,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsDPadRight}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="DpadRight">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.DpadRight, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.DpadRight, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -592,6 +317,13 @@
                 Grid.Column="1"
                 HorizontalAlignment="Stretch"
                 VerticalAlignment="Stretch">
+                <!-- Controller Picture -->
+                <Image
+                    Margin="0,10"
+                    MaxHeight="300"
+                    HorizontalAlignment="Stretch"
+                    VerticalAlignment="Stretch"
+                    Source="{Binding Image}" />
                 <Border
                     BorderBrush="{DynamicResource ThemeControlBorderColor}"
                     BorderThickness="1"
@@ -613,92 +345,89 @@
                                 IsSnapToTickEnabled="True"
                                 SmallChange="0.01"
                                 Minimum="0"
-                                Value="{ReflectionBinding Configuration.TriggerThreshold, Mode=TwoWay}" />
+                                Value="{Binding Config.TriggerThreshold, Mode=TwoWay}" />
                             <TextBlock
                               Width="25"
-                              Text="{ReflectionBinding Configuration.TriggerThreshold, StringFormat=\{0:0.00\}}" />
+                              Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" />
                         </StackPanel>
                         <StackPanel
-                            Margin="0,4,0,0"
-                            HorizontalAlignment="Center"
-                            VerticalAlignment="Center"
-                            IsVisible="{Binding !IsRight}"
-                            Orientation="Horizontal">
-                            <TextBlock
-                                Width="20"
+                            Orientation="Vertical"
+                            IsVisible="{Binding HasSides}">
+                            <StackPanel
+                                Margin="0,4,0,0"
                                 HorizontalAlignment="Center"
                                 VerticalAlignment="Center"
-                                Text="{locale:Locale ControllerSettingsLeftSR}"
-                                TextAlignment="Center" />
-                            <ToggleButton>
+                                IsVisible="{Binding IsLeft}"
+                                Orientation="Horizontal">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.LeftButtonSr, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Width="20"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsLeftSR}"
                                     TextAlignment="Center" />
-                            </ToggleButton>
-                        </StackPanel>
-                        <StackPanel
-                            Margin="0,4,0,0"
-                            HorizontalAlignment="Center"
-                            VerticalAlignment="Center"
-                            IsVisible="{Binding !IsRight}"
-                            Orientation="Horizontal">
-                            <TextBlock
-                                Width="20"
+                                <ToggleButton Name="LeftButtonSr">
+                                    <TextBlock
+                                        Text="{Binding Config.LeftButtonSr, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <StackPanel
+                                Margin="0,4,0,0"
                                 HorizontalAlignment="Center"
                                 VerticalAlignment="Center"
-                                Text="{locale:Locale ControllerSettingsLeftSL}"
-                                TextAlignment="Center" />
-                            <ToggleButton>
+                                IsVisible="{Binding IsLeft}"
+                                Orientation="Horizontal">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.LeftButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Width="20"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsLeftSL}"
                                     TextAlignment="Center" />
-                            </ToggleButton>
-                        </StackPanel>
-                        <StackPanel
-                            Margin="0,4,0,0"
-                            HorizontalAlignment="Center"
-                            VerticalAlignment="Center"
-                            IsVisible="{Binding !IsLeft}"
-                            Orientation="Horizontal">
-                            <TextBlock
-                                Width="20"
+                                <ToggleButton Name="LeftButtonSl">
+                                    <TextBlock
+                                        Text="{Binding Config.LeftButtonSl, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <StackPanel
+                                Margin="0,4,0,0"
                                 HorizontalAlignment="Center"
                                 VerticalAlignment="Center"
-                                Text="{locale:Locale ControllerSettingsRightSR}"
-                                TextAlignment="Center" />
-                            <ToggleButton>
+                                IsVisible="{Binding IsRight}"
+                                Orientation="Horizontal">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.RightButtonSr, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Width="20"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsRightSR}"
                                     TextAlignment="Center" />
-                            </ToggleButton>
-                        </StackPanel>
-                        <StackPanel
-                            Margin="0,4,0,0"
-                            HorizontalAlignment="Center"
-                            VerticalAlignment="Center"
-                            IsVisible="{Binding !IsLeft}"
-                            Orientation="Horizontal">
-                            <TextBlock
-                                Width="20"
+                                <ToggleButton Name="RightButtonSr">
+                                    <TextBlock
+                                        Text="{Binding Config.RightButtonSr, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <StackPanel
+                                Margin="0,4,0,0"
                                 HorizontalAlignment="Center"
                                 VerticalAlignment="Center"
-                                Text="{locale:Locale ControllerSettingsRightSL}"
-                                TextAlignment="Center" />
-                            <ToggleButton>
+                                IsVisible="{Binding IsRight}"
+                                Orientation="Horizontal">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.RightButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Width="20"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsRightSL}"
                                     TextAlignment="Center" />
-                            </ToggleButton>
+                                <ToggleButton Name="RightButtonSl">
+                                    <TextBlock
+                                        Text="{Binding Config.RightButtonSl, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
                         </StackPanel>
                     </StackPanel>
                 </Border>
-                <!-- Controller Picture -->
-                <Image
-                    Margin="0,10,0,0"
-                    MaxHeight="300"
-                    HorizontalAlignment="Stretch"
-                    VerticalAlignment="Stretch"
-                    Source="{Binding Image}" />
                 <!-- Motion + Rumble -->
                 <StackPanel
                     Margin="0,10,0,0"
@@ -710,8 +439,7 @@
                         BorderThickness="1"
                         CornerRadius="5"
                         VerticalAlignment="Bottom"
-                        HorizontalAlignment="Stretch"
-                        IsVisible="{Binding IsController}">
+                        HorizontalAlignment="Stretch">
                         <Grid>
                             <Grid.ColumnDefinitions>
                                 <ColumnDefinition Width="*" />
@@ -721,7 +449,7 @@
                                 Margin="10"
                                 MinWidth="0"
                                 Grid.Column="0"
-                                IsChecked="{ReflectionBinding Configuration.EnableMotion, Mode=TwoWay}">
+                                IsChecked="{Binding Config.EnableMotion, Mode=TwoWay}">
                                 <TextBlock Text="{locale:Locale ControllerSettingsMotion}" />
                             </CheckBox>
                             <Button
@@ -737,7 +465,6 @@
                         BorderThickness="1"
                         CornerRadius="5"
                         HorizontalAlignment="Stretch"
-                        IsVisible="{Binding IsController}"
                         Margin="0,-1,0,0">
                         <Grid>
                             <Grid.ColumnDefinitions>
@@ -748,7 +475,7 @@
                                 Margin="10"
                                 MinWidth="0"
                                 Grid.Column="0"
-                                IsChecked="{ReflectionBinding Configuration.EnableRumble, Mode=TwoWay}">
+                                IsChecked="{Binding Config.EnableRumble, Mode=TwoWay}">
                                 <TextBlock Text="{locale:Locale ControllerSettingsRumble}" />
                             </CheckBox>
                             <Button
@@ -794,9 +521,9 @@
                                 VerticalAlignment="Center"
                                 Text="{locale:Locale ControllerSettingsTriggerZR}"
                                 TextAlignment="Center" />
-                            <ToggleButton>
+                            <ToggleButton Name="ButtonZr">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.ButtonZr, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Text="{Binding Config.ButtonZr, Converter={StaticResource Key}}"
                                     TextAlignment="Center" />
                             </ToggleButton>
                         </StackPanel>
@@ -812,9 +539,9 @@
                                 VerticalAlignment="Center"
                                 Text="{locale:Locale ControllerSettingsTriggerR}"
                                 TextAlignment="Center" />
-                            <ToggleButton>
+                            <ToggleButton Name="ButtonR">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.ButtonR, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Text="{Binding Config.ButtonR, Converter={StaticResource Key}}"
                                     TextAlignment="Center" />
                             </ToggleButton>
                         </StackPanel>
@@ -830,15 +557,15 @@
                                 VerticalAlignment="Center"
                                 Text="{locale:Locale ControllerSettingsButtonPlus}"
                                 TextAlignment="Center" />
-                            <ToggleButton>
+                            <ToggleButton Name="ButtonPlus">
                                 <TextBlock
-                                    Text="{ReflectionBinding Configuration.ButtonPlus, Mode=TwoWay, Converter={StaticResource Key}}"
+                                    Text="{Binding Config.ButtonPlus, Converter={StaticResource Key}}"
                                     TextAlignment="Center" />
                             </ToggleButton>
                         </StackPanel>
                     </Grid>
                 </Border>
-                <!-- Right Joystick -->
+                <!-- Right Buttons -->
                 <Border
                     BorderBrush="{DynamicResource ThemeControlBorderColor}"
                     BorderThickness="1"
@@ -865,9 +592,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsButtonA}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="ButtonA">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.ButtonA, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.ButtonA, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -882,9 +609,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsButtonB}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="ButtonB">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.ButtonB, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.ButtonB, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -899,9 +626,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsButtonX}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="ButtonX">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.ButtonX, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.ButtonX, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -916,9 +643,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsButtonY}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="ButtonY">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.ButtonY, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.ButtonY, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -938,100 +665,8 @@
                             Margin="0,0,0,10"
                             HorizontalAlignment="Center"
                             Text="{locale:Locale ControllerSettingsRStick}" />
-                        <!-- Right Joystick Keyboard -->
-                        <StackPanel
-                            IsVisible="{Binding !IsController}"
-                            Orientation="Vertical">
-                            <!-- Right Joystick Button -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickButton}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.RightKeyboardStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                            <!-- Right Joystick Up -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickUp}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.RightStickUp, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                            <!-- Right Joystick Down -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickDown}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.RightStickDown, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                            <!-- Right Joystick Left -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickLeft}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.RightStickLeft, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                            <!-- Right Joystick Right -->
-                            <StackPanel
-                                Margin="0,0,0,4"
-                                Orientation="Horizontal">
-                                <TextBlock
-                                    Margin="0,0,10,0"
-                                    Width="120"
-                                    HorizontalAlignment="Center"
-                                    VerticalAlignment="Center"
-                                    Text="{locale:Locale ControllerSettingsStickRight}"
-                                    TextAlignment="Center" />
-                                <ToggleButton>
-                                    <TextBlock
-                                        Text="{ReflectionBinding Configuration.RightStickRight, Mode=TwoWay, Converter={StaticResource Key}}"
-                                        TextAlignment="Center" />
-                                </ToggleButton>
-                            </StackPanel>
-                        </StackPanel>
                         <!-- Right Joystick Controller -->
-                        <StackPanel
-                            IsVisible="{Binding IsController}"
-                            Orientation="Vertical">
+                        <StackPanel Orientation="Vertical">
                             <!-- Right Joystick Button -->
                             <StackPanel
                                 Orientation="Horizontal">
@@ -1042,9 +677,9 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsStickButton}"
                                     TextAlignment="Center" />
-                                <ToggleButton>
+                                <ToggleButton Name="RightStickButton">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.RightControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.RightStickButton, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
@@ -1060,20 +695,20 @@
                                     VerticalAlignment="Center"
                                     Text="{locale:Locale ControllerSettingsStickStick}"
                                     TextAlignment="Center" />
-                                <ToggleButton Tag="stick">
+                                <ToggleButton Name="RightJoystick" Tag="stick">
                                     <TextBlock
-                                        Text="{ReflectionBinding Configuration.RightJoystick, Mode=TwoWay, Converter={StaticResource Key}}"
+                                        Text="{Binding Config.RightJoystick, Converter={StaticResource Key}}"
                                         TextAlignment="Center" />
                                 </ToggleButton>
                             </StackPanel>
                             <Separator Margin="0,8,0,8" Height="1" />
-                            <CheckBox IsChecked="{ReflectionBinding Configuration.RightInvertStickX}">
+                            <CheckBox IsChecked="{Binding Config.RightInvertStickX}">
                                 <TextBlock Text="{locale:Locale ControllerSettingsStickInvertXAxis}" />
                             </CheckBox>
-                            <CheckBox IsChecked="{ReflectionBinding Configuration.RightInvertStickY}">
+                            <CheckBox IsChecked="{Binding Config.RightInvertStickY}">
                                 <TextBlock Text="{locale:Locale ControllerSettingsStickInvertYAxis}" />
                             </CheckBox>
-                            <CheckBox IsChecked="{ReflectionBinding Configuration.RightRotate90}">
+                            <CheckBox IsChecked="{Binding Config.RightRotate90}">
                                 <TextBlock Text="{locale:Locale ControllerSettingsRotate90}" />
                             </CheckBox>
                             <Separator Margin="0,8,0,8" Height="1" />
@@ -1094,11 +729,11 @@
                                         Padding="0"
                                         VerticalAlignment="Center"
                                         Minimum="0"
-                                        Value="{ReflectionBinding Configuration.DeadzoneRight, Mode=TwoWay}" />
+                                        Value="{Binding Config.DeadzoneRight, Mode=TwoWay}" />
                                     <TextBlock
                                         VerticalAlignment="Center"
                                         Width="25"
-                                        Text="{ReflectionBinding Configuration.DeadzoneRight, StringFormat=\{0:0.00\}}" />
+                                        Text="{Binding Config.DeadzoneRight, StringFormat=\{0:0.00\}}" />
                                 </StackPanel>
                                 <TextBlock
                                     HorizontalAlignment="Center"
@@ -1114,11 +749,11 @@
                                         IsSnapToTickEnabled="True"
                                         SmallChange="0.01"
                                         Minimum="0"
-                                        Value="{ReflectionBinding Configuration.RangeRight, Mode=TwoWay}" />
+                                        Value="{Binding Config.RangeRight, Mode=TwoWay}" />
                                     <TextBlock
                                         VerticalAlignment="Center"
                                         Width="25"
-                                        Text="{ReflectionBinding Configuration.RangeRight, StringFormat=\{0:0.00\}}" />
+                                        Text="{Binding Config.RangeRight, StringFormat=\{0:0.00\}}" />
                                 </StackPanel>
                             </StackPanel>
                         </StackPanel>
diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs
index 351297060..b76648da7 100644
--- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs
+++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs
@@ -1,35 +1,29 @@
+using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Controls.Primitives;
 using Avalonia.Input;
 using Avalonia.Interactivity;
 using Avalonia.LogicalTree;
-using Ryujinx.Ava.Common.Locale;
 using Ryujinx.Ava.UI.Helpers;
-using Ryujinx.Ava.UI.Models;
-using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ava.UI.ViewModels.Input;
 using Ryujinx.Common.Configuration.Hid.Controller;
 using Ryujinx.Input;
 using Ryujinx.Input.Assigner;
-using System;
+using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
 
 namespace Ryujinx.Ava.UI.Views.Input
 {
     public partial class ControllerInputView : UserControl
     {
-        private bool _dialogOpen;
-
         private ButtonKeyAssigner _currentAssigner;
-        internal ControllerInputViewModel ViewModel { get; set; }
 
         public ControllerInputView()
         {
-            DataContext = ViewModel = new ControllerInputViewModel(this);
-
             InitializeComponent();
 
             foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
             {
-                if (visual is ToggleButton button && visual is not CheckBox)
+                if (visual is ToggleButton button and not CheckBox)
                 {
                     button.IsCheckedChanged += Button_IsCheckedChanged;
                 }
@@ -67,14 +61,87 @@ namespace Ryujinx.Ava.UI.Views.Input
 
                         PointerPressed += MouseClick;
 
-                        IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
+                        var viewModel = (DataContext as ControllerInputViewModel);
+
+                        IKeyboard keyboard = (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
                         IButtonAssigner assigner = CreateButtonAssigner(isStick);
 
                         _currentAssigner.ButtonAssigned += (sender, e) =>
                         {
-                            if (e.IsAssigned)
+                            if (e.ButtonValue.HasValue)
                             {
-                                ViewModel.IsModified = true;
+                                var buttonValue = e.ButtonValue.Value;
+                                viewModel.ParentModel.IsModified = true;
+
+                                switch (button.Name)
+                                {
+                                    case "ButtonZl":
+                                        viewModel.Config.ButtonZl = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "ButtonL":
+                                        viewModel.Config.ButtonL = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "ButtonMinus":
+                                        viewModel.Config.ButtonMinus = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "LeftStickButton":
+                                        viewModel.Config.LeftStickButton = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "LeftJoystick":
+                                        viewModel.Config.LeftJoystick = buttonValue.AsHidType<StickInputId>();
+                                        break;
+                                    case "DpadUp":
+                                        viewModel.Config.DpadUp = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "DpadDown":
+                                        viewModel.Config.DpadDown = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "DpadLeft":
+                                        viewModel.Config.DpadLeft = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "DpadRight":
+                                        viewModel.Config.DpadRight = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "LeftButtonSr":
+                                        viewModel.Config.LeftButtonSr = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "LeftButtonSl":
+                                        viewModel.Config.LeftButtonSl = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "RightButtonSr":
+                                        viewModel.Config.RightButtonSr = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "RightButtonSl":
+                                        viewModel.Config.RightButtonSl = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "ButtonZr":
+                                        viewModel.Config.ButtonZr = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "ButtonR":
+                                        viewModel.Config.ButtonR = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "ButtonPlus":
+                                        viewModel.Config.ButtonPlus = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "ButtonA":
+                                        viewModel.Config.ButtonA = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "ButtonB":
+                                        viewModel.Config.ButtonB = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "ButtonX":
+                                        viewModel.Config.ButtonX = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "ButtonY":
+                                        viewModel.Config.ButtonY = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "RightStickButton":
+                                        viewModel.Config.RightStickButton = buttonValue.AsHidType<GamepadInputId>();
+                                        break;
+                                    case "RightJoystick":
+                                        viewModel.Config.RightJoystick = buttonValue.AsHidType<StickInputId>();
+                                        break;
+                                }
                             }
                         };
 
@@ -84,8 +151,6 @@ namespace Ryujinx.Ava.UI.Views.Input
                     {
                         if (_currentAssigner != null)
                         {
-                            ToggleButton oldButton = _currentAssigner.ToggledButton;
-
                             _currentAssigner.Cancel();
                             _currentAssigner = null;
                             button.IsChecked = false;
@@ -100,82 +165,34 @@ namespace Ryujinx.Ava.UI.Views.Input
             }
         }
 
-        public void SaveCurrentProfile()
-        {
-            ViewModel.Save();
-        }
-
-        private IButtonAssigner CreateButtonAssigner(bool forStick)
-        {
-            IButtonAssigner assigner;
-
-            var device = ViewModel.Devices[ViewModel.Device];
-
-            if (device.Type == DeviceType.Keyboard)
-            {
-                assigner = new KeyboardKeyAssigner((IKeyboard)ViewModel.SelectedGamepad);
-            }
-            else if (device.Type == DeviceType.Controller)
-            {
-                assigner = new GamepadButtonAssigner(ViewModel.SelectedGamepad, (ViewModel.Config as StandardControllerInputConfig).TriggerThreshold, forStick);
-            }
-            else
-            {
-                throw new Exception("Controller not supported");
-            }
-
-            return assigner;
-        }
-
         private void MouseClick(object sender, PointerPressedEventArgs e)
         {
-            bool shouldUnbind = false;
-
-            if (e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed)
-            {
-                shouldUnbind = true;
-            }
+            bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
 
             _currentAssigner?.Cancel(shouldUnbind);
 
             PointerPressed -= MouseClick;
         }
 
-        private async void PlayerIndexBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+        private IButtonAssigner CreateButtonAssigner(bool forStick)
         {
-            if (ViewModel.IsModified && !_dialogOpen)
-            {
-                _dialogOpen = true;
+            IButtonAssigner assigner;
 
-                var result = await ContentDialogHelper.CreateConfirmationDialog(
-                    LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage],
-                    LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage],
-                    LocaleManager.Instance[LocaleKeys.InputDialogYes],
-                    LocaleManager.Instance[LocaleKeys.InputDialogNo],
-                    LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
+            var controllerInputViewModel = DataContext as ControllerInputViewModel;
 
-                if (result == UserResult.Yes)
-                {
-                    ViewModel.Save();
-                }
+            assigner = new GamepadButtonAssigner(
+                controllerInputViewModel.ParentModel.SelectedGamepad,
+                (controllerInputViewModel.ParentModel.Config as StandardControllerInputConfig).TriggerThreshold,
+                forStick);
 
-                _dialogOpen = false;
-
-                ViewModel.IsModified = false;
-
-                if (e.AddedItems.Count > 0)
-                {
-                    var player = (PlayerModel)e.AddedItems[0];
-                    ViewModel.PlayerId = player.Id;
-                }
-            }
+            return assigner;
         }
 
-        public void Dispose()
+        protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
         {
+            base.OnDetachedFromVisualTree(e);
             _currentAssigner?.Cancel();
             _currentAssigner = null;
-            ViewModel.Dispose();
         }
     }
 }
diff --git a/src/Ryujinx/UI/Views/Input/InputView.axaml b/src/Ryujinx/UI/Views/Input/InputView.axaml
new file mode 100644
index 000000000..b4940941c
--- /dev/null
+++ b/src/Ryujinx/UI/Views/Input/InputView.axaml
@@ -0,0 +1,225 @@
+<UserControl
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
+    xmlns:views="clr-namespace:Ryujinx.Ava.UI.Views.Input"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input"
+    HorizontalAlignment="Stretch"
+    VerticalAlignment="Stretch"
+    d:DesignHeight="800"
+    d:DesignWidth="800"
+    x:Class="Ryujinx.Ava.UI.Views.Input.InputView"
+    x:DataType="viewModels:InputViewModel"
+    x:CompileBindings="True"
+    mc:Ignorable="d"
+    Focusable="True">
+    <Design.DataContext>
+        <viewModels:InputViewModel />
+    </Design.DataContext>
+    <UserControl.Styles>
+        <Style Selector="ToggleButton">
+            <Setter Property="Width" Value="90" />
+            <Setter Property="Height" Value="27" />
+            <Setter Property="HorizontalAlignment" Value="Stretch" />
+        </Style>
+    </UserControl.Styles>
+    <StackPanel
+        HorizontalAlignment="Stretch"
+        VerticalAlignment="Stretch"
+        Orientation="Vertical">
+        <StackPanel
+            Margin="0 0 0 5"
+            Orientation="Vertical"
+            Spacing="5">
+            <Grid>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="10" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <!-- Player Selection -->
+                <Grid
+                    Grid.Column="0"
+                    Margin="2"
+                    HorizontalAlignment="Stretch"
+                    VerticalAlignment="Center">
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="Auto"/>
+                        <ColumnDefinition Width="*" />
+                    </Grid.ColumnDefinitions>
+                    <TextBlock
+                        Margin="5,0,10,0"
+                        Width="90"
+                        HorizontalAlignment="Left"
+                        VerticalAlignment="Center"
+                        Text="{locale:Locale ControllerSettingsPlayer}" />
+                    <ComboBox
+                        Grid.Column="1"
+                        Name="PlayerIndexBox"
+                        HorizontalAlignment="Stretch"
+                        VerticalAlignment="Center"
+                        SelectionChanged="PlayerIndexBox_OnSelectionChanged"
+                        ItemsSource="{Binding PlayerIndexes}"
+                        SelectedIndex="{Binding PlayerId}">
+                        <ComboBox.ItemTemplate>
+                            <DataTemplate>
+                                <TextBlock Text="{Binding Name}" />
+                            </DataTemplate>
+                        </ComboBox.ItemTemplate>
+                    </ComboBox>
+                </Grid>
+                <!-- Profile Selection -->
+                <Grid
+                    Grid.Column="2"
+                    Margin="2"
+                    HorizontalAlignment="Stretch"
+                    VerticalAlignment="Center">
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="Auto"/>
+                        <ColumnDefinition Width="*" />
+                        <ColumnDefinition Width="Auto"/>
+                        <ColumnDefinition Width="Auto"/>
+                        <ColumnDefinition Width="Auto"/>
+                    </Grid.ColumnDefinitions>
+                    <TextBlock
+                        Margin="5,0,10,0"
+                        Width="90"
+                        HorizontalAlignment="Left"
+                        VerticalAlignment="Center"
+                        Text="{locale:Locale ControllerSettingsProfile}" />
+                    <ui:FAComboBox
+                        Grid.Column="1"
+                        IsEditable="True"
+                        Name="ProfileBox"
+                        HorizontalAlignment="Stretch"
+                        VerticalAlignment="Center"
+                        SelectedIndex="0"
+                        ItemsSource="{Binding ProfilesList}"
+                        Text="{Binding ProfileName, Mode=TwoWay}" />
+                    <Button
+                        Grid.Column="2"
+                        MinWidth="0"
+                        Margin="5,0,0,0"
+                        VerticalAlignment="Center"
+                        ToolTip.Tip="{locale:Locale ControllerSettingsLoadProfileToolTip}"
+                        Command="{Binding LoadProfile}">
+                        <ui:SymbolIcon
+                            Symbol="Upload"
+                            FontSize="15"
+                            Height="20" />
+                    </Button>
+                    <Button
+                        Grid.Column="3"
+                            MinWidth="0"
+                            Margin="5,0,0,0"
+                            VerticalAlignment="Center"
+                            ToolTip.Tip="{locale:Locale ControllerSettingsSaveProfileToolTip}"
+                            Command="{Binding SaveProfile}">
+                        <ui:SymbolIcon
+                            Symbol="Save"
+                            FontSize="15"
+                            Height="20" />
+                    </Button>
+                    <Button
+                        Grid.Column="4"
+                            MinWidth="0"
+                            Margin="5,0,0,0"
+                            VerticalAlignment="Center"
+                            ToolTip.Tip="{locale:Locale ControllerSettingsRemoveProfileToolTip}"
+                            Command="{Binding RemoveProfile}">
+                        <ui:SymbolIcon
+                            Symbol="Delete"
+                            FontSize="15"
+                            Height="20" />
+                    </Button>
+                </Grid>
+            </Grid>
+            <Separator />
+            <Grid>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="10" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <!-- Input Device -->
+                <Grid
+                    Grid.Column="0"
+                    Margin="2"
+                    HorizontalAlignment="Stretch">
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="Auto"/>
+                        <ColumnDefinition Width="*"/>
+                        <ColumnDefinition Width="Auto" />
+                    </Grid.ColumnDefinitions>
+                    <TextBlock
+                        Grid.Column="0"
+                        Margin="5,0,10,0"
+                        Width="90"
+                        HorizontalAlignment="Left"
+                        VerticalAlignment="Center"
+                        Text="{locale:Locale ControllerSettingsInputDevice}" />
+                    <ComboBox
+                        Grid.Column="1"
+                        Name="DeviceBox"
+                        HorizontalAlignment="Stretch"
+                        VerticalAlignment="Center"
+                        ItemsSource="{Binding DeviceList}"
+                        SelectedIndex="{Binding Device}" />
+                    <Button
+                        Grid.Column="2"
+                        MinWidth="0"
+                        Margin="5,0,0,0"
+                        VerticalAlignment="Center"
+                        Command="{Binding LoadDevices}">
+                        <ui:SymbolIcon
+                            Symbol="Refresh"
+                            FontSize="15"
+                            Height="20"/>
+                    </Button>
+                </Grid>
+                <!-- Controller Type -->
+                <Grid
+                    Grid.Column="2"
+                    Margin="2"
+                    HorizontalAlignment="Stretch"
+                    VerticalAlignment="Center">
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="Auto"/>
+                        <ColumnDefinition Width="*" />
+                    </Grid.ColumnDefinitions>
+                    <TextBlock
+                        Margin="5,0,10,0"
+                        Width="90"
+                        HorizontalAlignment="Left"
+                        VerticalAlignment="Center"
+                        Text="{locale:Locale ControllerSettingsControllerType}" />
+                    <ComboBox
+                        Grid.Column="1"
+                        HorizontalAlignment="Stretch"
+                        ItemsSource="{Binding Controllers}"
+                        SelectedIndex="{Binding Controller}">
+                        <ComboBox.ItemTemplate>
+                            <DataTemplate DataType="models:ControllerModel">
+                                <TextBlock Text="{Binding Name}" />
+                            </DataTemplate>
+                        </ComboBox.ItemTemplate>
+                    </ComboBox>
+                </Grid>
+            </Grid>
+        </StackPanel>
+        <ContentControl Content="{Binding ConfigViewModel}" IsVisible="{Binding ShowSettings}">
+            <ContentControl.DataTemplates>
+                <DataTemplate DataType="viewModels:ControllerInputViewModel">
+                    <views:ControllerInputView />
+                </DataTemplate>
+                <DataTemplate DataType="viewModels:KeyboardInputViewModel">
+                    <views:KeyboardInputView />
+                </DataTemplate>
+            </ContentControl.DataTemplates>
+        </ContentControl>
+    </StackPanel>
+</UserControl>
diff --git a/src/Ryujinx/UI/Views/Input/InputView.axaml.cs b/src/Ryujinx/UI/Views/Input/InputView.axaml.cs
new file mode 100644
index 000000000..356381a8a
--- /dev/null
+++ b/src/Ryujinx/UI/Views/Input/InputView.axaml.cs
@@ -0,0 +1,61 @@
+using Avalonia.Controls;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.Models;
+using Ryujinx.Ava.UI.ViewModels.Input;
+
+namespace Ryujinx.Ava.UI.Views.Input
+{
+    public partial class InputView : UserControl
+    {
+        private bool _dialogOpen;
+        private InputViewModel ViewModel { get; set; }
+
+        public InputView()
+        {
+            DataContext = ViewModel = new InputViewModel(this);
+
+            InitializeComponent();
+        }
+
+        public void SaveCurrentProfile()
+        {
+            ViewModel.Save();
+        }
+
+        private async void PlayerIndexBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            if (ViewModel.IsModified && !_dialogOpen)
+            {
+                _dialogOpen = true;
+
+                var result = await ContentDialogHelper.CreateConfirmationDialog(
+                    LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage],
+                    LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage],
+                    LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                    LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                    LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
+
+                if (result == UserResult.Yes)
+                {
+                    ViewModel.Save();
+                }
+
+                _dialogOpen = false;
+
+                ViewModel.IsModified = false;
+
+                if (e.AddedItems.Count > 0)
+                {
+                    var player = (PlayerModel)e.AddedItems[0];
+                    ViewModel.PlayerId = player.Id;
+                }
+            }
+        }
+
+        public void Dispose()
+        {
+            ViewModel.Dispose();
+        }
+    }
+}
diff --git a/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml b/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml
new file mode 100644
index 000000000..e4566f463
--- /dev/null
+++ b/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml
@@ -0,0 +1,675 @@
+<UserControl
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input"
+    xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
+    HorizontalAlignment="Stretch"
+    VerticalAlignment="Stretch"
+    d:DesignHeight="800"
+    d:DesignWidth="800"
+    x:Class="Ryujinx.Ava.UI.Views.Input.KeyboardInputView"
+    x:DataType="viewModels:KeyboardInputViewModel"
+    x:CompileBindings="True"
+    mc:Ignorable="d"
+    Focusable="True">
+    <Design.DataContext>
+        <viewModels:KeyboardInputViewModel />
+    </Design.DataContext>
+    <UserControl.Resources>
+        <helpers:KeyValueConverter x:Key="Key" />
+    </UserControl.Resources>
+    <UserControl.Styles>
+        <Style Selector="ToggleButton">
+            <Setter Property="Width" Value="90" />
+            <Setter Property="Height" Value="27" />
+            <Setter Property="HorizontalAlignment" Value="Stretch" />
+        </Style>
+    </UserControl.Styles>
+    <StackPanel
+        HorizontalAlignment="Stretch"
+        VerticalAlignment="Stretch"
+        Orientation="Vertical">
+        <!-- Button / JoyStick Settings -->
+        <Grid
+            Name="SettingButtons"
+            MinHeight="450">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="Auto" />
+                <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="Auto" />
+            </Grid.ColumnDefinitions>
+            <!-- Left Controls -->
+            <StackPanel
+                Orientation="Vertical"
+                Margin="0,0,5,0"
+                Grid.Column="0">
+                <!-- Left Triggers -->
+                <Border
+                    BorderBrush="{DynamicResource ThemeControlBorderColor}"
+                    BorderThickness="1"
+                    IsVisible="{Binding IsLeft}"
+                    MinHeight="90"
+                    CornerRadius="5">
+                    <Grid
+                        Margin="10"
+                        HorizontalAlignment="Stretch">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition />
+                            <ColumnDefinition />
+                        </Grid.ColumnDefinitions>
+                        <Grid.RowDefinitions>
+                            <RowDefinition />
+                            <RowDefinition />
+                        </Grid.RowDefinitions>
+                        <StackPanel
+                            Grid.Column="0"
+                            Grid.Row="0"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsTriggerZL}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="ButtonZl">
+                                <TextBlock
+                                    Text="{Binding Config.ButtonZl, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                        <StackPanel
+                            Grid.Column="0"
+                            Grid.Row="1"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsTriggerL}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="ButtonL">
+                                <TextBlock
+                                    Text="{Binding Config.ButtonL, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                        <StackPanel
+                            Grid.Column="1"
+                            Grid.Row="1"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsButtonMinus}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="ButtonMinus">
+                                <TextBlock
+                                    Text="{Binding Config.ButtonMinus, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                    </Grid>
+                </Border>
+                <!-- Left Joystick -->
+                <Border
+                    BorderBrush="{DynamicResource ThemeControlBorderColor}"
+                    BorderThickness="1"
+                    IsVisible="{Binding IsLeft}"
+                    Margin="0,5,0,0"
+                    CornerRadius="5">
+                    <StackPanel
+                        Margin="10"
+                        Orientation="Vertical">
+                        <TextBlock
+                            Margin="0,0,0,10"
+                            HorizontalAlignment="Center"
+                            Text="{locale:Locale ControllerSettingsLStick}" />
+                        <!-- Left Joystick Keyboard -->
+                        <StackPanel Orientation="Vertical">
+                            <!-- Left Joystick Button -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickButton}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="LeftStickButton">
+                                    <TextBlock
+                                        Text="{Binding Config.LeftStickButton, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Left Joystick Up -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickUp}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="LeftStickUp">
+                                    <TextBlock
+                                        Text="{Binding Config.LeftStickUp, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Left Joystick Down -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickDown}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="LeftStickDown">
+                                    <TextBlock
+                                        Text="{Binding Config.LeftStickDown, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Left Joystick Left -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickLeft}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="LeftStickLeft">
+                                    <TextBlock
+                                        Text="{Binding Config.LeftStickLeft, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Left Joystick Right -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickRight}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="LeftStickRight">
+                                    <TextBlock
+                                        Text="{Binding Config.LeftStickRight, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                        </StackPanel>
+                    </StackPanel>
+                </Border>
+                <!-- Left DPad -->
+                <Border
+                    BorderBrush="{DynamicResource ThemeControlBorderColor}"
+                    BorderThickness="1"
+                    VerticalAlignment="Top"
+                    IsVisible="{Binding IsLeft}"
+                    Margin="0,5,0,0"
+                    CornerRadius="5">
+                    <StackPanel
+                        Margin="10"
+                        Orientation="Vertical">
+                        <TextBlock
+                            Margin="0,0,0,10"
+                            HorizontalAlignment="Center"
+                            Text="{locale:Locale ControllerSettingsDPad}" />
+                        <StackPanel Orientation="Vertical">
+                            <!-- Left DPad Up -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsDPadUp}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="DpadUp">
+                                    <TextBlock
+                                        Text="{Binding Config.DpadUp, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Left DPad Down -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsDPadDown}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="DpadDown">
+                                    <TextBlock
+                                        Text="{Binding Config.DpadDown, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Left DPad Left -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsDPadLeft}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="DpadLeft">
+                                    <TextBlock
+                                        Text="{Binding Config.DpadLeft, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Left DPad Right -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsDPadRight}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="DpadRight">
+                                    <TextBlock
+                                        Text="{Binding Config.DpadRight, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                        </StackPanel>
+                    </StackPanel>
+                </Border>
+            </StackPanel>
+            <!-- Triggers & Side Buttons -->
+            <StackPanel
+                Grid.Column="1"
+                HorizontalAlignment="Stretch"
+                VerticalAlignment="Stretch">
+                <!-- Controller Picture -->
+                <Image
+                    Margin="0,10"
+                    MaxHeight="300"
+                    HorizontalAlignment="Stretch"
+                    VerticalAlignment="Stretch"
+                    Source="{Binding Image}" />
+                <Border
+                    BorderBrush="{DynamicResource ThemeControlBorderColor}"
+                    BorderThickness="1"
+                    CornerRadius="5"
+                    MinHeight="90"
+                    IsVisible="{Binding HasSides}">
+                    <StackPanel
+                        Margin="8"
+                        Orientation="Vertical">
+                        <StackPanel
+                            Margin="0,4,0,0"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            IsVisible="{Binding IsLeft}"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsLeftSR}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="LeftButtonSr">
+                                <TextBlock
+                                    Text="{Binding Config.LeftButtonSr, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                        <StackPanel
+                            Margin="0,4,0,0"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            IsVisible="{Binding IsLeft}"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsLeftSL}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="LeftButtonSl">
+                                <TextBlock
+                                    Text="{Binding Config.LeftButtonSl, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                        <StackPanel
+                            Margin="0,4,0,0"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            IsVisible="{Binding IsRight}"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsRightSR}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="RightButtonSr">
+                                <TextBlock
+                                    Text="{Binding Config.RightButtonSr, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                        <StackPanel
+                            Margin="0,4,0,0"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            IsVisible="{Binding IsRight}"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsRightSL}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="RightButtonSl">
+                                <TextBlock
+                                    Text="{Binding Config.RightButtonSl, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                    </StackPanel>
+                </Border>
+            </StackPanel>
+            <!-- Right Controls -->
+            <StackPanel
+                Orientation="Vertical"
+                Margin="5,0,0,0"
+                Grid.Column="2">
+                <!-- Right Triggers -->
+                <Border
+                    BorderBrush="{DynamicResource ThemeControlBorderColor}"
+                    BorderThickness="1"
+                    IsVisible="{Binding IsRight}"
+                    MinHeight="90"
+                    CornerRadius="5">
+                    <Grid
+                        Margin="10"
+                        HorizontalAlignment="Stretch">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition />
+                            <ColumnDefinition />
+                        </Grid.ColumnDefinitions>
+                        <Grid.RowDefinitions>
+                            <RowDefinition />
+                            <RowDefinition />
+                        </Grid.RowDefinitions>
+                        <StackPanel
+                            Grid.Column="1"
+                            Grid.Row="0"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsTriggerZR}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="ButtonZr">
+                                <TextBlock
+                                    Text="{Binding Config.ButtonZr, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                        <StackPanel
+                            Grid.Column="1"
+                            Grid.Row="1"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsTriggerR}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="ButtonR">
+                                <TextBlock
+                                    Text="{Binding Config.ButtonR, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                        <StackPanel
+                            Grid.Column="0"
+                            Grid.Row="1"
+                            HorizontalAlignment="Right"
+                            VerticalAlignment="Center"
+                            Orientation="Horizontal">
+                            <TextBlock
+                                Width="20"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{locale:Locale ControllerSettingsButtonPlus}"
+                                TextAlignment="Center" />
+                            <ToggleButton Name="ButtonPlus">
+                                <TextBlock
+                                    Text="{Binding Config.ButtonPlus, Converter={StaticResource Key}}"
+                                    TextAlignment="Center" />
+                            </ToggleButton>
+                        </StackPanel>
+                    </Grid>
+                </Border>
+                <!-- Right Buttons -->
+                <Border
+                    BorderBrush="{DynamicResource ThemeControlBorderColor}"
+                    BorderThickness="1"
+                    IsVisible="{Binding IsRight}"
+                    Margin="0,5,0,0"
+                    CornerRadius="5">
+                    <StackPanel
+                        Margin="10"
+                        Orientation="Vertical">
+                        <TextBlock
+                            Margin="0,0,0,10"
+                            HorizontalAlignment="Center"
+                            Text="{locale:Locale ControllerSettingsButtons}" />
+                        <StackPanel
+                            Orientation="Vertical">
+                            <!-- Right Buttons A -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Width="120"
+                                    Margin="0,0,10,0"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsButtonA}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="ButtonA">
+                                    <TextBlock
+                                        Text="{Binding Config.ButtonA, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Right Buttons B -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Width="120"
+                                    Margin="0,0,10,0"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsButtonB}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="ButtonB">
+                                    <TextBlock
+                                        Text="{Binding Config.ButtonB, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Right Buttons X -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Width="120"
+                                    Margin="0,0,10,0"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsButtonX}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="ButtonX">
+                                    <TextBlock
+                                        Text="{Binding Config.ButtonX, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Right Buttons Y -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Width="120"
+                                    Margin="0,0,10,0"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsButtonY}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="ButtonY">
+                                    <TextBlock
+                                        Text="{Binding Config.ButtonY, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                        </StackPanel>
+                    </StackPanel>
+                </Border>
+                <!-- Right DPad -->
+                <Border
+                    Padding="10"
+                    BorderBrush="{DynamicResource ThemeControlBorderColor}"
+                    BorderThickness="1"
+                    CornerRadius="5"
+                    IsVisible="{Binding IsRight}"
+                    Margin="0,5,0,0">
+                    <StackPanel Orientation="Vertical">
+                        <TextBlock
+                            Margin="0,0,0,10"
+                            HorizontalAlignment="Center"
+                            Text="{locale:Locale ControllerSettingsRStick}" />
+                        <!-- Right Joystick Keyboard -->
+                        <StackPanel Orientation="Vertical">
+                            <!-- Right Joystick Button -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickButton}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="RightStickButton">
+                                    <TextBlock
+                                        Text="{Binding Config.RightStickButton, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Right Joystick Up -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickUp}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="RightStickUp">
+                                    <TextBlock
+                                        Text="{Binding Config.RightStickUp, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Right Joystick Down -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickDown}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="RightStickDown">
+                                    <TextBlock
+                                        Text="{Binding Config.RightStickDown, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Right Joystick Left -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickLeft}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="RightStickLeft">
+                                    <TextBlock
+                                        Text="{Binding Config.RightStickLeft, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                            <!-- Right Joystick Right -->
+                            <StackPanel
+                                Margin="0,0,0,4"
+                                Orientation="Horizontal">
+                                <TextBlock
+                                    Margin="0,0,10,0"
+                                    Width="120"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    Text="{locale:Locale ControllerSettingsStickRight}"
+                                    TextAlignment="Center" />
+                                <ToggleButton Name="RightStickRight">
+                                    <TextBlock
+                                        Text="{Binding Config.RightStickRight, Converter={StaticResource Key}}"
+                                        TextAlignment="Center" />
+                                </ToggleButton>
+                            </StackPanel>
+                        </StackPanel>
+                    </StackPanel>
+                </Border>
+            </StackPanel>
+        </Grid>
+    </StackPanel>
+</UserControl>
\ No newline at end of file
diff --git a/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs b/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs
new file mode 100644
index 000000000..f17c7496c
--- /dev/null
+++ b/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs
@@ -0,0 +1,208 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.LogicalTree;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.ViewModels.Input;
+using Ryujinx.Input;
+using Ryujinx.Input.Assigner;
+using Key = Ryujinx.Common.Configuration.Hid.Key;
+
+namespace Ryujinx.Ava.UI.Views.Input
+{
+    public partial class KeyboardInputView : UserControl
+    {
+        private ButtonKeyAssigner _currentAssigner;
+
+        public KeyboardInputView()
+        {
+            InitializeComponent();
+
+            foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
+            {
+                if (visual is ToggleButton button and not CheckBox)
+                {
+                    button.IsCheckedChanged += Button_IsCheckedChanged;
+                }
+            }
+        }
+
+        protected override void OnPointerReleased(PointerReleasedEventArgs e)
+        {
+            base.OnPointerReleased(e);
+
+            if (_currentAssigner != null && _currentAssigner.ToggledButton != null && !_currentAssigner.ToggledButton.IsPointerOver)
+            {
+                _currentAssigner.Cancel();
+            }
+        }
+
+        private void Button_IsCheckedChanged(object sender, RoutedEventArgs e)
+        {
+            if (sender is ToggleButton button)
+            {
+                if ((bool)button.IsChecked)
+                {
+                    if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
+                    {
+                        return;
+                    }
+
+                    if (_currentAssigner == null)
+                    {
+                        _currentAssigner = new ButtonKeyAssigner(button);
+
+                        Focus(NavigationMethod.Pointer);
+
+                        PointerPressed += MouseClick;
+
+                        var viewModel = (DataContext as KeyboardInputViewModel);
+
+                        IKeyboard keyboard = (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
+                        IButtonAssigner assigner = CreateButtonAssigner();
+
+                        _currentAssigner.ButtonAssigned += (sender, e) =>
+                        {
+                            if (e.ButtonValue.HasValue)
+                            {
+                                var buttonValue = e.ButtonValue.Value;
+                                viewModel.ParentModel.IsModified = true;
+
+                                switch (button.Name)
+                                {
+                                    case "ButtonZl":
+                                        viewModel.Config.ButtonZl = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ButtonL":
+                                        viewModel.Config.ButtonL = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ButtonMinus":
+                                        viewModel.Config.ButtonMinus = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "LeftStickButton":
+                                        viewModel.Config.LeftStickButton = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "LeftStickUp":
+                                        viewModel.Config.LeftStickUp = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "LeftStickDown":
+                                        viewModel.Config.LeftStickDown = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "LeftStickRight":
+                                        viewModel.Config.LeftStickRight = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "LeftStickLeft":
+                                        viewModel.Config.LeftStickLeft = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "DpadUp":
+                                        viewModel.Config.DpadUp = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "DpadDown":
+                                        viewModel.Config.DpadDown = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "DpadLeft":
+                                        viewModel.Config.DpadLeft = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "DpadRight":
+                                        viewModel.Config.DpadRight = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "LeftButtonSr":
+                                        viewModel.Config.LeftButtonSr = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "LeftButtonSl":
+                                        viewModel.Config.LeftButtonSl = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "RightButtonSr":
+                                        viewModel.Config.RightButtonSr = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "RightButtonSl":
+                                        viewModel.Config.RightButtonSl = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ButtonZr":
+                                        viewModel.Config.ButtonZr = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ButtonR":
+                                        viewModel.Config.ButtonR = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ButtonPlus":
+                                        viewModel.Config.ButtonPlus = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ButtonA":
+                                        viewModel.Config.ButtonA = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ButtonB":
+                                        viewModel.Config.ButtonB = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ButtonX":
+                                        viewModel.Config.ButtonX = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ButtonY":
+                                        viewModel.Config.ButtonY = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "RightStickButton":
+                                        viewModel.Config.RightStickButton = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "RightStickUp":
+                                        viewModel.Config.RightStickUp = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "RightStickDown":
+                                        viewModel.Config.RightStickDown = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "RightStickRight":
+                                        viewModel.Config.RightStickRight = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "RightStickLeft":
+                                        viewModel.Config.RightStickLeft = buttonValue.AsHidType<Key>();
+                                        break;
+                                }
+                            }
+                        };
+
+                        _currentAssigner.GetInputAndAssign(assigner, keyboard);
+                    }
+                    else
+                    {
+                        if (_currentAssigner != null)
+                        {
+                            _currentAssigner.Cancel();
+                            _currentAssigner = null;
+                            button.IsChecked = false;
+                        }
+                    }
+                }
+                else
+                {
+                    _currentAssigner?.Cancel();
+                    _currentAssigner = null;
+                }
+            }
+        }
+
+        private void MouseClick(object sender, PointerPressedEventArgs e)
+        {
+            bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
+
+            _currentAssigner?.Cancel(shouldUnbind);
+
+            PointerPressed -= MouseClick;
+        }
+
+        private IButtonAssigner CreateButtonAssigner()
+        {
+            IButtonAssigner assigner;
+
+            assigner = new KeyboardKeyAssigner((IKeyboard)(DataContext as KeyboardInputViewModel).ParentModel.SelectedGamepad);
+
+            return assigner;
+        }
+
+        protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
+        {
+            base.OnDetachedFromVisualTree(e);
+            _currentAssigner?.Cancel();
+            _currentAssigner = null;
+        }
+    }
+}
diff --git a/src/Ryujinx/UI/Views/Input/MotionInputView.axaml b/src/Ryujinx/UI/Views/Input/MotionInputView.axaml
index a6b587f67..0d018e297 100644
--- a/src/Ryujinx/UI/Views/Input/MotionInputView.axaml
+++ b/src/Ryujinx/UI/Views/Input/MotionInputView.axaml
@@ -6,7 +6,7 @@
     xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
     xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
     xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
-    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input"
     mc:Ignorable="d"
     x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView"
     x:DataType="viewModels:MotionInputViewModel"
diff --git a/src/Ryujinx/UI/Views/Input/MotionInputView.axaml.cs b/src/Ryujinx/UI/Views/Input/MotionInputView.axaml.cs
index 1b340752b..2304364b6 100644
--- a/src/Ryujinx/UI/Views/Input/MotionInputView.axaml.cs
+++ b/src/Ryujinx/UI/Views/Input/MotionInputView.axaml.cs
@@ -1,9 +1,7 @@
 using Avalonia.Controls;
 using FluentAvalonia.UI.Controls;
 using Ryujinx.Ava.Common.Locale;
-using Ryujinx.Ava.UI.Models;
-using Ryujinx.Ava.UI.ViewModels;
-using Ryujinx.Common.Configuration.Hid.Controller;
+using Ryujinx.Ava.UI.ViewModels.Input;
 using System.Threading.Tasks;
 
 namespace Ryujinx.Ava.UI.Views.Input
@@ -19,7 +17,7 @@ namespace Ryujinx.Ava.UI.Views.Input
 
         public MotionInputView(ControllerInputViewModel viewModel)
         {
-            var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
+            var config = viewModel.Config;
 
             _viewModel = new MotionInputViewModel
             {
@@ -51,7 +49,7 @@ namespace Ryujinx.Ava.UI.Views.Input
             };
             contentDialog.PrimaryButtonClick += (sender, args) =>
             {
-                var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
+                var config = viewModel.Config;
                 config.Slot = content._viewModel.Slot;
                 config.Sensitivity = content._viewModel.Sensitivity;
                 config.GyroDeadzone = content._viewModel.GyroDeadzone;
diff --git a/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml b/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml
index 5b7087a47..1beb1f06e 100644
--- a/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml
+++ b/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml
@@ -5,7 +5,7 @@
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
-    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input"
     mc:Ignorable="d"
     x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView"
     x:DataType="viewModels:RumbleInputViewModel"
diff --git a/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml.cs b/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml.cs
index 9307f872c..58a4b416b 100644
--- a/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml.cs
+++ b/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml.cs
@@ -1,9 +1,7 @@
 using Avalonia.Controls;
 using FluentAvalonia.UI.Controls;
 using Ryujinx.Ava.Common.Locale;
-using Ryujinx.Ava.UI.Models;
-using Ryujinx.Ava.UI.ViewModels;
-using Ryujinx.Common.Configuration.Hid.Controller;
+using Ryujinx.Ava.UI.ViewModels.Input;
 using System.Threading.Tasks;
 
 namespace Ryujinx.Ava.UI.Views.Input
@@ -19,7 +17,7 @@ namespace Ryujinx.Ava.UI.Views.Input
 
         public RumbleInputView(ControllerInputViewModel viewModel)
         {
-            var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
+            var config = viewModel.Config;
 
             _viewModel = new RumbleInputViewModel
             {
@@ -47,7 +45,7 @@ namespace Ryujinx.Ava.UI.Views.Input
 
             contentDialog.PrimaryButtonClick += (sender, args) =>
             {
-                var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
+                var config = viewModel.Config;
                 config.StrongRumble = content._viewModel.StrongRumble;
                 config.WeakRumble = content._viewModel.WeakRumble;
             };
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml
index b4eae01ef..bffcada05 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml
@@ -9,6 +9,7 @@
     xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
     mc:Ignorable="d"
     x:DataType="viewModels:SettingsViewModel"
+    x:CompileBindings="True"
     Focusable="True">
     <Design.DataContext>
         <viewModels:SettingsViewModel />
@@ -16,6 +17,23 @@
     <UserControl.Resources>
         <helpers:KeyValueConverter x:Key="Key" />
     </UserControl.Resources>
+    <UserControl.Styles>
+        <Style Selector="StackPanel > StackPanel">
+            <Setter Property="Margin" Value="10, 0, 0, 0" />
+            <Setter Property="Orientation" Value="Horizontal" />
+        </Style>
+        <Style Selector="StackPanel > StackPanel > TextBlock">
+            <Setter Property="VerticalAlignment" Value="Center" />
+            <Setter Property="Width" Value="230" />
+        </Style>
+        <Style Selector="ToggleButton">
+            <Setter Property="Width" Value="90" />
+            <Setter Property="Height" Value="27" />
+        </Style>
+        <Style Selector="ToggleButton > TextBlock">
+            <Setter Property="TextAlignment" Value="Center" />
+        </Style>
+    </UserControl.Styles>
     <ScrollViewer
         Name="HotkeysPage"
         HorizontalAlignment="Stretch"
@@ -23,81 +41,69 @@
         HorizontalScrollBarVisibility="Disabled"
         VerticalScrollBarVisibility="Auto">
         <Border Classes="settings">
-            <StackPanel Margin="10" Orientation="Vertical" Spacing="10">
-                <TextBlock Classes="h1" Text="{locale:Locale SettingsTabHotkeysHotkeys}" />
-                <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
-                    <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleVsyncHotkey}" Width="230" />
-                    <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
-                        <TextBlock
-                            Text="{Binding KeyboardHotkeys.ToggleVsync, Mode=TwoWay, Converter={StaticResource Key}}"
-                            TextAlignment="Center" />
+            <StackPanel
+                Name="SettingButtons"
+                Margin="10"
+                Orientation="Vertical"
+                Spacing="10">
+                <TextBlock
+                    Classes="h1"
+                    Text="{locale:Locale SettingsTabHotkeysHotkeys}" />
+                <StackPanel>
+                    <TextBlock Text="{locale:Locale SettingsTabHotkeysToggleVsyncHotkey}" />
+                    <ToggleButton Name="ToggleVsync">
+                        <TextBlock Text="{Binding KeyboardHotkey.ToggleVsync, Converter={StaticResource Key}}" />
                     </ToggleButton>
                 </StackPanel>
-                <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
-                    <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysScreenshotHotkey}" Width="230" />
-                    <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
-                        <TextBlock
-                            Text="{Binding KeyboardHotkeys.Screenshot, Mode=TwoWay, Converter={StaticResource Key}}"
-                            TextAlignment="Center" />
+                <StackPanel>
+                    <TextBlock Text="{locale:Locale SettingsTabHotkeysScreenshotHotkey}" />
+                    <ToggleButton Name="Screenshot">
+                        <TextBlock Text="{Binding KeyboardHotkey.Screenshot, Converter={StaticResource Key}}" />
                     </ToggleButton>
                 </StackPanel>
-                <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
-                    <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysShowUiHotkey}" Width="230" />
-                    <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
-                        <TextBlock
-                            Text="{Binding KeyboardHotkeys.ShowUI, Mode=TwoWay, Converter={StaticResource Key}}"
-                            TextAlignment="Center" />
+                <StackPanel>
+                    <TextBlock Text="{locale:Locale SettingsTabHotkeysShowUiHotkey}" />
+                    <ToggleButton Name="ShowUI">
+                        <TextBlock Text="{Binding KeyboardHotkey.ShowUI, Converter={StaticResource Key}}" />
                     </ToggleButton>
                 </StackPanel>
-                <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
-                    <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysPauseHotkey}" Width="230" />
-                    <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
-                        <TextBlock
-                            Text="{Binding KeyboardHotkeys.Pause, Mode=TwoWay, Converter={StaticResource Key}}"
-                            TextAlignment="Center" />
+                <StackPanel>
+                    <TextBlock Text="{locale:Locale SettingsTabHotkeysPauseHotkey}" />
+                    <ToggleButton Name="Pause">
+                        <TextBlock Text="{Binding KeyboardHotkey.Pause, Converter={StaticResource Key}}" />
                     </ToggleButton>
                 </StackPanel>
-                <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
-                    <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleMuteHotkey}" Width="230" />
-                    <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
-                        <TextBlock
-                            Text="{Binding KeyboardHotkeys.ToggleMute, Mode=TwoWay, Converter={StaticResource Key}}"
-                            TextAlignment="Center" />
+                <StackPanel>
+                    <TextBlock Text="{locale:Locale SettingsTabHotkeysToggleMuteHotkey}" />
+                    <ToggleButton Name="ToggleMute">
+                        <TextBlock Text="{Binding KeyboardHotkey.ToggleMute, Converter={StaticResource Key}}" />
                     </ToggleButton>
                 </StackPanel>
-                <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
-                    <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleUpHotkey}" Width="230" />
-                    <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
-                        <TextBlock
-                            Text="{Binding KeyboardHotkeys.ResScaleUp, Mode=TwoWay, Converter={StaticResource Key}}"
-                            TextAlignment="Center" />
+                <StackPanel>
+                    <TextBlock Text="{locale:Locale SettingsTabHotkeysResScaleUpHotkey}" />
+                    <ToggleButton Name="ResScaleUp">
+                        <TextBlock Text="{Binding KeyboardHotkey.ResScaleUp, Converter={StaticResource Key}}" />
                     </ToggleButton>
                 </StackPanel>
-                <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
-                    <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleDownHotkey}" Width="230" />
-                    <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
-                        <TextBlock
-                            Text="{Binding KeyboardHotkeys.ResScaleDown, Mode=TwoWay, Converter={StaticResource Key}}"
-                            TextAlignment="Center" />
+                <StackPanel>
+                    <TextBlock Text="{locale:Locale SettingsTabHotkeysResScaleDownHotkey}" />
+                    <ToggleButton Name="ResScaleDown">
+                        <TextBlock Text="{Binding KeyboardHotkey.ResScaleDown, Converter={StaticResource Key}}" />
                     </ToggleButton>
                 </StackPanel>
-                <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
-                    <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" />
-                    <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
-                        <TextBlock
-                            Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}"
-                            TextAlignment="Center" />
+                <StackPanel>
+                    <TextBlock Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" />
+                    <ToggleButton Name="VolumeUp">
+                        <TextBlock Text="{Binding KeyboardHotkey.VolumeUp, Converter={StaticResource Key}}" />
                     </ToggleButton>
                 </StackPanel>
-                <StackPanel Margin="10,0,0,0" Orientation="Horizontal">
-                    <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" />
-                    <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
-                        <TextBlock
-                            Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}"
-                            TextAlignment="Center" />
+                <StackPanel>
+                    <TextBlock Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" />
+                    <ToggleButton Name="VolumeDown">
+                        <TextBlock Text="{Binding KeyboardHotkey.VolumeDown, Converter={StaticResource Key}}" />
                     </ToggleButton>
                 </StackPanel>
             </StackPanel>
         </Border>
    </ScrollViewer>
-</UserControl>
\ No newline at end of file
+</UserControl>
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs
index b006d703f..fb0fe2bb1 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs
+++ b/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs
@@ -2,10 +2,13 @@ using Avalonia.Controls;
 using Avalonia.Controls.Primitives;
 using Avalonia.Input;
 using Avalonia.Interactivity;
+using Avalonia.LogicalTree;
 using Ryujinx.Ava.Input;
 using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.ViewModels;
 using Ryujinx.Input;
 using Ryujinx.Input.Assigner;
+using Key = Ryujinx.Common.Configuration.Hid.Key;
 
 namespace Ryujinx.Ava.UI.Views.Settings
 {
@@ -17,9 +20,28 @@ namespace Ryujinx.Ava.UI.Views.Settings
         public SettingsHotkeysView()
         {
             InitializeComponent();
+
+            foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
+            {
+                if (visual is ToggleButton button and not CheckBox)
+                {
+                    button.IsCheckedChanged += Button_IsCheckedChanged;
+                }
+            }
+
             _avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this);
         }
 
+        protected override void OnPointerReleased(PointerReleasedEventArgs e)
+        {
+            base.OnPointerReleased(e);
+
+            if (!_currentAssigner?.ToggledButton?.IsPointerOver ?? false)
+            {
+                _currentAssigner.Cancel();
+            }
+        }
+
         private void MouseClick(object sender, PointerPressedEventArgs e)
         {
             bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
@@ -29,53 +51,94 @@ namespace Ryujinx.Ava.UI.Views.Settings
             PointerPressed -= MouseClick;
         }
 
-        private void Button_Checked(object sender, RoutedEventArgs e)
+        private void Button_IsCheckedChanged(object sender, RoutedEventArgs e)
         {
             if (sender is ToggleButton button)
             {
-                if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
+                if ((bool)button.IsChecked)
                 {
-                    return;
-                }
+                    if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
+                    {
+                        return;
+                    }
 
-                if (_currentAssigner == null && button.IsChecked != null && (bool)button.IsChecked)
-                {
-                    _currentAssigner = new ButtonKeyAssigner(button);
+                    if (_currentAssigner == null)
+                    {
+                        _currentAssigner = new ButtonKeyAssigner(button);
 
-                    this.Focus(NavigationMethod.Pointer);
+                        this.Focus(NavigationMethod.Pointer);
 
-                    PointerPressed += MouseClick;
+                        PointerPressed += MouseClick;
 
-                    var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad(_avaloniaKeyboardDriver.GamepadsIds[0]);
-                    IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
+                        var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad("0");
+                        IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
 
-                    _currentAssigner.GetInputAndAssign(assigner);
+                        _currentAssigner.ButtonAssigned += (sender, e) =>
+                        {
+                            if (e.ButtonValue.HasValue)
+                            {
+                                var viewModel = (DataContext) as SettingsViewModel;
+                                var buttonValue = e.ButtonValue.Value;
+
+                                switch (button.Name)
+                                {
+                                    case "ToggleVsync":
+                                        viewModel.KeyboardHotkey.ToggleVsync = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "Screenshot":
+                                        viewModel.KeyboardHotkey.Screenshot = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ShowUI":
+                                        viewModel.KeyboardHotkey.ShowUI = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "Pause":
+                                        viewModel.KeyboardHotkey.Pause = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ToggleMute":
+                                        viewModel.KeyboardHotkey.ToggleMute = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ResScaleUp":
+                                        viewModel.KeyboardHotkey.ResScaleUp = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "ResScaleDown":
+                                        viewModel.KeyboardHotkey.ResScaleDown = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "VolumeUp":
+                                        viewModel.KeyboardHotkey.VolumeUp = buttonValue.AsHidType<Key>();
+                                        break;
+                                    case "VolumeDown":
+                                        viewModel.KeyboardHotkey.VolumeDown = buttonValue.AsHidType<Key>();
+                                        break;
+                                }
+                            }
+                        };
+
+                        _currentAssigner.GetInputAndAssign(assigner, keyboard);
+                    }
+                    else
+                    {
+                        if (_currentAssigner != null)
+                        {
+                            _currentAssigner.Cancel();
+                            _currentAssigner = null;
+                            button.IsChecked = false;
+                        }
+                    }
                 }
                 else
                 {
-                    if (_currentAssigner != null)
-                    {
-                        ToggleButton oldButton = _currentAssigner.ToggledButton;
-
-                        _currentAssigner.Cancel();
-                        _currentAssigner = null;
-
-                        button.IsChecked = false;
-                    }
+                    _currentAssigner?.Cancel();
+                    _currentAssigner = null;
                 }
             }
         }
 
-        private void Button_Unchecked(object sender, RoutedEventArgs e)
-        {
-            _currentAssigner?.Cancel();
-            _currentAssigner = null;
-        }
-
         public void Dispose()
         {
             _currentAssigner?.Cancel();
             _currentAssigner = null;
+
+            _avaloniaKeyboardDriver.Dispose();
         }
     }
 }
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml
index 81f4b68b7..55c2ed6e3 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml
@@ -27,9 +27,9 @@
                         <RowDefinition Height="*" />
                         <RowDefinition Height="Auto" />
                     </Grid.RowDefinitions>
-                    <views:ControllerInputView
+                    <views:InputView
                         Grid.Row="0"
-                        Name="ControllerSettings" />
+                        Name="InputView" />
                     <StackPanel
                         Orientation="Vertical"
                         Grid.Row="2">
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml.cs
index e75c9f0cc..55b69af06 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml.cs
+++ b/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml.cs
@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
 
         public void Dispose()
         {
-            ControllerSettings.Dispose();
+            InputView.Dispose();
         }
     }
 }
diff --git a/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs b/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs
index d7bb0b883..314501c52 100644
--- a/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs
+++ b/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs
@@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.Windows
 
         public void SaveSettings()
         {
-            InputPage.ControllerSettings?.SaveCurrentProfile();
+            InputPage.InputView?.SaveCurrentProfile();
 
             if (Owner is MainWindow window && ViewModel.DirectoryChanged)
             {