aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIsaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com>2024-04-17 22:52:12 +0100
committerGitHub <noreply@github.com>2024-04-17 18:52:12 -0300
commit446f2854a5af18aef7151f95d64e0fe66a3498b8 (patch)
tree2d92deeffc089cdad97ed49d13b0e858ddabd404 /src
parent8884d1fd732c9ba788f0ab711e6a9f507d934ac8 (diff)
Ava UI: Input Menu Refactor (#5826)1.1.1282
* Refactor * Apply suggestions from code review Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Update src/Ryujinx.Input/ButtonValueType.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Add empty line * Requested renames * Update src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs Co-authored-by: gdkchan <gab.dark.100@gmail.com> * Make parent models private readonly * Fix ControllerInputView * Make line shorter * Mac keys in locale * Double line break * Fix build * Get rid of _isValid * Fix potential race condition * Rename HasAnyButtonPressed to IsAnyButtonPressed * Use switches * Simplify enumeration --------- Co-authored-by: Ac_K <Acoustik666@gmail.com> Co-authored-by: gdkchan <gab.dark.100@gmail.com> Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs2
-rw-r--r--src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs158
-rw-r--r--src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs6
-rw-r--r--src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs15
-rw-r--r--src/Ryujinx.Input/Assigner/IButtonAssigner.cs4
-rw-r--r--src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs12
-rw-r--r--src/Ryujinx.Input/Button.cs33
-rw-r--r--src/Ryujinx.Input/ButtonType.cs9
-rw-r--r--src/Ryujinx.Input/HLE/NpadController.cs24
-rw-r--r--src/Ryujinx/Assets/Locales/en_US.json101
-rw-r--r--src/Ryujinx/Assets/Styles/Styles.xaml5
-rw-r--r--src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs30
-rw-r--r--src/Ryujinx/UI/Helpers/KeyValueConverter.cs182
-rw-r--r--src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs580
-rw-r--r--src/Ryujinx/UI/Models/Input/HotkeyConfig.cs141
-rw-r--r--src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs422
-rw-r--r--src/Ryujinx/UI/Models/InputConfiguration.cs456
-rw-r--r--src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs84
-rw-r--r--src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs (renamed from src/Ryujinx/UI/ViewModels/ControllerInputViewModel.cs)92
-rw-r--r--src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs73
-rw-r--r--src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs (renamed from src/Ryujinx/UI/ViewModels/MotionInputViewModel.cs)2
-rw-r--r--src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs (renamed from src/Ryujinx/UI/ViewModels/RumbleInputViewModel.cs)2
-rw-r--r--src/Ryujinx/UI/ViewModels/SettingsViewModel.cs18
-rw-r--r--src/Ryujinx/UI/Views/Input/ControllerInputView.axaml617
-rw-r--r--src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs165
-rw-r--r--src/Ryujinx/UI/Views/Input/InputView.axaml225
-rw-r--r--src/Ryujinx/UI/Views/Input/InputView.axaml.cs61
-rw-r--r--src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml675
-rw-r--r--src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs208
-rw-r--r--src/Ryujinx/UI/Views/Input/MotionInputView.axaml2
-rw-r--r--src/Ryujinx/UI/Views/Input/MotionInputView.axaml.cs8
-rw-r--r--src/Ryujinx/UI/Views/Input/RumbleInputView.axaml2
-rw-r--r--src/Ryujinx/UI/Views/Input/RumbleInputView.axaml.cs8
-rw-r--r--src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml120
-rw-r--r--src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs117
-rw-r--r--src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml4
-rw-r--r--src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml.cs2
-rw-r--r--src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs2
38 files changed, 3397 insertions, 1270 deletions
diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs
index e9c163cf..0cb49ca8 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 00000000..5a8ca96a
--- /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 6712657f..d0b8266f 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 388ebcc0..80fed2b8 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 76a9fece..688fbddb 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 e52ef4a2..3c011a63 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 00000000..4289901c
--- /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 00000000..25ef5eea
--- /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 8411c10a..cde20f5d 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 ef40fd5b..77ad7d1f 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 f7f64be2..b3a6f59c 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 7e8ba734..4f2b8daa 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));
-
- static void SetButtonText(ToggleButton button, string text)
- {
- ILogical textBlock = button.GetLogicalDescendants().First(x => x is TextBlock);
+ ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton));
- 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 028ed6bf..cbcf16ab 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 00000000..833670bd
--- /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 00000000..b5f53508
--- /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 00000000..66f1f62a
--- /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 f1352c6d..00000000
--- 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 00000000..6ee79a37
--- /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
index 71ad2c12..74da4597 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)
+ else
{
- string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
+ bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
- InputConfig config = null;
-
- if (IsKeyboard)
+ if (validFileName)
{
- config = (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig();
- }
- else if (IsController)
- {
- config = (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig();
- }
+ string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
- config.ControllerType = Controllers[_controller].Type;
+ InputConfig config = null;
- string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
+ if (IsKeyboard)
+ {
+ config = (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig();
+ }
+ else if (IsController)
+ {
+ config = (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
+ }
- await File.WriteAllTextAsync(path, jsonString);
+ config.ControllerType = Controllers[_controller].Type;
- LoadProfiles();
- }
- else
- {
- await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
+ 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 00000000..0b530eb0
--- /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
index 0b12a51f..c9ed8f2d 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
index 49de1993..8ad33cf4 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 fde8f74a..6074a5fd 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 99f2b6b6..08bdf90f 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 35129706..b76648da 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;
-
- 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();
- }
+ IButtonAssigner assigner;
- _dialogOpen = false;
+ var controllerInputViewModel = DataContext as ControllerInputViewModel;
- ViewModel.IsModified = false;
+ assigner = new GamepadButtonAssigner(
+ controllerInputViewModel.ParentModel.SelectedGamepad,
+ (controllerInputViewModel.ParentModel.Config as StandardControllerInputConfig).TriggerThreshold,
+ forStick);
- 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 00000000..b4940941
--- /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 00000000..356381a8
--- /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 00000000..e4566f46
--- /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 00000000..f17c7496
--- /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 a6b587f6..0d018e29 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 1b340752..2304364b 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 5b7087a4..1beb1f06 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 9307f872..58a4b416 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 b4eae01e..bffcada0 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 b006d703..fb0fe2bb 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);
- }
- else
- {
- if (_currentAssigner != null)
- {
- ToggleButton oldButton = _currentAssigner.ToggledButton;
+ _currentAssigner.ButtonAssigned += (sender, e) =>
+ {
+ if (e.ButtonValue.HasValue)
+ {
+ var viewModel = (DataContext) as SettingsViewModel;
+ var buttonValue = e.ButtonValue.Value;
- _currentAssigner.Cancel();
- _currentAssigner = null;
+ 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;
+ }
+ }
+ };
- button.IsChecked = false;
+ _currentAssigner.GetInputAndAssign(assigner, keyboard);
+ }
+ else
+ {
+ if (_currentAssigner != null)
+ {
+ _currentAssigner.Cancel();
+ _currentAssigner = null;
+ button.IsChecked = false;
+ }
}
}
+ else
+ {
+ _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 81f4b68b..55c2ed6e 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 e75c9f0c..55b69af0 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 d7bb0b88..314501c5 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)
{