mirror of
				https://github.com/ryujinx-mirror/ryujinx.git
				synced 2025-11-04 08:18:58 -06:00 
			
		
		
		
	Ava UI: Input Menu Refactor (#5826)
* 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>
This commit is contained in:
		@@ -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; }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										158
									
								
								src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								src/Ryujinx.Input/Button.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/Ryujinx.Input/Button.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								src/Ryujinx.Input/ButtonType.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Ryujinx.Input/ButtonType.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
namespace Ryujinx.Input
 | 
			
		||||
{
 | 
			
		||||
    public enum ButtonType
 | 
			
		||||
    {
 | 
			
		||||
        Key,
 | 
			
		||||
        GamepadButtonInputId,
 | 
			
		||||
        StickId,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
</Styles>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,8 @@
 | 
			
		||||
using Avalonia.Controls;
 | 
			
		||||
using Avalonia.Controls.Primitives;
 | 
			
		||||
using Avalonia.LogicalTree;
 | 
			
		||||
using Avalonia.Threading;
 | 
			
		||||
using Ryujinx.Input;
 | 
			
		||||
using Ryujinx.Input.Assigner;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Ava.UI.Helpers
 | 
			
		||||
@@ -15,12 +12,12 @@ namespace Ryujinx.Ava.UI.Helpers
 | 
			
		||||
        internal class ButtonAssignedEventArgs : EventArgs
 | 
			
		||||
        {
 | 
			
		||||
            public ToggleButton Button { get; }
 | 
			
		||||
            public bool IsAssigned { get; }
 | 
			
		||||
            public Button? ButtonValue { get; }
 | 
			
		||||
 | 
			
		||||
            public ButtonAssignedEventArgs(ToggleButton button, bool isAssigned)
 | 
			
		||||
            public ButtonAssignedEventArgs(ToggleButton button, Button? buttonValue)
 | 
			
		||||
            {
 | 
			
		||||
                Button = button;
 | 
			
		||||
                IsAssigned = isAssigned;
 | 
			
		||||
                ButtonValue = buttonValue;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -69,7 +66,7 @@ namespace Ryujinx.Ava.UI.Helpers
 | 
			
		||||
 | 
			
		||||
                    assigner.ReadInput();
 | 
			
		||||
 | 
			
		||||
                    if (assigner.HasAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape)))
 | 
			
		||||
                    if (assigner.IsAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape)))
 | 
			
		||||
                    {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
@@ -78,15 +75,11 @@ namespace Ryujinx.Ava.UI.Helpers
 | 
			
		||||
 | 
			
		||||
            await Dispatcher.UIThread.InvokeAsync(() =>
 | 
			
		||||
            {
 | 
			
		||||
                string pressedButton = assigner.GetPressedButton();
 | 
			
		||||
                Button? pressedButton = assigner.GetPressedButton();
 | 
			
		||||
 | 
			
		||||
                if (_shouldUnbind)
 | 
			
		||||
                {
 | 
			
		||||
                    SetButtonText(ToggledButton, "Unbound");
 | 
			
		||||
                }
 | 
			
		||||
                else if (pressedButton != "")
 | 
			
		||||
                {
 | 
			
		||||
                    SetButtonText(ToggledButton, pressedButton);
 | 
			
		||||
                    pressedButton = null;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                _shouldUnbind = false;
 | 
			
		||||
@@ -94,17 +87,8 @@ namespace Ryujinx.Ava.UI.Helpers
 | 
			
		||||
 | 
			
		||||
                ToggledButton.IsChecked = false;
 | 
			
		||||
 | 
			
		||||
                ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton != null));
 | 
			
		||||
                ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton));
 | 
			
		||||
 | 
			
		||||
                static void SetButtonText(ToggleButton button, string text)
 | 
			
		||||
                {
 | 
			
		||||
                    ILogical textBlock = button.GetLogicalDescendants().First(x => x is TextBlock);
 | 
			
		||||
 | 
			
		||||
                    if (textBlock != null && textBlock is TextBlock block)
 | 
			
		||||
                    {
 | 
			
		||||
                        block.Text = text;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										580
									
								
								src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										580
									
								
								src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										141
									
								
								src/Ryujinx/UI/Models/Input/HotkeyConfig.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/Ryujinx/UI/Models/Input/HotkeyConfig.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										422
									
								
								src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										422
									
								
								src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -8,7 +8,7 @@ using Ryujinx.Ava.Common.Locale;
 | 
			
		||||
using Ryujinx.Ava.Input;
 | 
			
		||||
using Ryujinx.Ava.UI.Helpers;
 | 
			
		||||
using Ryujinx.Ava.UI.Models;
 | 
			
		||||
using Ryujinx.Ava.UI.Views.Input;
 | 
			
		||||
using Ryujinx.Ava.UI.Models.Input;
 | 
			
		||||
using Ryujinx.Ava.UI.Windows;
 | 
			
		||||
using Ryujinx.Common;
 | 
			
		||||
using Ryujinx.Common.Configuration;
 | 
			
		||||
@@ -30,9 +30,9 @@ using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.Gamepad
 | 
			
		||||
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
 | 
			
		||||
using Key = Ryujinx.Common.Configuration.Hid.Key;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
namespace Ryujinx.Ava.UI.ViewModels.Input
 | 
			
		||||
{
 | 
			
		||||
    public class ControllerInputViewModel : BaseModel, IDisposable
 | 
			
		||||
    public class InputViewModel : BaseModel, IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private const string Disabled = "disabled";
 | 
			
		||||
        private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg";
 | 
			
		||||
@@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
        private int _controllerNumber;
 | 
			
		||||
        private string _controllerImage;
 | 
			
		||||
        private int _device;
 | 
			
		||||
        private object _configuration;
 | 
			
		||||
        private object _configViewModel;
 | 
			
		||||
        private string _profileName;
 | 
			
		||||
        private bool _isLoaded;
 | 
			
		||||
 | 
			
		||||
@@ -71,13 +71,14 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
        public bool IsLeft { get; set; }
 | 
			
		||||
 | 
			
		||||
        public bool IsModified { get; set; }
 | 
			
		||||
        public event Action NotifyChangesEvent;
 | 
			
		||||
 | 
			
		||||
        public object Configuration
 | 
			
		||||
        public object ConfigViewModel
 | 
			
		||||
        {
 | 
			
		||||
            get => _configuration;
 | 
			
		||||
            get => _configViewModel;
 | 
			
		||||
            set
 | 
			
		||||
            {
 | 
			
		||||
                _configuration = value;
 | 
			
		||||
                _configViewModel = value;
 | 
			
		||||
 | 
			
		||||
                OnPropertyChanged();
 | 
			
		||||
            }
 | 
			
		||||
@@ -232,7 +233,7 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
 | 
			
		||||
        public InputConfig Config { get; set; }
 | 
			
		||||
 | 
			
		||||
        public ControllerInputViewModel(UserControl owner) : this()
 | 
			
		||||
        public InputViewModel(UserControl owner) : this()
 | 
			
		||||
        {
 | 
			
		||||
            if (Program.PreviewerDetached)
 | 
			
		||||
            {
 | 
			
		||||
@@ -255,7 +256,7 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ControllerInputViewModel()
 | 
			
		||||
        public InputViewModel()
 | 
			
		||||
        {
 | 
			
		||||
            PlayerIndexes = new ObservableCollection<PlayerModel>();
 | 
			
		||||
            Controllers = new ObservableCollection<ControllerModel>();
 | 
			
		||||
@@ -282,12 +283,12 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
 | 
			
		||||
            if (Config is StandardKeyboardInputConfig keyboardInputConfig)
 | 
			
		||||
            {
 | 
			
		||||
                Configuration = new InputConfiguration<Key, ConfigStickInputId>(keyboardInputConfig);
 | 
			
		||||
                ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (Config is StandardControllerInputConfig controllerInputConfig)
 | 
			
		||||
            {
 | 
			
		||||
                Configuration = new InputConfiguration<ConfigGamepadInputId, ConfigStickInputId>(controllerInputConfig);
 | 
			
		||||
                ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -323,16 +324,6 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async void ShowMotionConfig()
 | 
			
		||||
        {
 | 
			
		||||
            await MotionInputView.Show(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async void ShowRumbleConfig()
 | 
			
		||||
        {
 | 
			
		||||
            await RumbleInputView.Show(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void LoadInputDriver()
 | 
			
		||||
        {
 | 
			
		||||
            if (_device < 0)
 | 
			
		||||
@@ -740,7 +731,7 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (Configuration == null)
 | 
			
		||||
            if (ConfigViewModel == null)
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
@@ -751,35 +742,37 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
 | 
			
		||||
 | 
			
		||||
            if (validFileName)
 | 
			
		||||
            {
 | 
			
		||||
                string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
 | 
			
		||||
 | 
			
		||||
                InputConfig config = null;
 | 
			
		||||
 | 
			
		||||
                if (IsKeyboard)
 | 
			
		||||
                {
 | 
			
		||||
                    config = (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig();
 | 
			
		||||
                }
 | 
			
		||||
                else if (IsController)
 | 
			
		||||
                {
 | 
			
		||||
                    config = (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                config.ControllerType = Controllers[_controller].Type;
 | 
			
		||||
 | 
			
		||||
                string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
 | 
			
		||||
 | 
			
		||||
                await File.WriteAllTextAsync(path, jsonString);
 | 
			
		||||
 | 
			
		||||
                LoadProfiles();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
 | 
			
		||||
                bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
 | 
			
		||||
 | 
			
		||||
                if (validFileName)
 | 
			
		||||
                {
 | 
			
		||||
                    string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
 | 
			
		||||
 | 
			
		||||
                    InputConfig config = null;
 | 
			
		||||
 | 
			
		||||
                    if (IsKeyboard)
 | 
			
		||||
                    {
 | 
			
		||||
                        config = (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig();
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (IsController)
 | 
			
		||||
                    {
 | 
			
		||||
                        config = (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    config.ControllerType = Controllers[_controller].Type;
 | 
			
		||||
 | 
			
		||||
                    string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
 | 
			
		||||
 | 
			
		||||
                    await File.WriteAllTextAsync(path, jsonString);
 | 
			
		||||
 | 
			
		||||
                    LoadProfiles();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -830,18 +823,18 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
 | 
			
		||||
                if (device.Type == DeviceType.Keyboard)
 | 
			
		||||
                {
 | 
			
		||||
                    var inputConfig = Configuration as InputConfiguration<Key, ConfigStickInputId>;
 | 
			
		||||
                    var inputConfig = (ConfigViewModel as KeyboardInputViewModel).Config;
 | 
			
		||||
                    inputConfig.Id = device.Id;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    var inputConfig = Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>;
 | 
			
		||||
                    var inputConfig = (ConfigViewModel as ControllerInputViewModel).Config;
 | 
			
		||||
                    inputConfig.Id = device.Id.Split(" ")[0];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var config = !IsController
 | 
			
		||||
                    ? (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig()
 | 
			
		||||
                    : (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig();
 | 
			
		||||
                    ? (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig()
 | 
			
		||||
                    : (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
 | 
			
		||||
                config.ControllerType = Controllers[_controller].Type;
 | 
			
		||||
                config.PlayerIndex = _playerId;
 | 
			
		||||
 | 
			
		||||
@@ -872,12 +865,13 @@ namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
 | 
			
		||||
        public void NotifyChanges()
 | 
			
		||||
        {
 | 
			
		||||
            OnPropertyChanged(nameof(Configuration));
 | 
			
		||||
            OnPropertyChanged(nameof(ConfigViewModel));
 | 
			
		||||
            OnPropertyChanged(nameof(IsController));
 | 
			
		||||
            OnPropertyChanged(nameof(ShowSettings));
 | 
			
		||||
            OnPropertyChanged(nameof(IsKeyboard));
 | 
			
		||||
            OnPropertyChanged(nameof(IsRight));
 | 
			
		||||
            OnPropertyChanged(nameof(IsLeft));
 | 
			
		||||
            NotifyChangesEvent?.Invoke();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
							
								
								
									
										73
									
								
								src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
namespace Ryujinx.Ava.UI.ViewModels.Input
 | 
			
		||||
{
 | 
			
		||||
    public class MotionInputViewModel : BaseModel
 | 
			
		||||
    {
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace Ryujinx.Ava.UI.ViewModels
 | 
			
		||||
namespace Ryujinx.Ava.UI.ViewModels.Input
 | 
			
		||||
{
 | 
			
		||||
    public class RumbleInputViewModel : BaseModel
 | 
			
		||||
    {
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,35 +1,29 @@
 | 
			
		||||
using Avalonia;
 | 
			
		||||
using Avalonia.Controls;
 | 
			
		||||
using Avalonia.Controls.Primitives;
 | 
			
		||||
using Avalonia.Input;
 | 
			
		||||
using Avalonia.Interactivity;
 | 
			
		||||
using Avalonia.LogicalTree;
 | 
			
		||||
using Ryujinx.Ava.Common.Locale;
 | 
			
		||||
using Ryujinx.Ava.UI.Helpers;
 | 
			
		||||
using Ryujinx.Ava.UI.Models;
 | 
			
		||||
using Ryujinx.Ava.UI.ViewModels;
 | 
			
		||||
using Ryujinx.Ava.UI.ViewModels.Input;
 | 
			
		||||
using Ryujinx.Common.Configuration.Hid.Controller;
 | 
			
		||||
using Ryujinx.Input;
 | 
			
		||||
using Ryujinx.Input.Assigner;
 | 
			
		||||
using System;
 | 
			
		||||
using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Ava.UI.Views.Input
 | 
			
		||||
{
 | 
			
		||||
    public partial class ControllerInputView : UserControl
 | 
			
		||||
    {
 | 
			
		||||
        private bool _dialogOpen;
 | 
			
		||||
 | 
			
		||||
        private ButtonKeyAssigner _currentAssigner;
 | 
			
		||||
        internal ControllerInputViewModel ViewModel { get; set; }
 | 
			
		||||
 | 
			
		||||
        public ControllerInputView()
 | 
			
		||||
        {
 | 
			
		||||
            DataContext = ViewModel = new ControllerInputViewModel(this);
 | 
			
		||||
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
 | 
			
		||||
            foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
 | 
			
		||||
            {
 | 
			
		||||
                if (visual is ToggleButton button && visual is not CheckBox)
 | 
			
		||||
                if (visual is ToggleButton button and not CheckBox)
 | 
			
		||||
                {
 | 
			
		||||
                    button.IsCheckedChanged += Button_IsCheckedChanged;
 | 
			
		||||
                }
 | 
			
		||||
@@ -67,14 +61,87 @@ namespace Ryujinx.Ava.UI.Views.Input
 | 
			
		||||
 | 
			
		||||
                        PointerPressed += MouseClick;
 | 
			
		||||
 | 
			
		||||
                        IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
 | 
			
		||||
                        var viewModel = (DataContext as ControllerInputViewModel);
 | 
			
		||||
 | 
			
		||||
                        IKeyboard keyboard = (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
 | 
			
		||||
                        IButtonAssigner assigner = CreateButtonAssigner(isStick);
 | 
			
		||||
 | 
			
		||||
                        _currentAssigner.ButtonAssigned += (sender, e) =>
 | 
			
		||||
                        {
 | 
			
		||||
                            if (e.IsAssigned)
 | 
			
		||||
                            if (e.ButtonValue.HasValue)
 | 
			
		||||
                            {
 | 
			
		||||
                                ViewModel.IsModified = true;
 | 
			
		||||
                                var buttonValue = e.ButtonValue.Value;
 | 
			
		||||
                                viewModel.ParentModel.IsModified = true;
 | 
			
		||||
 | 
			
		||||
                                switch (button.Name)
 | 
			
		||||
                                {
 | 
			
		||||
                                    case "ButtonZl":
 | 
			
		||||
                                        viewModel.Config.ButtonZl = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ButtonL":
 | 
			
		||||
                                        viewModel.Config.ButtonL = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ButtonMinus":
 | 
			
		||||
                                        viewModel.Config.ButtonMinus = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "LeftStickButton":
 | 
			
		||||
                                        viewModel.Config.LeftStickButton = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "LeftJoystick":
 | 
			
		||||
                                        viewModel.Config.LeftJoystick = buttonValue.AsHidType<StickInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "DpadUp":
 | 
			
		||||
                                        viewModel.Config.DpadUp = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "DpadDown":
 | 
			
		||||
                                        viewModel.Config.DpadDown = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "DpadLeft":
 | 
			
		||||
                                        viewModel.Config.DpadLeft = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "DpadRight":
 | 
			
		||||
                                        viewModel.Config.DpadRight = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "LeftButtonSr":
 | 
			
		||||
                                        viewModel.Config.LeftButtonSr = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "LeftButtonSl":
 | 
			
		||||
                                        viewModel.Config.LeftButtonSl = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "RightButtonSr":
 | 
			
		||||
                                        viewModel.Config.RightButtonSr = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "RightButtonSl":
 | 
			
		||||
                                        viewModel.Config.RightButtonSl = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ButtonZr":
 | 
			
		||||
                                        viewModel.Config.ButtonZr = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ButtonR":
 | 
			
		||||
                                        viewModel.Config.ButtonR = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ButtonPlus":
 | 
			
		||||
                                        viewModel.Config.ButtonPlus = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ButtonA":
 | 
			
		||||
                                        viewModel.Config.ButtonA = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ButtonB":
 | 
			
		||||
                                        viewModel.Config.ButtonB = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ButtonX":
 | 
			
		||||
                                        viewModel.Config.ButtonX = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ButtonY":
 | 
			
		||||
                                        viewModel.Config.ButtonY = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "RightStickButton":
 | 
			
		||||
                                        viewModel.Config.RightStickButton = buttonValue.AsHidType<GamepadInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "RightJoystick":
 | 
			
		||||
                                        viewModel.Config.RightJoystick = buttonValue.AsHidType<StickInputId>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
@@ -84,8 +151,6 @@ namespace Ryujinx.Ava.UI.Views.Input
 | 
			
		||||
                    {
 | 
			
		||||
                        if (_currentAssigner != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            ToggleButton oldButton = _currentAssigner.ToggledButton;
 | 
			
		||||
 | 
			
		||||
                            _currentAssigner.Cancel();
 | 
			
		||||
                            _currentAssigner = null;
 | 
			
		||||
                            button.IsChecked = false;
 | 
			
		||||
@@ -100,82 +165,34 @@ namespace Ryujinx.Ava.UI.Views.Input
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SaveCurrentProfile()
 | 
			
		||||
        {
 | 
			
		||||
            ViewModel.Save();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private IButtonAssigner CreateButtonAssigner(bool forStick)
 | 
			
		||||
        {
 | 
			
		||||
            IButtonAssigner assigner;
 | 
			
		||||
 | 
			
		||||
            var device = ViewModel.Devices[ViewModel.Device];
 | 
			
		||||
 | 
			
		||||
            if (device.Type == DeviceType.Keyboard)
 | 
			
		||||
            {
 | 
			
		||||
                assigner = new KeyboardKeyAssigner((IKeyboard)ViewModel.SelectedGamepad);
 | 
			
		||||
            }
 | 
			
		||||
            else if (device.Type == DeviceType.Controller)
 | 
			
		||||
            {
 | 
			
		||||
                assigner = new GamepadButtonAssigner(ViewModel.SelectedGamepad, (ViewModel.Config as StandardControllerInputConfig).TriggerThreshold, forStick);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                throw new Exception("Controller not supported");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return assigner;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void MouseClick(object sender, PointerPressedEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            bool shouldUnbind = false;
 | 
			
		||||
 | 
			
		||||
            if (e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed)
 | 
			
		||||
            {
 | 
			
		||||
                shouldUnbind = true;
 | 
			
		||||
            }
 | 
			
		||||
            bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
 | 
			
		||||
 | 
			
		||||
            _currentAssigner?.Cancel(shouldUnbind);
 | 
			
		||||
 | 
			
		||||
            PointerPressed -= MouseClick;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void PlayerIndexBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
 | 
			
		||||
        private IButtonAssigner CreateButtonAssigner(bool forStick)
 | 
			
		||||
        {
 | 
			
		||||
            if (ViewModel.IsModified && !_dialogOpen)
 | 
			
		||||
            {
 | 
			
		||||
                _dialogOpen = true;
 | 
			
		||||
            IButtonAssigner assigner;
 | 
			
		||||
 | 
			
		||||
                var result = await ContentDialogHelper.CreateConfirmationDialog(
 | 
			
		||||
                    LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage],
 | 
			
		||||
                    LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage],
 | 
			
		||||
                    LocaleManager.Instance[LocaleKeys.InputDialogYes],
 | 
			
		||||
                    LocaleManager.Instance[LocaleKeys.InputDialogNo],
 | 
			
		||||
                    LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
 | 
			
		||||
            var controllerInputViewModel = DataContext as ControllerInputViewModel;
 | 
			
		||||
 | 
			
		||||
                if (result == UserResult.Yes)
 | 
			
		||||
                {
 | 
			
		||||
                    ViewModel.Save();
 | 
			
		||||
                }
 | 
			
		||||
            assigner = new GamepadButtonAssigner(
 | 
			
		||||
                controllerInputViewModel.ParentModel.SelectedGamepad,
 | 
			
		||||
                (controllerInputViewModel.ParentModel.Config as StandardControllerInputConfig).TriggerThreshold,
 | 
			
		||||
                forStick);
 | 
			
		||||
 | 
			
		||||
                _dialogOpen = false;
 | 
			
		||||
 | 
			
		||||
                ViewModel.IsModified = false;
 | 
			
		||||
 | 
			
		||||
                if (e.AddedItems.Count > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    var player = (PlayerModel)e.AddedItems[0];
 | 
			
		||||
                    ViewModel.PlayerId = player.Id;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return assigner;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            base.OnDetachedFromVisualTree(e);
 | 
			
		||||
            _currentAssigner?.Cancel();
 | 
			
		||||
            _currentAssigner = null;
 | 
			
		||||
            ViewModel.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										225
									
								
								src/Ryujinx/UI/Views/Input/InputView.axaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								src/Ryujinx/UI/Views/Input/InputView.axaml
									
									
									
									
									
										Normal file
									
								
							@@ -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>
 | 
			
		||||
							
								
								
									
										61
									
								
								src/Ryujinx/UI/Views/Input/InputView.axaml.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/Ryujinx/UI/Views/Input/InputView.axaml.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										675
									
								
								src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										675
									
								
								src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml
									
									
									
									
									
										Normal file
									
								
							@@ -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>
 | 
			
		||||
							
								
								
									
										208
									
								
								src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
            };
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
</UserControl>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,13 @@ using Avalonia.Controls;
 | 
			
		||||
using Avalonia.Controls.Primitives;
 | 
			
		||||
using Avalonia.Input;
 | 
			
		||||
using Avalonia.Interactivity;
 | 
			
		||||
using Avalonia.LogicalTree;
 | 
			
		||||
using Ryujinx.Ava.Input;
 | 
			
		||||
using Ryujinx.Ava.UI.Helpers;
 | 
			
		||||
using Ryujinx.Ava.UI.ViewModels;
 | 
			
		||||
using Ryujinx.Input;
 | 
			
		||||
using Ryujinx.Input.Assigner;
 | 
			
		||||
using Key = Ryujinx.Common.Configuration.Hid.Key;
 | 
			
		||||
 | 
			
		||||
namespace Ryujinx.Ava.UI.Views.Settings
 | 
			
		||||
{
 | 
			
		||||
@@ -17,9 +20,28 @@ namespace Ryujinx.Ava.UI.Views.Settings
 | 
			
		||||
        public SettingsHotkeysView()
 | 
			
		||||
        {
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
 | 
			
		||||
            foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
 | 
			
		||||
            {
 | 
			
		||||
                if (visual is ToggleButton button and not CheckBox)
 | 
			
		||||
                {
 | 
			
		||||
                    button.IsCheckedChanged += Button_IsCheckedChanged;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void OnPointerReleased(PointerReleasedEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            base.OnPointerReleased(e);
 | 
			
		||||
 | 
			
		||||
            if (!_currentAssigner?.ToggledButton?.IsPointerOver ?? false)
 | 
			
		||||
            {
 | 
			
		||||
                _currentAssigner.Cancel();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void MouseClick(object sender, PointerPressedEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
 | 
			
		||||
@@ -29,53 +51,94 @@ namespace Ryujinx.Ava.UI.Views.Settings
 | 
			
		||||
            PointerPressed -= MouseClick;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void Button_Checked(object sender, RoutedEventArgs e)
 | 
			
		||||
        private void Button_IsCheckedChanged(object sender, RoutedEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            if (sender is ToggleButton button)
 | 
			
		||||
            {
 | 
			
		||||
                if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
 | 
			
		||||
                if ((bool)button.IsChecked)
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                    if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
 | 
			
		||||
                    {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                if (_currentAssigner == null && button.IsChecked != null && (bool)button.IsChecked)
 | 
			
		||||
                {
 | 
			
		||||
                    _currentAssigner = new ButtonKeyAssigner(button);
 | 
			
		||||
                    if (_currentAssigner == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        _currentAssigner = new ButtonKeyAssigner(button);
 | 
			
		||||
 | 
			
		||||
                    this.Focus(NavigationMethod.Pointer);
 | 
			
		||||
                        this.Focus(NavigationMethod.Pointer);
 | 
			
		||||
 | 
			
		||||
                    PointerPressed += MouseClick;
 | 
			
		||||
                        PointerPressed += MouseClick;
 | 
			
		||||
 | 
			
		||||
                    var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad(_avaloniaKeyboardDriver.GamepadsIds[0]);
 | 
			
		||||
                    IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
 | 
			
		||||
                        var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad("0");
 | 
			
		||||
                        IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
 | 
			
		||||
 | 
			
		||||
                    _currentAssigner.GetInputAndAssign(assigner);
 | 
			
		||||
                        _currentAssigner.ButtonAssigned += (sender, e) =>
 | 
			
		||||
                        {
 | 
			
		||||
                            if (e.ButtonValue.HasValue)
 | 
			
		||||
                            {
 | 
			
		||||
                                var viewModel = (DataContext) as SettingsViewModel;
 | 
			
		||||
                                var buttonValue = e.ButtonValue.Value;
 | 
			
		||||
 | 
			
		||||
                                switch (button.Name)
 | 
			
		||||
                                {
 | 
			
		||||
                                    case "ToggleVsync":
 | 
			
		||||
                                        viewModel.KeyboardHotkey.ToggleVsync = buttonValue.AsHidType<Key>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "Screenshot":
 | 
			
		||||
                                        viewModel.KeyboardHotkey.Screenshot = buttonValue.AsHidType<Key>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ShowUI":
 | 
			
		||||
                                        viewModel.KeyboardHotkey.ShowUI = buttonValue.AsHidType<Key>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "Pause":
 | 
			
		||||
                                        viewModel.KeyboardHotkey.Pause = buttonValue.AsHidType<Key>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ToggleMute":
 | 
			
		||||
                                        viewModel.KeyboardHotkey.ToggleMute = buttonValue.AsHidType<Key>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ResScaleUp":
 | 
			
		||||
                                        viewModel.KeyboardHotkey.ResScaleUp = buttonValue.AsHidType<Key>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "ResScaleDown":
 | 
			
		||||
                                        viewModel.KeyboardHotkey.ResScaleDown = buttonValue.AsHidType<Key>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "VolumeUp":
 | 
			
		||||
                                        viewModel.KeyboardHotkey.VolumeUp = buttonValue.AsHidType<Key>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case "VolumeDown":
 | 
			
		||||
                                        viewModel.KeyboardHotkey.VolumeDown = buttonValue.AsHidType<Key>();
 | 
			
		||||
                                        break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
                        _currentAssigner.GetInputAndAssign(assigner, keyboard);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        if (_currentAssigner != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            _currentAssigner.Cancel();
 | 
			
		||||
                            _currentAssigner = null;
 | 
			
		||||
                            button.IsChecked = false;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    if (_currentAssigner != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        ToggleButton oldButton = _currentAssigner.ToggledButton;
 | 
			
		||||
 | 
			
		||||
                        _currentAssigner.Cancel();
 | 
			
		||||
                        _currentAssigner = null;
 | 
			
		||||
 | 
			
		||||
                        button.IsChecked = false;
 | 
			
		||||
                    }
 | 
			
		||||
                    _currentAssigner?.Cancel();
 | 
			
		||||
                    _currentAssigner = null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void Button_Unchecked(object sender, RoutedEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            _currentAssigner?.Cancel();
 | 
			
		||||
            _currentAssigner = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _currentAssigner?.Cancel();
 | 
			
		||||
            _currentAssigner = null;
 | 
			
		||||
 | 
			
		||||
            _avaloniaKeyboardDriver.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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">
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            ControllerSettings.Dispose();
 | 
			
		||||
            InputView.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user