mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-01-10 12:49:13 +00:00
Slow and steady
This commit is contained in:
parent
d3f0c085d3
commit
139a4b1fe7
11 changed files with 2125 additions and 1886 deletions
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,325 +1,64 @@
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Collections;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
|
||||||
using Avalonia.Svg.Skia;
|
using Avalonia.Svg.Skia;
|
||||||
using Avalonia.Threading;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
|
||||||
using Ryujinx.Ava.Input;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
|
||||||
using Ryujinx.Ava.UI.Models;
|
using Ryujinx.Ava.UI.Models;
|
||||||
using Ryujinx.Ava.UI.Views.Input;
|
using Ryujinx.Ava.UI.Views.Input;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Common.Configuration;
|
|
||||||
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 Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.Input;
|
|
||||||
using Ryujinx.UI.Common.Configuration;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json;
|
|
||||||
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
|
||||||
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
|
||||||
{
|
{
|
||||||
public class ControllerInputViewModel : BaseModel, IDisposable
|
public class ControllerInputViewModel : BaseModel
|
||||||
{
|
{
|
||||||
private const string Disabled = "disabled";
|
private ControllerInputConfig _config;
|
||||||
private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg";
|
private bool _isLeft;
|
||||||
private const string JoyConPairResource = "Ryujinx.UI.Common/Resources/Controller_JoyConPair.svg";
|
private bool _isRight;
|
||||||
private const string JoyConLeftResource = "Ryujinx.UI.Common/Resources/Controller_JoyConLeft.svg";
|
private bool _showSettings;
|
||||||
private const string JoyConRightResource = "Ryujinx.UI.Common/Resources/Controller_JoyConRight.svg";
|
private SvgImage _image;
|
||||||
private const string KeyboardString = "keyboard";
|
|
||||||
private const string ControllerString = "controller";
|
|
||||||
private readonly MainWindow _mainWindow;
|
|
||||||
|
|
||||||
private PlayerIndex _playerId;
|
public ControllerInputConfig Config
|
||||||
private int _controller;
|
|
||||||
private int _controllerNumber;
|
|
||||||
private string _controllerImage;
|
|
||||||
private int _device;
|
|
||||||
private object _configuration;
|
|
||||||
private string _profileName;
|
|
||||||
private bool _isLoaded;
|
|
||||||
|
|
||||||
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
public IGamepadDriver AvaloniaKeyboardDriver { get; }
|
|
||||||
public IGamepad SelectedGamepad { get; private set; }
|
|
||||||
|
|
||||||
public ObservableCollection<PlayerModel> PlayerIndexes { get; set; }
|
|
||||||
public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; }
|
|
||||||
internal ObservableCollection<ControllerModel> Controllers { get; set; }
|
|
||||||
public AvaloniaList<string> ProfilesList { get; set; }
|
|
||||||
public AvaloniaList<string> DeviceList { get; set; }
|
|
||||||
|
|
||||||
// XAML Flags
|
|
||||||
public bool ShowSettings => _device > 0;
|
|
||||||
public bool IsController => _device > 1;
|
|
||||||
public bool IsKeyboard => !IsController;
|
|
||||||
public bool IsRight { get; set; }
|
|
||||||
public bool IsLeft { get; set; }
|
|
||||||
|
|
||||||
public bool IsModified { get; set; }
|
|
||||||
|
|
||||||
public object Configuration
|
|
||||||
{
|
{
|
||||||
get => _configuration;
|
get => _config;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_configuration = value;
|
_config = value;
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerIndex PlayerId
|
public bool IsLeft
|
||||||
{
|
{
|
||||||
get => _playerId;
|
get => _isLeft;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (IsModified)
|
_isLeft = value;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsModified = false;
|
|
||||||
_playerId = value;
|
|
||||||
|
|
||||||
if (!Enum.IsDefined(typeof(PlayerIndex), _playerId))
|
|
||||||
{
|
|
||||||
_playerId = PlayerIndex.Player1;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadConfiguration();
|
|
||||||
LoadDevice();
|
|
||||||
LoadProfiles();
|
|
||||||
|
|
||||||
_isLoaded = true;
|
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Controller
|
public bool IsRight
|
||||||
{
|
{
|
||||||
get => _controller;
|
get => _isRight;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_controller = value;
|
_isRight = value;
|
||||||
|
|
||||||
if (_controller == -1)
|
|
||||||
{
|
|
||||||
_controller = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Controllers.Count > 0 && value < Controllers.Count && _controller > -1)
|
|
||||||
{
|
|
||||||
ControllerType controller = Controllers[_controller].Type;
|
|
||||||
|
|
||||||
IsLeft = true;
|
|
||||||
IsRight = true;
|
|
||||||
|
|
||||||
switch (controller)
|
|
||||||
{
|
|
||||||
case ControllerType.Handheld:
|
|
||||||
ControllerImage = JoyConPairResource;
|
|
||||||
break;
|
|
||||||
case ControllerType.ProController:
|
|
||||||
ControllerImage = ProControllerResource;
|
|
||||||
break;
|
|
||||||
case ControllerType.JoyconPair:
|
|
||||||
ControllerImage = JoyConPairResource;
|
|
||||||
break;
|
|
||||||
case ControllerType.JoyconLeft:
|
|
||||||
ControllerImage = JoyConLeftResource;
|
|
||||||
IsRight = false;
|
|
||||||
break;
|
|
||||||
case ControllerType.JoyconRight:
|
|
||||||
ControllerImage = JoyConRightResource;
|
|
||||||
IsLeft = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadInputDriver();
|
|
||||||
LoadProfiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
NotifyChanges();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ControllerImage
|
public bool ShowSettings
|
||||||
{
|
{
|
||||||
get => _controllerImage;
|
get => _showSettings;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_controllerImage = value;
|
_showSettings = value;
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
OnPropertyChanged(nameof(Image));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SvgImage Image
|
public SvgImage Image
|
||||||
{
|
{
|
||||||
get
|
get => _image;
|
||||||
{
|
|
||||||
SvgImage image = new();
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(_controllerImage))
|
|
||||||
{
|
|
||||||
SvgSource source = new(default(Uri));
|
|
||||||
|
|
||||||
source.Load(EmbeddedResources.GetStream(_controllerImage));
|
|
||||||
|
|
||||||
image.Source = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ProfileName
|
|
||||||
{
|
|
||||||
get => _profileName; set
|
|
||||||
{
|
|
||||||
_profileName = value;
|
|
||||||
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Device
|
|
||||||
{
|
|
||||||
get => _device;
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_device = value < 0 ? 0 : value;
|
_image = value;
|
||||||
|
|
||||||
if (_device >= Devices.Count)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var selected = Devices[_device].Type;
|
|
||||||
|
|
||||||
if (selected != DeviceType.None)
|
|
||||||
{
|
|
||||||
LoadControllers();
|
|
||||||
|
|
||||||
if (_isLoaded)
|
|
||||||
{
|
|
||||||
LoadConfiguration(LoadDefaultConfiguration());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
NotifyChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputConfig Config { get; set; }
|
|
||||||
|
|
||||||
public ControllerInputViewModel(UserControl owner) : this()
|
|
||||||
{
|
|
||||||
if (Program.PreviewerDetached)
|
|
||||||
{
|
|
||||||
_mainWindow =
|
|
||||||
(MainWindow)((IClassicDesktopStyleApplicationLifetime)Application.Current
|
|
||||||
.ApplicationLifetime).MainWindow;
|
|
||||||
|
|
||||||
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner);
|
|
||||||
|
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
|
||||||
|
|
||||||
_mainWindow.ViewModel.AppHost?.NpadManager.BlockInputUpdates();
|
|
||||||
|
|
||||||
_isLoaded = false;
|
|
||||||
|
|
||||||
LoadDevices();
|
|
||||||
|
|
||||||
PlayerId = PlayerIndex.Player1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ControllerInputViewModel()
|
|
||||||
{
|
|
||||||
PlayerIndexes = new ObservableCollection<PlayerModel>();
|
|
||||||
Controllers = new ObservableCollection<ControllerModel>();
|
|
||||||
Devices = new ObservableCollection<(DeviceType Type, string Id, string Name)>();
|
|
||||||
ProfilesList = new AvaloniaList<string>();
|
|
||||||
DeviceList = new AvaloniaList<string>();
|
|
||||||
|
|
||||||
ControllerImage = ProControllerResource;
|
|
||||||
|
|
||||||
PlayerIndexes.Add(new(PlayerIndex.Player1, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer1]));
|
|
||||||
PlayerIndexes.Add(new(PlayerIndex.Player2, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer2]));
|
|
||||||
PlayerIndexes.Add(new(PlayerIndex.Player3, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer3]));
|
|
||||||
PlayerIndexes.Add(new(PlayerIndex.Player4, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer4]));
|
|
||||||
PlayerIndexes.Add(new(PlayerIndex.Player5, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer5]));
|
|
||||||
PlayerIndexes.Add(new(PlayerIndex.Player6, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer6]));
|
|
||||||
PlayerIndexes.Add(new(PlayerIndex.Player7, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer7]));
|
|
||||||
PlayerIndexes.Add(new(PlayerIndex.Player8, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer8]));
|
|
||||||
PlayerIndexes.Add(new(PlayerIndex.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsHandheld]));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadConfiguration(InputConfig inputConfig = null)
|
|
||||||
{
|
|
||||||
Config = inputConfig ?? ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == _playerId);
|
|
||||||
|
|
||||||
if (Config is StandardKeyboardInputConfig keyboardInputConfig)
|
|
||||||
{
|
|
||||||
Configuration = new InputConfiguration<Key, ConfigStickInputId>(keyboardInputConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config is StandardControllerInputConfig controllerInputConfig)
|
|
||||||
{
|
|
||||||
Configuration = new InputConfiguration<ConfigGamepadInputId, ConfigStickInputId>(controllerInputConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadDevice()
|
|
||||||
{
|
|
||||||
if (Config == null || Config.Backend == InputBackendType.Invalid)
|
|
||||||
{
|
|
||||||
Device = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var type = DeviceType.None;
|
|
||||||
|
|
||||||
if (Config is StandardKeyboardInputConfig)
|
|
||||||
{
|
|
||||||
type = DeviceType.Keyboard;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config is StandardControllerInputConfig)
|
|
||||||
{
|
|
||||||
type = DeviceType.Controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
var item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id);
|
|
||||||
if (item != default)
|
|
||||||
{
|
|
||||||
Device = Devices.ToList().FindIndex(x => x.Id == item.Id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Device = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,566 +71,5 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
await RumbleInputView.Show(this);
|
await RumbleInputView.Show(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadInputDriver()
|
|
||||||
{
|
|
||||||
if (_device < 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string id = GetCurrentGamepadId();
|
|
||||||
var type = Devices[Device].Type;
|
|
||||||
|
|
||||||
if (type == DeviceType.None)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == DeviceType.Keyboard)
|
|
||||||
{
|
|
||||||
if (_mainWindow.InputManager.KeyboardDriver is AvaloniaKeyboardDriver)
|
|
||||||
{
|
|
||||||
// NOTE: To get input in this window, we need to bind a custom keyboard driver instead of using the InputManager one as the main window isn't focused...
|
|
||||||
SelectedGamepad = AvaloniaKeyboardDriver.GetGamepad(id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectedGamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectedGamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleOnGamepadDisconnected(string id)
|
|
||||||
{
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
|
||||||
{
|
|
||||||
LoadDevices();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleOnGamepadConnected(string id)
|
|
||||||
{
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
|
||||||
{
|
|
||||||
LoadDevices();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetCurrentGamepadId()
|
|
||||||
{
|
|
||||||
if (_device < 0)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
var device = Devices[Device];
|
|
||||||
|
|
||||||
if (device.Type == DeviceType.None)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return device.Id.Split(" ")[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadControllers()
|
|
||||||
{
|
|
||||||
Controllers.Clear();
|
|
||||||
|
|
||||||
if (_playerId == PlayerIndex.Handheld)
|
|
||||||
{
|
|
||||||
Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeHandheld]));
|
|
||||||
|
|
||||||
Controller = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Controllers.Add(new(ControllerType.ProController, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeProController]));
|
|
||||||
Controllers.Add(new(ControllerType.JoyconPair, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConPair]));
|
|
||||||
Controllers.Add(new(ControllerType.JoyconLeft, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConLeft]));
|
|
||||||
Controllers.Add(new(ControllerType.JoyconRight, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConRight]));
|
|
||||||
|
|
||||||
if (Config != null && Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType) != -1)
|
|
||||||
{
|
|
||||||
Controller = Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Controller = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetShortGamepadName(string str)
|
|
||||||
{
|
|
||||||
const string Ellipsis = "...";
|
|
||||||
const int MaxSize = 50;
|
|
||||||
|
|
||||||
if (str.Length > MaxSize)
|
|
||||||
{
|
|
||||||
return $"{str.AsSpan(0, MaxSize - Ellipsis.Length)}{Ellipsis}";
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetShortGamepadId(string str)
|
|
||||||
{
|
|
||||||
const string Hyphen = "-";
|
|
||||||
const int Offset = 1;
|
|
||||||
|
|
||||||
return str[(str.IndexOf(Hyphen) + Offset)..];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadDevices()
|
|
||||||
{
|
|
||||||
lock (Devices)
|
|
||||||
{
|
|
||||||
Devices.Clear();
|
|
||||||
DeviceList.Clear();
|
|
||||||
Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled]));
|
|
||||||
|
|
||||||
foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds)
|
|
||||||
{
|
|
||||||
using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
|
|
||||||
|
|
||||||
if (gamepad != null)
|
|
||||||
{
|
|
||||||
Devices.Add((DeviceType.Keyboard, id, $"{GetShortGamepadName(gamepad.Name)}"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string id in _mainWindow.InputManager.GamepadDriver.GamepadsIds)
|
|
||||||
{
|
|
||||||
using IGamepad gamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id);
|
|
||||||
|
|
||||||
if (gamepad != null)
|
|
||||||
{
|
|
||||||
if (Devices.Any(controller => GetShortGamepadId(controller.Id) == GetShortGamepadId(gamepad.Id)))
|
|
||||||
{
|
|
||||||
_controllerNumber++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Devices.Add((DeviceType.Controller, id, $"{GetShortGamepadName(gamepad.Name)} ({_controllerNumber})"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_controllerNumber = 0;
|
|
||||||
|
|
||||||
DeviceList.AddRange(Devices.Select(x => x.Name));
|
|
||||||
Device = Math.Min(Device, DeviceList.Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetProfileBasePath()
|
|
||||||
{
|
|
||||||
string path = AppDataManager.ProfilesDirPath;
|
|
||||||
var type = Devices[Device == -1 ? 0 : Device].Type;
|
|
||||||
|
|
||||||
if (type == DeviceType.Keyboard)
|
|
||||||
{
|
|
||||||
path = Path.Combine(path, KeyboardString);
|
|
||||||
}
|
|
||||||
else if (type == DeviceType.Controller)
|
|
||||||
{
|
|
||||||
path = Path.Combine(path, ControllerString);
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadProfiles()
|
|
||||||
{
|
|
||||||
ProfilesList.Clear();
|
|
||||||
|
|
||||||
string basePath = GetProfileBasePath();
|
|
||||||
|
|
||||||
if (!Directory.Exists(basePath))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(basePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfilesList.Add((LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]));
|
|
||||||
|
|
||||||
foreach (string profile in Directory.GetFiles(basePath, "*.json", SearchOption.AllDirectories))
|
|
||||||
{
|
|
||||||
ProfilesList.Add(Path.GetFileNameWithoutExtension(profile));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(ProfileName))
|
|
||||||
{
|
|
||||||
ProfileName = LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputConfig LoadDefaultConfiguration()
|
|
||||||
{
|
|
||||||
var activeDevice = Devices.FirstOrDefault();
|
|
||||||
|
|
||||||
if (Devices.Count > 0 && Device < Devices.Count && Device >= 0)
|
|
||||||
{
|
|
||||||
activeDevice = Devices[Device];
|
|
||||||
}
|
|
||||||
|
|
||||||
InputConfig config;
|
|
||||||
if (activeDevice.Type == DeviceType.Keyboard)
|
|
||||||
{
|
|
||||||
string id = activeDevice.Id;
|
|
||||||
|
|
||||||
config = new StandardKeyboardInputConfig
|
|
||||||
{
|
|
||||||
Version = InputConfig.CurrentVersion,
|
|
||||||
Backend = InputBackendType.WindowKeyboard,
|
|
||||||
Id = id,
|
|
||||||
ControllerType = ControllerType.ProController,
|
|
||||||
LeftJoycon = new LeftJoyconCommonConfig<Key>
|
|
||||||
{
|
|
||||||
DpadUp = Key.Up,
|
|
||||||
DpadDown = Key.Down,
|
|
||||||
DpadLeft = Key.Left,
|
|
||||||
DpadRight = Key.Right,
|
|
||||||
ButtonMinus = Key.Minus,
|
|
||||||
ButtonL = Key.E,
|
|
||||||
ButtonZl = Key.Q,
|
|
||||||
ButtonSl = Key.Unbound,
|
|
||||||
ButtonSr = Key.Unbound,
|
|
||||||
},
|
|
||||||
LeftJoyconStick =
|
|
||||||
new JoyconConfigKeyboardStick<Key>
|
|
||||||
{
|
|
||||||
StickUp = Key.W,
|
|
||||||
StickDown = Key.S,
|
|
||||||
StickLeft = Key.A,
|
|
||||||
StickRight = Key.D,
|
|
||||||
StickButton = Key.F,
|
|
||||||
},
|
|
||||||
RightJoycon = new RightJoyconCommonConfig<Key>
|
|
||||||
{
|
|
||||||
ButtonA = Key.Z,
|
|
||||||
ButtonB = Key.X,
|
|
||||||
ButtonX = Key.C,
|
|
||||||
ButtonY = Key.V,
|
|
||||||
ButtonPlus = Key.Plus,
|
|
||||||
ButtonR = Key.U,
|
|
||||||
ButtonZr = Key.O,
|
|
||||||
ButtonSl = Key.Unbound,
|
|
||||||
ButtonSr = Key.Unbound,
|
|
||||||
},
|
|
||||||
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
|
||||||
{
|
|
||||||
StickUp = Key.I,
|
|
||||||
StickDown = Key.K,
|
|
||||||
StickLeft = Key.J,
|
|
||||||
StickRight = Key.L,
|
|
||||||
StickButton = Key.H,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (activeDevice.Type == DeviceType.Controller)
|
|
||||||
{
|
|
||||||
bool isNintendoStyle = Devices.ToList().Find(x => x.Id == activeDevice.Id).Name.Contains("Nintendo");
|
|
||||||
|
|
||||||
string id = activeDevice.Id.Split(" ")[0];
|
|
||||||
|
|
||||||
config = new StandardControllerInputConfig
|
|
||||||
{
|
|
||||||
Version = InputConfig.CurrentVersion,
|
|
||||||
Backend = InputBackendType.GamepadSDL2,
|
|
||||||
Id = id,
|
|
||||||
ControllerType = ControllerType.ProController,
|
|
||||||
DeadzoneLeft = 0.1f,
|
|
||||||
DeadzoneRight = 0.1f,
|
|
||||||
RangeLeft = 1.0f,
|
|
||||||
RangeRight = 1.0f,
|
|
||||||
TriggerThreshold = 0.5f,
|
|
||||||
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
|
|
||||||
{
|
|
||||||
DpadUp = ConfigGamepadInputId.DpadUp,
|
|
||||||
DpadDown = ConfigGamepadInputId.DpadDown,
|
|
||||||
DpadLeft = ConfigGamepadInputId.DpadLeft,
|
|
||||||
DpadRight = ConfigGamepadInputId.DpadRight,
|
|
||||||
ButtonMinus = ConfigGamepadInputId.Minus,
|
|
||||||
ButtonL = ConfigGamepadInputId.LeftShoulder,
|
|
||||||
ButtonZl = ConfigGamepadInputId.LeftTrigger,
|
|
||||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
|
||||||
ButtonSr = ConfigGamepadInputId.Unbound,
|
|
||||||
},
|
|
||||||
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
|
||||||
{
|
|
||||||
Joystick = ConfigStickInputId.Left,
|
|
||||||
StickButton = ConfigGamepadInputId.LeftStick,
|
|
||||||
InvertStickX = false,
|
|
||||||
InvertStickY = false,
|
|
||||||
},
|
|
||||||
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
|
||||||
{
|
|
||||||
ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
|
|
||||||
ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
|
|
||||||
ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
|
|
||||||
ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
|
|
||||||
ButtonPlus = ConfigGamepadInputId.Plus,
|
|
||||||
ButtonR = ConfigGamepadInputId.RightShoulder,
|
|
||||||
ButtonZr = ConfigGamepadInputId.RightTrigger,
|
|
||||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
|
||||||
ButtonSr = ConfigGamepadInputId.Unbound,
|
|
||||||
},
|
|
||||||
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
|
||||||
{
|
|
||||||
Joystick = ConfigStickInputId.Right,
|
|
||||||
StickButton = ConfigGamepadInputId.RightStick,
|
|
||||||
InvertStickX = false,
|
|
||||||
InvertStickY = false,
|
|
||||||
},
|
|
||||||
Motion = new StandardMotionConfigController
|
|
||||||
{
|
|
||||||
MotionBackend = MotionInputBackendType.GamepadDriver,
|
|
||||||
EnableMotion = true,
|
|
||||||
Sensitivity = 100,
|
|
||||||
GyroDeadzone = 1,
|
|
||||||
},
|
|
||||||
Rumble = new RumbleConfigController
|
|
||||||
{
|
|
||||||
StrongRumble = 1f,
|
|
||||||
WeakRumble = 1f,
|
|
||||||
EnableRumble = false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
config = new InputConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
config.PlayerIndex = _playerId;
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void LoadProfile()
|
|
||||||
{
|
|
||||||
if (Device == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
InputConfig config = null;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(ProfileName))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])
|
|
||||||
{
|
|
||||||
config = LoadDefaultConfiguration();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
|
|
||||||
|
|
||||||
if (!File.Exists(path))
|
|
||||||
{
|
|
||||||
var index = ProfilesList.IndexOf(ProfileName);
|
|
||||||
if (index != -1)
|
|
||||||
{
|
|
||||||
ProfilesList.RemoveAt(index);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
|
|
||||||
}
|
|
||||||
catch (JsonException) { }
|
|
||||||
catch (InvalidOperationException)
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Configuration, $"Profile {ProfileName} is incompatible with the current input configuration system.");
|
|
||||||
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogProfileInvalidProfileErrorMessage, ProfileName));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config != null)
|
|
||||||
{
|
|
||||||
_isLoaded = false;
|
|
||||||
|
|
||||||
LoadConfiguration(config);
|
|
||||||
|
|
||||||
LoadDevice();
|
|
||||||
|
|
||||||
_isLoaded = true;
|
|
||||||
|
|
||||||
NotifyChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void SaveProfile()
|
|
||||||
{
|
|
||||||
if (Device == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Configuration == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])
|
|
||||||
{
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileDefaultProfileOverwriteErrorMessage]);
|
|
||||||
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void RemoveProfile()
|
|
||||||
{
|
|
||||||
if (Device == 0 || ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault] || ProfilesList.IndexOf(ProfileName) == -1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
|
||||||
LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileTitle],
|
|
||||||
LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileMessage],
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
|
||||||
|
|
||||||
if (result == UserResult.Yes)
|
|
||||||
{
|
|
||||||
string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
|
|
||||||
|
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
|
||||||
File.Delete(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadProfiles();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save()
|
|
||||||
{
|
|
||||||
IsModified = false;
|
|
||||||
|
|
||||||
List<InputConfig> newConfig = new();
|
|
||||||
|
|
||||||
newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value);
|
|
||||||
|
|
||||||
newConfig.Remove(newConfig.Find(x => x == null));
|
|
||||||
|
|
||||||
if (Device == 0)
|
|
||||||
{
|
|
||||||
newConfig.Remove(newConfig.Find(x => x.PlayerIndex == this.PlayerId));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var device = Devices[Device];
|
|
||||||
|
|
||||||
if (device.Type == DeviceType.Keyboard)
|
|
||||||
{
|
|
||||||
var inputConfig = Configuration as InputConfiguration<Key, ConfigStickInputId>;
|
|
||||||
inputConfig.Id = device.Id;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var inputConfig = Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>;
|
|
||||||
inputConfig.Id = device.Id.Split(" ")[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
var config = !IsController
|
|
||||||
? (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig()
|
|
||||||
: (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig();
|
|
||||||
config.ControllerType = Controllers[_controller].Type;
|
|
||||||
config.PlayerIndex = _playerId;
|
|
||||||
|
|
||||||
int i = newConfig.FindIndex(x => x.PlayerIndex == PlayerId);
|
|
||||||
if (i == -1)
|
|
||||||
{
|
|
||||||
newConfig.Add(config);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newConfig[i] = config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_mainWindow.ViewModel.AppHost?.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
|
||||||
|
|
||||||
// Atomically replace and signal input change.
|
|
||||||
// NOTE: Do not modify InputConfig.Value directly as other code depends on the on-change event.
|
|
||||||
ConfigurationState.Instance.Hid.InputConfig.Value = newConfig;
|
|
||||||
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void NotifyChange(string property)
|
|
||||||
{
|
|
||||||
OnPropertyChanged(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void NotifyChanges()
|
|
||||||
{
|
|
||||||
OnPropertyChanged(nameof(Configuration));
|
|
||||||
OnPropertyChanged(nameof(IsController));
|
|
||||||
OnPropertyChanged(nameof(ShowSettings));
|
|
||||||
OnPropertyChanged(nameof(IsKeyboard));
|
|
||||||
OnPropertyChanged(nameof(IsRight));
|
|
||||||
OnPropertyChanged(nameof(IsLeft));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
|
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected;
|
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected;
|
|
||||||
|
|
||||||
_mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates();
|
|
||||||
|
|
||||||
SelectedGamepad?.Dispose();
|
|
||||||
|
|
||||||
AvaloniaKeyboardDriver.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
890
src/Ryujinx.Ava/UI/ViewModels/InputViewModel.cs
Normal file
890
src/Ryujinx.Ava/UI/ViewModels/InputViewModel.cs
Normal file
|
@ -0,0 +1,890 @@
|
||||||
|
using Avalonia.Collections;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Svg.Skia;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
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.Windows;
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Configuration;
|
||||||
|
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 Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Utilities;
|
||||||
|
using Ryujinx.Input;
|
||||||
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
||||||
|
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
||||||
|
using Key = Ryujinx.Common.Configuration.Hid.Key;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
{
|
||||||
|
public class InputViewModel : BaseModel, IDisposable
|
||||||
|
{
|
||||||
|
private const string Disabled = "disabled";
|
||||||
|
private const string ProControllerResource = "Ryujinx.Ui.Common/Resources/Controller_ProCon.svg";
|
||||||
|
private const string JoyConPairResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConPair.svg";
|
||||||
|
private const string JoyConLeftResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConLeft.svg";
|
||||||
|
private const string JoyConRightResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConRight.svg";
|
||||||
|
private const string KeyboardString = "keyboard";
|
||||||
|
private const string ControllerString = "controller";
|
||||||
|
private readonly MainWindow _mainWindow;
|
||||||
|
|
||||||
|
private PlayerIndex _playerId;
|
||||||
|
private int _controller;
|
||||||
|
private int _controllerNumber = 0;
|
||||||
|
private string _controllerImage;
|
||||||
|
private int _device;
|
||||||
|
private object _configuration;
|
||||||
|
private string _profileName;
|
||||||
|
private bool _isLoaded;
|
||||||
|
private readonly UserControl _owner;
|
||||||
|
|
||||||
|
private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
|
public IGamepadDriver AvaloniaKeyboardDriver { get; }
|
||||||
|
public IGamepad SelectedGamepad { get; private set; }
|
||||||
|
|
||||||
|
public ObservableCollection<PlayerModel> PlayerIndexes { get; set; }
|
||||||
|
public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; }
|
||||||
|
internal ObservableCollection<ControllerModel> Controllers { get; set; }
|
||||||
|
public AvaloniaList<string> ProfilesList { get; set; }
|
||||||
|
public AvaloniaList<string> DeviceList { get; set; }
|
||||||
|
|
||||||
|
// XAML Flags
|
||||||
|
public bool ShowSettings => _device > 0;
|
||||||
|
public bool IsController => _device > 1;
|
||||||
|
public bool IsKeyboard => !IsController;
|
||||||
|
public bool IsRight { get; set; }
|
||||||
|
public bool IsLeft { get; set; }
|
||||||
|
|
||||||
|
public bool IsModified { get; set; }
|
||||||
|
|
||||||
|
public object Configuration
|
||||||
|
{
|
||||||
|
get => _configuration;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_configuration = value;
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerIndex PlayerId
|
||||||
|
{
|
||||||
|
get => _playerId;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (IsModified)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsModified = false;
|
||||||
|
_playerId = value;
|
||||||
|
|
||||||
|
if (!Enum.IsDefined(typeof(PlayerIndex), _playerId))
|
||||||
|
{
|
||||||
|
_playerId = PlayerIndex.Player1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadConfiguration();
|
||||||
|
LoadDevice();
|
||||||
|
LoadProfiles();
|
||||||
|
|
||||||
|
_isLoaded = true;
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Controller
|
||||||
|
{
|
||||||
|
get => _controller;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_controller = value;
|
||||||
|
|
||||||
|
if (_controller == -1)
|
||||||
|
{
|
||||||
|
_controller = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Controllers.Count > 0 && value < Controllers.Count && _controller > -1)
|
||||||
|
{
|
||||||
|
ControllerType controller = Controllers[_controller].Type;
|
||||||
|
|
||||||
|
IsLeft = true;
|
||||||
|
IsRight = true;
|
||||||
|
|
||||||
|
switch (controller)
|
||||||
|
{
|
||||||
|
case ControllerType.Handheld:
|
||||||
|
ControllerImage = JoyConPairResource;
|
||||||
|
break;
|
||||||
|
case ControllerType.ProController:
|
||||||
|
ControllerImage = ProControllerResource;
|
||||||
|
break;
|
||||||
|
case ControllerType.JoyconPair:
|
||||||
|
ControllerImage = JoyConPairResource;
|
||||||
|
break;
|
||||||
|
case ControllerType.JoyconLeft:
|
||||||
|
ControllerImage = JoyConLeftResource;
|
||||||
|
IsRight = false;
|
||||||
|
break;
|
||||||
|
case ControllerType.JoyconRight:
|
||||||
|
ControllerImage = JoyConRightResource;
|
||||||
|
IsLeft = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadInputDriver();
|
||||||
|
LoadProfiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
|
NotifyChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ControllerImage
|
||||||
|
{
|
||||||
|
get => _controllerImage;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_controllerImage = value;
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
|
OnPropertyChanged(nameof(Image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SvgImage Image
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
SvgImage image = new SvgImage();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(_controllerImage))
|
||||||
|
{
|
||||||
|
SvgSource source = new SvgSource();
|
||||||
|
|
||||||
|
source.Load(EmbeddedResources.GetStream(_controllerImage));
|
||||||
|
|
||||||
|
image.Source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ProfileName
|
||||||
|
{
|
||||||
|
get => _profileName; set
|
||||||
|
{
|
||||||
|
_profileName = value;
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Device
|
||||||
|
{
|
||||||
|
get => _device;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_device = value < 0 ? 0 : value;
|
||||||
|
|
||||||
|
if (_device >= Devices.Count)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected = Devices[_device].Type;
|
||||||
|
|
||||||
|
if (selected != DeviceType.None)
|
||||||
|
{
|
||||||
|
LoadControllers();
|
||||||
|
|
||||||
|
if (_isLoaded)
|
||||||
|
{
|
||||||
|
LoadConfiguration(LoadDefaultConfiguration());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
|
NotifyChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputConfig Config { get; set; }
|
||||||
|
|
||||||
|
public InputViewModel(UserControl owner) : this()
|
||||||
|
{
|
||||||
|
_owner = owner;
|
||||||
|
|
||||||
|
if (Program.PreviewerDetached)
|
||||||
|
{
|
||||||
|
_mainWindow =
|
||||||
|
(MainWindow)((IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current
|
||||||
|
.ApplicationLifetime).MainWindow;
|
||||||
|
|
||||||
|
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner);
|
||||||
|
|
||||||
|
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
||||||
|
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
||||||
|
if (_mainWindow.ViewModel.AppHost != null)
|
||||||
|
{
|
||||||
|
_mainWindow.ViewModel.AppHost.NpadManager.BlockInputUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoaded = false;
|
||||||
|
|
||||||
|
LoadDevices();
|
||||||
|
|
||||||
|
PlayerId = PlayerIndex.Player1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputViewModel()
|
||||||
|
{
|
||||||
|
PlayerIndexes = new ObservableCollection<PlayerModel>();
|
||||||
|
Controllers = new ObservableCollection<ControllerModel>();
|
||||||
|
Devices = new ObservableCollection<(DeviceType Type, string Id, string Name)>();
|
||||||
|
ProfilesList = new AvaloniaList<string>();
|
||||||
|
DeviceList = new AvaloniaList<string>();
|
||||||
|
|
||||||
|
ControllerImage = ProControllerResource;
|
||||||
|
|
||||||
|
PlayerIndexes.Add(new(PlayerIndex.Player1, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer1]));
|
||||||
|
PlayerIndexes.Add(new(PlayerIndex.Player2, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer2]));
|
||||||
|
PlayerIndexes.Add(new(PlayerIndex.Player3, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer3]));
|
||||||
|
PlayerIndexes.Add(new(PlayerIndex.Player4, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer4]));
|
||||||
|
PlayerIndexes.Add(new(PlayerIndex.Player5, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer5]));
|
||||||
|
PlayerIndexes.Add(new(PlayerIndex.Player6, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer6]));
|
||||||
|
PlayerIndexes.Add(new(PlayerIndex.Player7, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer7]));
|
||||||
|
PlayerIndexes.Add(new(PlayerIndex.Player8, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer8]));
|
||||||
|
PlayerIndexes.Add(new(PlayerIndex.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsHandheld]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadConfiguration(InputConfig inputConfig = null)
|
||||||
|
{
|
||||||
|
Config = inputConfig ?? ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == _playerId);
|
||||||
|
|
||||||
|
if (Config is StandardKeyboardInputConfig keyboardInputConfig)
|
||||||
|
{
|
||||||
|
Configuration = new KeyboardInputConfig(keyboardInputConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config is StandardControllerInputConfig controllerInputConfig)
|
||||||
|
{
|
||||||
|
Configuration = new ControllerInputConfig(controllerInputConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadDevice()
|
||||||
|
{
|
||||||
|
if (Config == null || Config.Backend == InputBackendType.Invalid)
|
||||||
|
{
|
||||||
|
Device = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var type = DeviceType.None;
|
||||||
|
|
||||||
|
if (Config is StandardKeyboardInputConfig)
|
||||||
|
{
|
||||||
|
type = DeviceType.Keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config is StandardControllerInputConfig)
|
||||||
|
{
|
||||||
|
type = DeviceType.Controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id);
|
||||||
|
if (item != default)
|
||||||
|
{
|
||||||
|
Device = Devices.ToList().FindIndex(x => x.Id == item.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Device = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadInputDriver()
|
||||||
|
{
|
||||||
|
if (_device < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string id = GetCurrentGamepadId();
|
||||||
|
var type = Devices[Device].Type;
|
||||||
|
|
||||||
|
if (type == DeviceType.None)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (type == DeviceType.Keyboard)
|
||||||
|
{
|
||||||
|
if (_mainWindow.InputManager.KeyboardDriver is AvaloniaKeyboardDriver)
|
||||||
|
{
|
||||||
|
// NOTE: To get input in this window, we need to bind a custom keyboard driver instead of using the InputManager one as the main window isn't focused...
|
||||||
|
SelectedGamepad = AvaloniaKeyboardDriver.GetGamepad(id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedGamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedGamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleOnGamepadDisconnected(string id)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
LoadDevices();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleOnGamepadConnected(string id)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
LoadDevices();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCurrentGamepadId()
|
||||||
|
{
|
||||||
|
if (_device < 0)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var device = Devices[Device];
|
||||||
|
|
||||||
|
if (device.Type == DeviceType.None)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return device.Id.Split(" ")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadControllers()
|
||||||
|
{
|
||||||
|
Controllers.Clear();
|
||||||
|
|
||||||
|
if (_playerId == PlayerIndex.Handheld)
|
||||||
|
{
|
||||||
|
Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeHandheld]));
|
||||||
|
|
||||||
|
Controller = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Controllers.Add(new(ControllerType.ProController, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeProController]));
|
||||||
|
Controllers.Add(new(ControllerType.JoyconPair, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConPair]));
|
||||||
|
Controllers.Add(new(ControllerType.JoyconLeft, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConLeft]));
|
||||||
|
Controllers.Add(new(ControllerType.JoyconRight, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConRight]));
|
||||||
|
|
||||||
|
if (Config != null && Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType) != -1)
|
||||||
|
{
|
||||||
|
Controller = Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Controller = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetShortGamepadName(string str)
|
||||||
|
{
|
||||||
|
const string Ellipsis = "...";
|
||||||
|
const int MaxSize = 50;
|
||||||
|
|
||||||
|
if (str.Length > MaxSize)
|
||||||
|
{
|
||||||
|
return $"{str.AsSpan(0, MaxSize - Ellipsis.Length)}{Ellipsis}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetShortGamepadId(string str)
|
||||||
|
{
|
||||||
|
const string Hyphen = "-";
|
||||||
|
const int Offset = 1;
|
||||||
|
|
||||||
|
return str.Substring(str.IndexOf(Hyphen) + Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadDevices()
|
||||||
|
{
|
||||||
|
lock (Devices)
|
||||||
|
{
|
||||||
|
Devices.Clear();
|
||||||
|
DeviceList.Clear();
|
||||||
|
Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled]));
|
||||||
|
|
||||||
|
foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds)
|
||||||
|
{
|
||||||
|
using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
|
||||||
|
|
||||||
|
if (gamepad != null)
|
||||||
|
{
|
||||||
|
Devices.Add((DeviceType.Keyboard, id, $"{GetShortGamepadName(gamepad.Name)}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string id in _mainWindow.InputManager.GamepadDriver.GamepadsIds)
|
||||||
|
{
|
||||||
|
using IGamepad gamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id);
|
||||||
|
|
||||||
|
if (gamepad != null)
|
||||||
|
{
|
||||||
|
if (Devices.Any(controller => GetShortGamepadId(controller.Id) == GetShortGamepadId(gamepad.Id)))
|
||||||
|
{
|
||||||
|
_controllerNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Devices.Add((DeviceType.Controller, id, $"{GetShortGamepadName(gamepad.Name)} ({_controllerNumber})"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_controllerNumber = 0;
|
||||||
|
|
||||||
|
DeviceList.AddRange(Devices.Select(x => x.Name));
|
||||||
|
Device = Math.Min(Device, DeviceList.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetProfileBasePath()
|
||||||
|
{
|
||||||
|
string path = AppDataManager.ProfilesDirPath;
|
||||||
|
var type = Devices[Device == -1 ? 0 : Device].Type;
|
||||||
|
|
||||||
|
if (type == DeviceType.Keyboard)
|
||||||
|
{
|
||||||
|
path = Path.Combine(path, KeyboardString);
|
||||||
|
}
|
||||||
|
else if (type == DeviceType.Controller)
|
||||||
|
{
|
||||||
|
path = Path.Combine(path, ControllerString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadProfiles()
|
||||||
|
{
|
||||||
|
ProfilesList.Clear();
|
||||||
|
|
||||||
|
string basePath = GetProfileBasePath();
|
||||||
|
|
||||||
|
if (!Directory.Exists(basePath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(basePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfilesList.Add((LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]));
|
||||||
|
|
||||||
|
foreach (string profile in Directory.GetFiles(basePath, "*.json", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
ProfilesList.Add(Path.GetFileNameWithoutExtension(profile));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(ProfileName))
|
||||||
|
{
|
||||||
|
ProfileName = LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputConfig LoadDefaultConfiguration()
|
||||||
|
{
|
||||||
|
var activeDevice = Devices.FirstOrDefault();
|
||||||
|
|
||||||
|
if (Devices.Count > 0 && Device < Devices.Count && Device >= 0)
|
||||||
|
{
|
||||||
|
activeDevice = Devices[Device];
|
||||||
|
}
|
||||||
|
|
||||||
|
InputConfig config;
|
||||||
|
if (activeDevice.Type == DeviceType.Keyboard)
|
||||||
|
{
|
||||||
|
string id = activeDevice.Id;
|
||||||
|
|
||||||
|
config = new StandardKeyboardInputConfig
|
||||||
|
{
|
||||||
|
Version = InputConfig.CurrentVersion,
|
||||||
|
Backend = InputBackendType.WindowKeyboard,
|
||||||
|
Id = id,
|
||||||
|
ControllerType = ControllerType.ProController,
|
||||||
|
LeftJoycon = new LeftJoyconCommonConfig<Key>
|
||||||
|
{
|
||||||
|
DpadUp = Key.Up,
|
||||||
|
DpadDown = Key.Down,
|
||||||
|
DpadLeft = Key.Left,
|
||||||
|
DpadRight = Key.Right,
|
||||||
|
ButtonMinus = Key.Minus,
|
||||||
|
ButtonL = Key.E,
|
||||||
|
ButtonZl = Key.Q,
|
||||||
|
ButtonSl = Key.Unbound,
|
||||||
|
ButtonSr = Key.Unbound
|
||||||
|
},
|
||||||
|
LeftJoyconStick =
|
||||||
|
new JoyconConfigKeyboardStick<Key>
|
||||||
|
{
|
||||||
|
StickUp = Key.W,
|
||||||
|
StickDown = Key.S,
|
||||||
|
StickLeft = Key.A,
|
||||||
|
StickRight = Key.D,
|
||||||
|
StickButton = Key.F
|
||||||
|
},
|
||||||
|
RightJoycon = new RightJoyconCommonConfig<Key>
|
||||||
|
{
|
||||||
|
ButtonA = Key.Z,
|
||||||
|
ButtonB = Key.X,
|
||||||
|
ButtonX = Key.C,
|
||||||
|
ButtonY = Key.V,
|
||||||
|
ButtonPlus = Key.Plus,
|
||||||
|
ButtonR = Key.U,
|
||||||
|
ButtonZr = Key.O,
|
||||||
|
ButtonSl = Key.Unbound,
|
||||||
|
ButtonSr = Key.Unbound
|
||||||
|
},
|
||||||
|
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||||
|
{
|
||||||
|
StickUp = Key.I,
|
||||||
|
StickDown = Key.K,
|
||||||
|
StickLeft = Key.J,
|
||||||
|
StickRight = Key.L,
|
||||||
|
StickButton = Key.H
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (activeDevice.Type == DeviceType.Controller)
|
||||||
|
{
|
||||||
|
bool isNintendoStyle = Devices.ToList().Find(x => x.Id == activeDevice.Id).Name.Contains("Nintendo");
|
||||||
|
|
||||||
|
string id = activeDevice.Id.Split(" ")[0];
|
||||||
|
|
||||||
|
config = new StandardControllerInputConfig
|
||||||
|
{
|
||||||
|
Version = InputConfig.CurrentVersion,
|
||||||
|
Backend = InputBackendType.GamepadSDL2,
|
||||||
|
Id = id,
|
||||||
|
ControllerType = ControllerType.ProController,
|
||||||
|
DeadzoneLeft = 0.1f,
|
||||||
|
DeadzoneRight = 0.1f,
|
||||||
|
RangeLeft = 1.0f,
|
||||||
|
RangeRight = 1.0f,
|
||||||
|
TriggerThreshold = 0.5f,
|
||||||
|
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
|
||||||
|
{
|
||||||
|
DpadUp = ConfigGamepadInputId.DpadUp,
|
||||||
|
DpadDown = ConfigGamepadInputId.DpadDown,
|
||||||
|
DpadLeft = ConfigGamepadInputId.DpadLeft,
|
||||||
|
DpadRight = ConfigGamepadInputId.DpadRight,
|
||||||
|
ButtonMinus = ConfigGamepadInputId.Minus,
|
||||||
|
ButtonL = ConfigGamepadInputId.LeftShoulder,
|
||||||
|
ButtonZl = ConfigGamepadInputId.LeftTrigger,
|
||||||
|
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||||
|
ButtonSr = ConfigGamepadInputId.Unbound
|
||||||
|
},
|
||||||
|
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||||
|
{
|
||||||
|
Joystick = ConfigStickInputId.Left,
|
||||||
|
StickButton = ConfigGamepadInputId.LeftStick,
|
||||||
|
InvertStickX = false,
|
||||||
|
InvertStickY = false
|
||||||
|
},
|
||||||
|
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
||||||
|
{
|
||||||
|
ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
|
||||||
|
ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
|
||||||
|
ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
|
||||||
|
ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
|
||||||
|
ButtonPlus = ConfigGamepadInputId.Plus,
|
||||||
|
ButtonR = ConfigGamepadInputId.RightShoulder,
|
||||||
|
ButtonZr = ConfigGamepadInputId.RightTrigger,
|
||||||
|
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||||
|
ButtonSr = ConfigGamepadInputId.Unbound
|
||||||
|
},
|
||||||
|
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||||
|
{
|
||||||
|
Joystick = ConfigStickInputId.Right,
|
||||||
|
StickButton = ConfigGamepadInputId.RightStick,
|
||||||
|
InvertStickX = false,
|
||||||
|
InvertStickY = false
|
||||||
|
},
|
||||||
|
Motion = new StandardMotionConfigController
|
||||||
|
{
|
||||||
|
MotionBackend = MotionInputBackendType.GamepadDriver,
|
||||||
|
EnableMotion = true,
|
||||||
|
Sensitivity = 100,
|
||||||
|
GyroDeadzone = 1
|
||||||
|
},
|
||||||
|
Rumble = new RumbleConfigController
|
||||||
|
{
|
||||||
|
StrongRumble = 1f,
|
||||||
|
WeakRumble = 1f,
|
||||||
|
EnableRumble = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
config = new InputConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
config.PlayerIndex = _playerId;
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void LoadProfile()
|
||||||
|
{
|
||||||
|
if (Device == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputConfig config = null;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(ProfileName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])
|
||||||
|
{
|
||||||
|
config = LoadDefaultConfiguration();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
|
||||||
|
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
var index = ProfilesList.IndexOf(ProfileName);
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
ProfilesList.RemoveAt(index);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
config = JsonHelper.DeserializeFromFile(path, SerializerContext.InputConfig);
|
||||||
|
}
|
||||||
|
catch (JsonException) { }
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Configuration, $"Profile {ProfileName} is incompatible with the current input configuration system.");
|
||||||
|
|
||||||
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogProfileInvalidProfileErrorMessage, ProfileName));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config != null)
|
||||||
|
{
|
||||||
|
_isLoaded = false;
|
||||||
|
|
||||||
|
LoadConfiguration(config);
|
||||||
|
|
||||||
|
LoadDevice();
|
||||||
|
|
||||||
|
_isLoaded = true;
|
||||||
|
|
||||||
|
NotifyChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void SaveProfile()
|
||||||
|
{
|
||||||
|
if (Device == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Configuration == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])
|
||||||
|
{
|
||||||
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileDefaultProfileOverwriteErrorMessage]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
|
||||||
|
|
||||||
|
if (validFileName)
|
||||||
|
{
|
||||||
|
string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
|
||||||
|
|
||||||
|
InputConfig config = null;
|
||||||
|
|
||||||
|
if (IsKeyboard)
|
||||||
|
{
|
||||||
|
config = (Configuration as KeyboardInputConfig).GetConfig();
|
||||||
|
}
|
||||||
|
else if (IsController)
|
||||||
|
{
|
||||||
|
config = (Configuration as ControllerInputConfig).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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void RemoveProfile()
|
||||||
|
{
|
||||||
|
if (Device == 0 || ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault] || ProfilesList.IndexOf(ProfileName) == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||||
|
LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileTitle],
|
||||||
|
LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileMessage],
|
||||||
|
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||||
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||||
|
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||||
|
|
||||||
|
if (result == UserResult.Yes)
|
||||||
|
{
|
||||||
|
string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json");
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
File.Delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadProfiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
IsModified = false;
|
||||||
|
|
||||||
|
List<InputConfig> newConfig = new();
|
||||||
|
|
||||||
|
newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value);
|
||||||
|
|
||||||
|
newConfig.Remove(newConfig.Find(x => x == null));
|
||||||
|
|
||||||
|
if (Device == 0)
|
||||||
|
{
|
||||||
|
newConfig.Remove(newConfig.Find(x => x.PlayerIndex == this.PlayerId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var device = Devices[Device];
|
||||||
|
|
||||||
|
if (device.Type == DeviceType.Keyboard)
|
||||||
|
{
|
||||||
|
var inputConfig = Configuration as KeyboardInputConfig;
|
||||||
|
inputConfig.Id = device.Id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var inputConfig = Configuration as ControllerInputConfig;
|
||||||
|
inputConfig.Id = device.Id.Split(" ")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = !IsController
|
||||||
|
? (Configuration as KeyboardInputConfig).GetConfig()
|
||||||
|
: (Configuration as ControllerInputConfig).GetConfig();
|
||||||
|
config.ControllerType = Controllers[_controller].Type;
|
||||||
|
config.PlayerIndex = _playerId;
|
||||||
|
|
||||||
|
int i = newConfig.FindIndex(x => x.PlayerIndex == PlayerId);
|
||||||
|
if (i == -1)
|
||||||
|
{
|
||||||
|
newConfig.Add(config);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newConfig[i] = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_mainWindow.ViewModel.AppHost?.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse);
|
||||||
|
|
||||||
|
// Atomically replace and signal input change.
|
||||||
|
// NOTE: Do not modify InputConfig.Value directly as other code depends on the on-change event.
|
||||||
|
ConfigurationState.Instance.Hid.InputConfig.Value = newConfig;
|
||||||
|
|
||||||
|
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifyChange(string property)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifyChanges()
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(Configuration));
|
||||||
|
OnPropertyChanged(nameof(IsController));
|
||||||
|
OnPropertyChanged(nameof(ShowSettings));
|
||||||
|
OnPropertyChanged(nameof(IsKeyboard));
|
||||||
|
OnPropertyChanged(nameof(IsRight));
|
||||||
|
OnPropertyChanged(nameof(IsLeft));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected;
|
||||||
|
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected;
|
||||||
|
|
||||||
|
_mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates();
|
||||||
|
|
||||||
|
SelectedGamepad?.Dispose();
|
||||||
|
|
||||||
|
AvaloniaKeyboardDriver.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
src/Ryujinx.Ava/UI/ViewModels/KeyboardInputViewModel.cs
Normal file
64
src/Ryujinx.Ava/UI/ViewModels/KeyboardInputViewModel.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using Avalonia.Svg.Skia;
|
||||||
|
using Ryujinx.Ava.UI.Models;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
{
|
||||||
|
public class KeyboardInputViewModel : BaseModel
|
||||||
|
{
|
||||||
|
private KeyboardInputConfig _config;
|
||||||
|
private bool _isLeft;
|
||||||
|
private bool _isRight;
|
||||||
|
private bool _showSettings;
|
||||||
|
private SvgImage _image;
|
||||||
|
|
||||||
|
public KeyboardInputConfig Config
|
||||||
|
{
|
||||||
|
get => _config;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_config = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsLeft
|
||||||
|
{
|
||||||
|
get => _isLeft;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_isLeft = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsRight
|
||||||
|
{
|
||||||
|
get => _isRight;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_isRight = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShowSettings
|
||||||
|
{
|
||||||
|
get => _showSettings;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_showSettings = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SvgImage Image
|
||||||
|
{
|
||||||
|
get => _image;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_image = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,9 @@
|
||||||
<UserControl
|
<UserControl
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
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"
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -15,6 +12,7 @@
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
x:Class="Ryujinx.Ava.UI.Views.Input.ControllerInputView"
|
x:Class="Ryujinx.Ava.UI.Views.Input.ControllerInputView"
|
||||||
x:DataType="viewModels:ControllerInputViewModel"
|
x:DataType="viewModels:ControllerInputViewModel"
|
||||||
|
x:CompileBindings="True"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Focusable="True">
|
Focusable="True">
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
|
@ -34,191 +32,10 @@
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Orientation="Vertical">
|
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 -->
|
<!-- Button / JoyStick Settings -->
|
||||||
<Grid
|
<Grid
|
||||||
Name="SettingButtons"
|
Name="SettingButtons"
|
||||||
MinHeight="450"
|
MinHeight="450"
|
||||||
FlowDirection="LeftToRight"
|
|
||||||
IsVisible="{Binding ShowSettings}">
|
IsVisible="{Binding ShowSettings}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
@ -260,7 +77,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonZl, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonZl, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -276,7 +93,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonL, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonL, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -292,7 +109,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonMinus, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonMinus, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -312,100 +129,8 @@
|
||||||
Margin="0,0,0,10"
|
Margin="0,0,0,10"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Text="{locale:Locale ControllerSettingsLStick}" />
|
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 -->
|
<!-- Left Joystick Controller -->
|
||||||
<StackPanel
|
<StackPanel Orientation="Vertical">
|
||||||
IsVisible="{Binding IsController}"
|
|
||||||
Orientation="Vertical">
|
|
||||||
<!-- Left Joystick Button -->
|
<!-- Left Joystick Button -->
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
|
@ -418,7 +143,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.LeftControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.LeftControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -435,20 +160,20 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton Tag="stick">
|
<ToggleButton Tag="stick">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.LeftJoystick, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.LeftJoystick, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Separator
|
<Separator
|
||||||
Margin="0,8,0,8"
|
Margin="0,8,0,8"
|
||||||
Height="1" />
|
Height="1" />
|
||||||
<CheckBox IsChecked="{ReflectionBinding Configuration.LeftInvertStickX}">
|
<CheckBox IsChecked="{Binding Config.LeftInvertStickX}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsStickInvertXAxis}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsStickInvertXAxis}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<CheckBox IsChecked="{ReflectionBinding Configuration.LeftInvertStickY}">
|
<CheckBox IsChecked="{Binding Config.LeftInvertStickY}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsStickInvertYAxis}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsStickInvertYAxis}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<CheckBox IsChecked="{ReflectionBinding Configuration.LeftRotate90}">
|
<CheckBox IsChecked="{Binding Config.LeftRotate90}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsRotate90}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsRotate90}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<Separator
|
<Separator
|
||||||
|
@ -462,18 +187,18 @@
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<controls:SliderScroll
|
<Slider
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="1"
|
Maximum="1"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
IsSnapToTickEnabled="True"
|
IsSnapToTickEnabled="True"
|
||||||
SmallChange="0.01"
|
SmallChange="0.01"
|
||||||
Minimum="0"
|
Minimum="0"
|
||||||
Value="{ReflectionBinding Configuration.DeadzoneLeft, Mode=TwoWay}" />
|
Value="{Binding Config.DeadzoneLeft, Mode=TwoWay}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Width="25"
|
Width="25"
|
||||||
Text="{ReflectionBinding Configuration.DeadzoneLeft, StringFormat=\{0:0.00\}}" />
|
Text="{Binding Config.DeadzoneLeft, StringFormat=\{0:0.00\}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
|
@ -482,18 +207,18 @@
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<controls:SliderScroll
|
<Slider
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="2"
|
Maximum="2"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
IsSnapToTickEnabled="True"
|
IsSnapToTickEnabled="True"
|
||||||
SmallChange="0.01"
|
SmallChange="0.01"
|
||||||
Minimum="0"
|
Minimum="0"
|
||||||
Value="{ReflectionBinding Configuration.RangeLeft, Mode=TwoWay}" />
|
Value="{Binding Config.RangeLeft, Mode=TwoWay}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Width="25"
|
Width="25"
|
||||||
Text="{ReflectionBinding Configuration.RangeLeft, StringFormat=\{0:0.00\}}" />
|
Text="{Binding Config.RangeLeft, StringFormat=\{0:0.00\}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -528,7 +253,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.DpadUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.DpadUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -545,7 +270,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.DpadDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.DpadDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -562,7 +287,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.DpadLeft, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.DpadLeft, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -579,7 +304,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.DpadRight, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.DpadRight, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -606,17 +331,17 @@
|
||||||
<StackPanel
|
<StackPanel
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<controls:SliderScroll
|
<Slider
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="1"
|
Maximum="1"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
IsSnapToTickEnabled="True"
|
IsSnapToTickEnabled="True"
|
||||||
SmallChange="0.01"
|
SmallChange="0.01"
|
||||||
Minimum="0"
|
Minimum="0"
|
||||||
Value="{ReflectionBinding Configuration.TriggerThreshold, Mode=TwoWay}" />
|
Value="{Binding Config.TriggerThreshold, Mode=TwoWay}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Width="25"
|
Width="25"
|
||||||
Text="{ReflectionBinding Configuration.TriggerThreshold, StringFormat=\{0:0.00\}}" />
|
Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Margin="0,4,0,0"
|
Margin="0,4,0,0"
|
||||||
|
@ -632,7 +357,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.LeftButtonSr, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.LeftButtonSr, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -650,7 +375,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.LeftButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.LeftButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -668,7 +393,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.RightButtonSr, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.RightButtonSr, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -686,7 +411,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.RightButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.RightButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -710,8 +435,7 @@
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CornerRadius="5"
|
CornerRadius="5"
|
||||||
VerticalAlignment="Bottom"
|
VerticalAlignment="Bottom"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch">
|
||||||
IsVisible="{Binding IsController}">
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
|
@ -721,7 +445,7 @@
|
||||||
Margin="10"
|
Margin="10"
|
||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
IsChecked="{ReflectionBinding Configuration.EnableMotion, Mode=TwoWay}">
|
IsChecked="{Binding Config.EnableMotion, Mode=TwoWay}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsMotion}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsMotion}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<Button
|
<Button
|
||||||
|
@ -737,7 +461,6 @@
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CornerRadius="5"
|
CornerRadius="5"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
IsVisible="{Binding IsController}"
|
|
||||||
Margin="0,-1,0,0">
|
Margin="0,-1,0,0">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
@ -748,7 +471,7 @@
|
||||||
Margin="10"
|
Margin="10"
|
||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
IsChecked="{ReflectionBinding Configuration.EnableRumble, Mode=TwoWay}">
|
IsChecked="{Binding Config.EnableRumble, Mode=TwoWay}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsRumble}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsRumble}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<Button
|
<Button
|
||||||
|
@ -796,7 +519,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonZr, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonZr, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -814,7 +537,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonR, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonR, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -832,7 +555,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonPlus, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonPlus, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -867,7 +590,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonA, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonA, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -884,7 +607,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonB, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonB, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -901,7 +624,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonX, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonX, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -918,7 +641,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.ButtonY, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.ButtonY, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -938,100 +661,8 @@
|
||||||
Margin="0,0,0,10"
|
Margin="0,0,0,10"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Text="{locale:Locale ControllerSettingsRStick}" />
|
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 -->
|
<!-- Right Joystick Controller -->
|
||||||
<StackPanel
|
<StackPanel Orientation="Vertical">
|
||||||
IsVisible="{Binding IsController}"
|
|
||||||
Orientation="Vertical">
|
|
||||||
<!-- Right Joystick Button -->
|
<!-- Right Joystick Button -->
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
|
@ -1044,7 +675,7 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton>
|
<ToggleButton>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.RightControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.RightControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -1062,18 +693,18 @@
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
<ToggleButton Tag="stick">
|
<ToggleButton Tag="stick">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{ReflectionBinding Configuration.RightJoystick, Mode=TwoWay, Converter={StaticResource Key}}"
|
Text="{Binding Config.RightJoystick, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Separator Margin="0,8,0,8" Height="1" />
|
<Separator Margin="0,8,0,8" Height="1" />
|
||||||
<CheckBox IsChecked="{ReflectionBinding Configuration.RightInvertStickX}">
|
<CheckBox IsChecked="{Binding Config.RightInvertStickX}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsStickInvertXAxis}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsStickInvertXAxis}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<CheckBox IsChecked="{ReflectionBinding Configuration.RightInvertStickY}">
|
<CheckBox IsChecked="{Binding Config.RightInvertStickY}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsStickInvertYAxis}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsStickInvertYAxis}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<CheckBox IsChecked="{ReflectionBinding Configuration.RightRotate90}">
|
<CheckBox IsChecked="{Binding Config.RightRotate90}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsRotate90}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsRotate90}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<Separator Margin="0,8,0,8" Height="1" />
|
<Separator Margin="0,8,0,8" Height="1" />
|
||||||
|
@ -1085,7 +716,7 @@
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<controls:SliderScroll
|
<Slider
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="1"
|
Maximum="1"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
|
@ -1094,11 +725,11 @@
|
||||||
Padding="0"
|
Padding="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Minimum="0"
|
Minimum="0"
|
||||||
Value="{ReflectionBinding Configuration.DeadzoneRight, Mode=TwoWay}" />
|
Value="{Binding Config.DeadzoneRight, Mode=TwoWay}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Width="25"
|
Width="25"
|
||||||
Text="{ReflectionBinding Configuration.DeadzoneRight, StringFormat=\{0:0.00\}}" />
|
Text="{Binding Config.DeadzoneRight, StringFormat=\{0:0.00\}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
|
@ -1107,18 +738,18 @@
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<controls:SliderScroll
|
<Slider
|
||||||
Width="130"
|
Width="130"
|
||||||
Maximum="2"
|
Maximum="2"
|
||||||
TickFrequency="0.01"
|
TickFrequency="0.01"
|
||||||
IsSnapToTickEnabled="True"
|
IsSnapToTickEnabled="True"
|
||||||
SmallChange="0.01"
|
SmallChange="0.01"
|
||||||
Minimum="0"
|
Minimum="0"
|
||||||
Value="{ReflectionBinding Configuration.RangeRight, Mode=TwoWay}" />
|
Value="{Binding Config.RangeRight, Mode=TwoWay}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Width="25"
|
Width="25"
|
||||||
Text="{ReflectionBinding Configuration.RangeRight, StringFormat=\{0:0.00\}}" />
|
Text="{Binding Config.RangeRight, StringFormat=\{0:0.00\}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
@ -1,181 +1,19 @@
|
||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Markup.Xaml;
|
||||||
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.Common.Configuration.Hid.Controller;
|
|
||||||
using Ryujinx.Input;
|
|
||||||
using Ryujinx.Input.Assigner;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Views.Input
|
namespace Ryujinx.Ava.UI.Views.Input
|
||||||
{
|
{
|
||||||
public partial class ControllerInputView : UserControl
|
public partial class ControllerInputView : UserControl
|
||||||
{
|
{
|
||||||
private bool _dialogOpen;
|
|
||||||
|
|
||||||
private ButtonKeyAssigner _currentAssigner;
|
|
||||||
internal ControllerInputViewModel ViewModel { get; set; }
|
|
||||||
|
|
||||||
public ControllerInputView()
|
public ControllerInputView()
|
||||||
{
|
{
|
||||||
DataContext = ViewModel = new ControllerInputViewModel(this);
|
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
if (visual is ToggleButton button && visual is not CheckBox)
|
AvaloniaXamlLoader.Load(this);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isStick = button.Tag != null && button.Tag.ToString() == "stick";
|
|
||||||
|
|
||||||
if (_currentAssigner == null)
|
|
||||||
{
|
|
||||||
_currentAssigner = new ButtonKeyAssigner(button);
|
|
||||||
|
|
||||||
this.Focus(NavigationMethod.Pointer);
|
|
||||||
|
|
||||||
PointerPressed += MouseClick;
|
|
||||||
|
|
||||||
IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
|
|
||||||
IButtonAssigner assigner = CreateButtonAssigner(isStick);
|
|
||||||
|
|
||||||
_currentAssigner.ButtonAssigned += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (e.IsAssigned)
|
|
||||||
{
|
|
||||||
ViewModel.IsModified = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_currentAssigner.GetInputAndAssign(assigner, keyboard);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_currentAssigner != null)
|
|
||||||
{
|
|
||||||
ToggleButton oldButton = _currentAssigner.ToggledButton;
|
|
||||||
|
|
||||||
_currentAssigner.Cancel();
|
|
||||||
_currentAssigner = null;
|
|
||||||
button.IsChecked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_currentAssigner?.Cancel();
|
|
||||||
_currentAssigner = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentAssigner?.Cancel(shouldUnbind);
|
|
||||||
|
|
||||||
PointerPressed -= MouseClick;
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
_currentAssigner?.Cancel();
|
|
||||||
_currentAssigner = null;
|
|
||||||
ViewModel.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
217
src/Ryujinx.Ava/UI/Views/Input/InputView.axaml
Normal file
217
src/Ryujinx.Ava/UI/Views/Input/InputView.axaml
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
<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"
|
||||||
|
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"
|
||||||
|
Items="{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:ComboBox
|
||||||
|
Grid.Column="1"
|
||||||
|
IsEditable="True"
|
||||||
|
Name="ProfileBox"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
SelectedIndex="0"
|
||||||
|
Items="{Binding ProfilesList}"
|
||||||
|
Text="{Binding ProfileName}" />
|
||||||
|
<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"
|
||||||
|
Items="{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"
|
||||||
|
Items="{ReflectionBinding Controllers}"
|
||||||
|
SelectedIndex="{ReflectionBinding Controller}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate DataType="models:ControllerModel">
|
||||||
|
<TextBlock Text="{Binding Name}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
<views:ControllerInputView IsVisible="{Binding IsController}"/>
|
||||||
|
<views:KeyboardInputView IsVisible="{Binding !IsController}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
180
src/Ryujinx.Ava/UI/Views/Input/InputView.axaml.cs
Normal file
180
src/Ryujinx.Ava/UI/Views/Input/InputView.axaml.cs
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
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.Common.Configuration.Hid.Controller;
|
||||||
|
using Ryujinx.Input;
|
||||||
|
using Ryujinx.Input.Assigner;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Input
|
||||||
|
{
|
||||||
|
public partial class InputView : UserControl
|
||||||
|
{
|
||||||
|
private bool _dialogOpen;
|
||||||
|
|
||||||
|
private ButtonKeyAssigner _currentAssigner;
|
||||||
|
internal InputViewModel ViewModel { get; set; }
|
||||||
|
|
||||||
|
public InputView()
|
||||||
|
{
|
||||||
|
DataContext = ViewModel = new InputViewModel(this);
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
|
||||||
|
{
|
||||||
|
if (visual is ToggleButton button && !(visual is CheckBox))
|
||||||
|
{
|
||||||
|
button.Checked += Button_Checked;
|
||||||
|
button.Unchecked += Button_Unchecked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPointerReleased(e);
|
||||||
|
|
||||||
|
if (_currentAssigner != null && _currentAssigner.ToggledButton != null && !_currentAssigner.ToggledButton.IsPointerOver)
|
||||||
|
{
|
||||||
|
_currentAssigner.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Button_Checked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ToggleButton button)
|
||||||
|
{
|
||||||
|
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isStick = button.Tag != null && button.Tag.ToString() == "stick";
|
||||||
|
|
||||||
|
if (_currentAssigner == null && (bool)button.IsChecked)
|
||||||
|
{
|
||||||
|
_currentAssigner = new ButtonKeyAssigner(button);
|
||||||
|
|
||||||
|
FocusManager.Instance.Focus(this, NavigationMethod.Pointer);
|
||||||
|
|
||||||
|
PointerPressed += MouseClick;
|
||||||
|
|
||||||
|
IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
|
||||||
|
IButtonAssigner assigner = CreateButtonAssigner(isStick);
|
||||||
|
|
||||||
|
_currentAssigner.ButtonAssigned += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (e.IsAssigned)
|
||||||
|
{
|
||||||
|
ViewModel.IsModified = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_currentAssigner.GetInputAndAssign(assigner, keyboard);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_currentAssigner != null)
|
||||||
|
{
|
||||||
|
ToggleButton oldButton = _currentAssigner.ToggledButton;
|
||||||
|
|
||||||
|
_currentAssigner.Cancel();
|
||||||
|
_currentAssigner = null;
|
||||||
|
button.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Button_Unchecked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_currentAssigner?.Cancel();
|
||||||
|
_currentAssigner = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MouseClick(object sender, PointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
bool shouldUnbind = false;
|
||||||
|
|
||||||
|
if (e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed)
|
||||||
|
{
|
||||||
|
shouldUnbind = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentAssigner?.Cancel(shouldUnbind);
|
||||||
|
|
||||||
|
PointerPressed -= MouseClick;
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
_currentAssigner?.Cancel();
|
||||||
|
_currentAssigner = null;
|
||||||
|
ViewModel.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
678
src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml
Normal file
678
src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml
Normal file
|
@ -0,0 +1,678 @@
|
||||||
|
<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"
|
||||||
|
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"
|
||||||
|
IsVisible="{Binding ShowSettings}">
|
||||||
|
<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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonZl, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonL, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonMinus, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.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="{Binding Config.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="{Binding Config.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="{Binding Config.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="{Binding Config.LeftStickRight, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.DpadUp, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.DpadDown, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.DpadLeft, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.DpadRight, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
<!-- Triggers & Side Buttons -->
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
|
<Border
|
||||||
|
BorderBrush="{DynamicResource ThemeControlBorderColor}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="5"
|
||||||
|
MinHeight="90">
|
||||||
|
<StackPanel
|
||||||
|
Margin="8"
|
||||||
|
Orientation="Vertical">
|
||||||
|
<TextBlock
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Text="{locale:Locale ControllerSettingsTriggerThreshold}" />
|
||||||
|
<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 ControllerSettingsLeftSR}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
<ToggleButton>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.LeftButtonSr, Mode=TwoWay, 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 ControllerSettingsLeftSL}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
<ToggleButton>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.LeftButtonSl, Mode=TwoWay, 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 ControllerSettingsRightSR}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
<ToggleButton>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.RightButtonSr, Mode=TwoWay, 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 ControllerSettingsRightSL}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
<ToggleButton>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.RightButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
<!-- Controller Picture -->
|
||||||
|
<Image
|
||||||
|
Margin="0,10,0,0"
|
||||||
|
MaxHeight="300"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Source="{Binding Image}" />
|
||||||
|
</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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonZr, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonR, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonPlus, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
<!-- Right Joystick -->
|
||||||
|
<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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonA, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonB, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonX, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.ButtonY, Mode=TwoWay, 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>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Config.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="{Binding Config.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="{Binding Config.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="{Binding Config.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="{Binding Config.RightStickRight, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
19
src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs
Normal file
19
src/Ryujinx.Ava/UI/Views/Input/KeyboardInputView.axaml.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Views.Input
|
||||||
|
{
|
||||||
|
public partial class KeyboardInputView : UserControl
|
||||||
|
{
|
||||||
|
public KeyboardInputView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,7 @@
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<views:ControllerInputView
|
<views:InputView
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Name="ControllerSettings" />
|
Name="ControllerSettings" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
|
Loading…
Reference in a new issue