forked from MeloNX/MeloNX
Nintendo controllers notoriously have the A/B and X/Y buttons swapped, compared to the standard. In order to combat this, when setting the default controller layout, Ryujinx checks whether the controller name contains "Nintendo", and swaps the mapping accordingly. However, the reason the mapping is inverted in the first place is because SDL has `SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS` set to 1 by default. By setting it to 0, the mapping will be based on the buttons' position instead. So, by doing it (and removing the `isNintendoStyle` variable), we get the following advantages: - The mapping will be the same on all controllers, removing the need to adjust custom mappings depending on what controller is used - Users who already set `SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS` to 0 globally for other games/applications (like me) won't have a wrong default mapping - Checking whether the controller name contains "Nintendo" is ugly Disadvantages: - Breaks the controller configuration for existing users who are using a Nintendo controller
1229 lines
51 KiB
C#
1229 lines
51 KiB
C#
using Gtk;
|
|
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.Input.Assigner;
|
|
using Ryujinx.Input.GTK3;
|
|
using Ryujinx.Ui.Common.Configuration;
|
|
using Ryujinx.Ui.Widgets;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
|
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
|
using GUI = Gtk.Builder.ObjectAttribute;
|
|
using Key = Ryujinx.Common.Configuration.Hid.Key;
|
|
|
|
namespace Ryujinx.Ui.Windows
|
|
{
|
|
public class ControllerWindow : Window
|
|
{
|
|
private readonly PlayerIndex _playerIndex;
|
|
private readonly InputConfig _inputConfig;
|
|
|
|
private bool _isWaitingForInput;
|
|
|
|
#pragma warning disable CS0649, IDE0044 // Field is never assigned to, Add readonly modifier
|
|
[GUI] Adjustment _controllerStrongRumble;
|
|
[GUI] Adjustment _controllerWeakRumble;
|
|
[GUI] Adjustment _controllerDeadzoneLeft;
|
|
[GUI] Adjustment _controllerDeadzoneRight;
|
|
[GUI] Adjustment _controllerRangeLeft;
|
|
[GUI] Adjustment _controllerRangeRight;
|
|
[GUI] Adjustment _controllerTriggerThreshold;
|
|
[GUI] Adjustment _slotNumber;
|
|
[GUI] Adjustment _altSlotNumber;
|
|
[GUI] Adjustment _sensitivity;
|
|
[GUI] Adjustment _gyroDeadzone;
|
|
[GUI] CheckButton _enableMotion;
|
|
[GUI] CheckButton _enableCemuHook;
|
|
[GUI] CheckButton _mirrorInput;
|
|
[GUI] Entry _dsuServerHost;
|
|
[GUI] Entry _dsuServerPort;
|
|
[GUI] ComboBoxText _inputDevice;
|
|
[GUI] ComboBoxText _profile;
|
|
[GUI] Box _settingsBox;
|
|
[GUI] Box _motionAltBox;
|
|
[GUI] Box _motionBox;
|
|
[GUI] Box _dsuServerHostBox;
|
|
[GUI] Box _dsuServerPortBox;
|
|
[GUI] Box _motionControllerSlot;
|
|
[GUI] Grid _leftStickKeyboard;
|
|
[GUI] Grid _leftStickController;
|
|
[GUI] Box _deadZoneLeftBox;
|
|
[GUI] Box _rangeLeftBox;
|
|
[GUI] Grid _rightStickKeyboard;
|
|
[GUI] Grid _rightStickController;
|
|
[GUI] Box _deadZoneRightBox;
|
|
[GUI] Box _rangeRightBox;
|
|
[GUI] Grid _leftSideTriggerBox;
|
|
[GUI] Grid _rightSideTriggerBox;
|
|
[GUI] Box _triggerThresholdBox;
|
|
[GUI] ComboBoxText _controllerType;
|
|
[GUI] ToggleButton _lStick;
|
|
[GUI] CheckButton _invertLStickX;
|
|
[GUI] CheckButton _invertLStickY;
|
|
[GUI] CheckButton _rotateL90CW;
|
|
[GUI] ToggleButton _lStickUp;
|
|
[GUI] ToggleButton _lStickDown;
|
|
[GUI] ToggleButton _lStickLeft;
|
|
[GUI] ToggleButton _lStickRight;
|
|
[GUI] ToggleButton _lStickButton;
|
|
[GUI] ToggleButton _dpadUp;
|
|
[GUI] ToggleButton _dpadDown;
|
|
[GUI] ToggleButton _dpadLeft;
|
|
[GUI] ToggleButton _dpadRight;
|
|
[GUI] ToggleButton _minus;
|
|
[GUI] ToggleButton _l;
|
|
[GUI] ToggleButton _zL;
|
|
[GUI] ToggleButton _rStick;
|
|
[GUI] CheckButton _invertRStickX;
|
|
[GUI] CheckButton _invertRStickY;
|
|
[GUI] CheckButton _rotateR90CW;
|
|
[GUI] ToggleButton _rStickUp;
|
|
[GUI] ToggleButton _rStickDown;
|
|
[GUI] ToggleButton _rStickLeft;
|
|
[GUI] ToggleButton _rStickRight;
|
|
[GUI] ToggleButton _rStickButton;
|
|
[GUI] ToggleButton _a;
|
|
[GUI] ToggleButton _b;
|
|
[GUI] ToggleButton _x;
|
|
[GUI] ToggleButton _y;
|
|
[GUI] ToggleButton _plus;
|
|
[GUI] ToggleButton _r;
|
|
[GUI] ToggleButton _zR;
|
|
[GUI] ToggleButton _lSl;
|
|
[GUI] ToggleButton _lSr;
|
|
[GUI] ToggleButton _rSl;
|
|
[GUI] ToggleButton _rSr;
|
|
[GUI] Image _controllerImage;
|
|
[GUI] CheckButton _enableRumble;
|
|
[GUI] Box _rumbleBox;
|
|
#pragma warning restore CS0649, IDE0044
|
|
|
|
private readonly MainWindow _mainWindow;
|
|
private readonly IGamepadDriver _gtk3KeyboardDriver;
|
|
private IGamepad _selectedGamepad;
|
|
private bool _mousePressed;
|
|
private bool _middleMousePressed;
|
|
|
|
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
|
|
public ControllerWindow(MainWindow mainWindow, PlayerIndex controllerId) : this(mainWindow, new Builder("Ryujinx.Ui.Windows.ControllerWindow.glade"), controllerId) { }
|
|
|
|
private ControllerWindow(MainWindow mainWindow, Builder builder, PlayerIndex controllerId) : base(builder.GetRawOwnedObject("_controllerWin"))
|
|
{
|
|
_mainWindow = mainWindow;
|
|
_selectedGamepad = null;
|
|
|
|
// 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...
|
|
_gtk3KeyboardDriver = new GTK3KeyboardDriver(this);
|
|
|
|
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
|
|
|
builder.Autoconnect(this);
|
|
|
|
_playerIndex = controllerId;
|
|
_inputConfig = ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == _playerIndex);
|
|
|
|
Title = $"Ryujinx - Controller Settings - {_playerIndex}";
|
|
|
|
if (_playerIndex == PlayerIndex.Handheld)
|
|
{
|
|
_controllerType.Append(ControllerType.Handheld.ToString(), "Handheld");
|
|
_controllerType.Sensitive = false;
|
|
}
|
|
else
|
|
{
|
|
_controllerType.Append(ControllerType.ProController.ToString(), "Pro Controller");
|
|
_controllerType.Append(ControllerType.JoyconPair.ToString(), "Joycon Pair");
|
|
_controllerType.Append(ControllerType.JoyconLeft.ToString(), "Joycon Left");
|
|
_controllerType.Append(ControllerType.JoyconRight.ToString(), "Joycon Right");
|
|
}
|
|
|
|
_controllerType.Active = 0; // Set initial value to first in list.
|
|
|
|
// Bind Events.
|
|
_lStick.Clicked += ButtonForStick_Pressed;
|
|
_lStickUp.Clicked += Button_Pressed;
|
|
_lStickDown.Clicked += Button_Pressed;
|
|
_lStickLeft.Clicked += Button_Pressed;
|
|
_lStickRight.Clicked += Button_Pressed;
|
|
_lStickButton.Clicked += Button_Pressed;
|
|
_dpadUp.Clicked += Button_Pressed;
|
|
_dpadDown.Clicked += Button_Pressed;
|
|
_dpadLeft.Clicked += Button_Pressed;
|
|
_dpadRight.Clicked += Button_Pressed;
|
|
_minus.Clicked += Button_Pressed;
|
|
_l.Clicked += Button_Pressed;
|
|
_zL.Clicked += Button_Pressed;
|
|
_lSl.Clicked += Button_Pressed;
|
|
_lSr.Clicked += Button_Pressed;
|
|
_rStick.Clicked += ButtonForStick_Pressed;
|
|
_rStickUp.Clicked += Button_Pressed;
|
|
_rStickDown.Clicked += Button_Pressed;
|
|
_rStickLeft.Clicked += Button_Pressed;
|
|
_rStickRight.Clicked += Button_Pressed;
|
|
_rStickButton.Clicked += Button_Pressed;
|
|
_a.Clicked += Button_Pressed;
|
|
_b.Clicked += Button_Pressed;
|
|
_x.Clicked += Button_Pressed;
|
|
_y.Clicked += Button_Pressed;
|
|
_plus.Clicked += Button_Pressed;
|
|
_r.Clicked += Button_Pressed;
|
|
_zR.Clicked += Button_Pressed;
|
|
_rSl.Clicked += Button_Pressed;
|
|
_rSr.Clicked += Button_Pressed;
|
|
_enableCemuHook.Clicked += CemuHookCheckButtonPressed;
|
|
|
|
// Setup current values.
|
|
UpdateInputDeviceList();
|
|
SetAvailableOptions();
|
|
|
|
ClearValues();
|
|
if (_inputDevice.ActiveId != null)
|
|
{
|
|
SetCurrentValues();
|
|
}
|
|
|
|
mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
|
mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
|
|
|
_mainWindow.RendererWidget?.NpadManager.BlockInputUpdates();
|
|
}
|
|
|
|
private void CemuHookCheckButtonPressed(object sender, EventArgs e)
|
|
{
|
|
UpdateCemuHookSpecificFieldsVisibility();
|
|
}
|
|
|
|
private void HandleOnGamepadDisconnected(string id)
|
|
{
|
|
Application.Invoke(delegate
|
|
{
|
|
UpdateInputDeviceList();
|
|
});
|
|
}
|
|
|
|
private void HandleOnGamepadConnected(string id)
|
|
{
|
|
Application.Invoke(delegate
|
|
{
|
|
UpdateInputDeviceList();
|
|
});
|
|
}
|
|
|
|
protected override void OnDestroyed()
|
|
{
|
|
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected;
|
|
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected;
|
|
|
|
_mainWindow.RendererWidget?.NpadManager.UnblockInputUpdates();
|
|
|
|
_selectedGamepad?.Dispose();
|
|
|
|
_gtk3KeyboardDriver.Dispose();
|
|
}
|
|
|
|
private static string GetShortGamepadName(string str)
|
|
{
|
|
const string ShrinkChars = "...";
|
|
const int MaxSize = 50;
|
|
|
|
if (str.Length > MaxSize)
|
|
{
|
|
return $"{str.AsSpan(0, MaxSize - ShrinkChars.Length)}{ShrinkChars}";
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
private void UpdateInputDeviceList()
|
|
{
|
|
_inputDevice.RemoveAll();
|
|
_inputDevice.Append("disabled", "Disabled");
|
|
_inputDevice.SetActiveId("disabled");
|
|
|
|
foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds)
|
|
{
|
|
IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
|
|
|
|
if (gamepad != null)
|
|
{
|
|
_inputDevice.Append($"keyboard/{id}", GetShortGamepadName($"{gamepad.Name} ({id})"));
|
|
|
|
gamepad.Dispose();
|
|
}
|
|
}
|
|
|
|
foreach (string id in _mainWindow.InputManager.GamepadDriver.GamepadsIds)
|
|
{
|
|
IGamepad gamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id);
|
|
|
|
if (gamepad != null)
|
|
{
|
|
_inputDevice.Append($"controller/{id}", GetShortGamepadName($"{gamepad.Name} ({id})"));
|
|
|
|
gamepad.Dispose();
|
|
}
|
|
}
|
|
|
|
switch (_inputConfig)
|
|
{
|
|
case StandardKeyboardInputConfig keyboard:
|
|
_inputDevice.SetActiveId($"keyboard/{keyboard.Id}");
|
|
break;
|
|
case StandardControllerInputConfig controller:
|
|
_inputDevice.SetActiveId($"controller/{controller.Id}");
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void UpdateCemuHookSpecificFieldsVisibility()
|
|
{
|
|
if (_enableCemuHook.Active)
|
|
{
|
|
_dsuServerHostBox.Show();
|
|
_dsuServerPortBox.Show();
|
|
_motionControllerSlot.Show();
|
|
_motionAltBox.Show();
|
|
_mirrorInput.Show();
|
|
}
|
|
else
|
|
{
|
|
_dsuServerHostBox.Hide();
|
|
_dsuServerPortBox.Hide();
|
|
_motionControllerSlot.Hide();
|
|
_motionAltBox.Hide();
|
|
_mirrorInput.Hide();
|
|
}
|
|
}
|
|
|
|
private void SetAvailableOptions()
|
|
{
|
|
if (_inputDevice.ActiveId != null && _inputDevice.ActiveId.StartsWith("keyboard"))
|
|
{
|
|
ShowAll();
|
|
_leftStickController.Hide();
|
|
_rightStickController.Hide();
|
|
_deadZoneLeftBox.Hide();
|
|
_deadZoneRightBox.Hide();
|
|
_rangeLeftBox.Hide();
|
|
_rangeRightBox.Hide();
|
|
_triggerThresholdBox.Hide();
|
|
_motionBox.Hide();
|
|
_rumbleBox.Hide();
|
|
}
|
|
else if (_inputDevice.ActiveId != null && _inputDevice.ActiveId.StartsWith("controller"))
|
|
{
|
|
ShowAll();
|
|
_leftStickKeyboard.Hide();
|
|
_rightStickKeyboard.Hide();
|
|
|
|
UpdateCemuHookSpecificFieldsVisibility();
|
|
}
|
|
else
|
|
{
|
|
_settingsBox.Hide();
|
|
}
|
|
|
|
ClearValues();
|
|
}
|
|
|
|
private void SetCurrentValues()
|
|
{
|
|
SetControllerSpecificFields();
|
|
|
|
SetProfiles();
|
|
|
|
if (_inputDevice.ActiveId.StartsWith("keyboard") && _inputConfig is StandardKeyboardInputConfig)
|
|
{
|
|
SetValues(_inputConfig);
|
|
}
|
|
else if (_inputDevice.ActiveId.StartsWith("controller") && _inputConfig is StandardControllerInputConfig)
|
|
{
|
|
SetValues(_inputConfig);
|
|
}
|
|
}
|
|
|
|
private void SetControllerSpecificFields()
|
|
{
|
|
_leftSideTriggerBox.Hide();
|
|
_rightSideTriggerBox.Hide();
|
|
_motionAltBox.Hide();
|
|
|
|
switch (_controllerType.ActiveId)
|
|
{
|
|
case "JoyconLeft":
|
|
_leftSideTriggerBox.Show();
|
|
break;
|
|
case "JoyconRight":
|
|
_rightSideTriggerBox.Show();
|
|
break;
|
|
case "JoyconPair":
|
|
_motionAltBox.Show();
|
|
break;
|
|
}
|
|
|
|
if (!OperatingSystem.IsMacOS())
|
|
{
|
|
_controllerImage.Pixbuf = _controllerType.ActiveId switch
|
|
{
|
|
"ProController" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_ProCon.svg", 400, 400),
|
|
"JoyconLeft" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConLeft.svg", 400, 500),
|
|
"JoyconRight" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConRight.svg", 400, 500),
|
|
_ => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConPair.svg", 400, 500),
|
|
};
|
|
}
|
|
}
|
|
|
|
private void ClearValues()
|
|
{
|
|
_lStick.Label = "Unbound";
|
|
_lStickUp.Label = "Unbound";
|
|
_lStickDown.Label = "Unbound";
|
|
_lStickLeft.Label = "Unbound";
|
|
_lStickRight.Label = "Unbound";
|
|
_lStickButton.Label = "Unbound";
|
|
_dpadUp.Label = "Unbound";
|
|
_dpadDown.Label = "Unbound";
|
|
_dpadLeft.Label = "Unbound";
|
|
_dpadRight.Label = "Unbound";
|
|
_minus.Label = "Unbound";
|
|
_l.Label = "Unbound";
|
|
_zL.Label = "Unbound";
|
|
_lSl.Label = "Unbound";
|
|
_lSr.Label = "Unbound";
|
|
_rStick.Label = "Unbound";
|
|
_rStickUp.Label = "Unbound";
|
|
_rStickDown.Label = "Unbound";
|
|
_rStickLeft.Label = "Unbound";
|
|
_rStickRight.Label = "Unbound";
|
|
_rStickButton.Label = "Unbound";
|
|
_a.Label = "Unbound";
|
|
_b.Label = "Unbound";
|
|
_x.Label = "Unbound";
|
|
_y.Label = "Unbound";
|
|
_plus.Label = "Unbound";
|
|
_r.Label = "Unbound";
|
|
_zR.Label = "Unbound";
|
|
_rSl.Label = "Unbound";
|
|
_rSr.Label = "Unbound";
|
|
_controllerStrongRumble.Value = 1;
|
|
_controllerWeakRumble.Value = 1;
|
|
_controllerDeadzoneLeft.Value = 0;
|
|
_controllerDeadzoneRight.Value = 0;
|
|
_controllerRangeLeft.Value = 1;
|
|
_controllerRangeRight.Value = 1;
|
|
_controllerTriggerThreshold.Value = 0;
|
|
_mirrorInput.Active = false;
|
|
_enableMotion.Active = false;
|
|
_enableCemuHook.Active = false;
|
|
_slotNumber.Value = 0;
|
|
_altSlotNumber.Value = 0;
|
|
_sensitivity.Value = 100;
|
|
_gyroDeadzone.Value = 1;
|
|
_dsuServerHost.Buffer.Text = "";
|
|
_dsuServerPort.Buffer.Text = "";
|
|
_enableRumble.Active = false;
|
|
}
|
|
|
|
private void SetValues(InputConfig config)
|
|
{
|
|
switch (config)
|
|
{
|
|
case StandardKeyboardInputConfig keyboardConfig:
|
|
if (!_controllerType.SetActiveId(keyboardConfig.ControllerType.ToString()))
|
|
{
|
|
_controllerType.SetActiveId(_playerIndex == PlayerIndex.Handheld
|
|
? ControllerType.Handheld.ToString()
|
|
: ControllerType.ProController.ToString());
|
|
}
|
|
|
|
_lStickUp.Label = keyboardConfig.LeftJoyconStick.StickUp.ToString();
|
|
_lStickDown.Label = keyboardConfig.LeftJoyconStick.StickDown.ToString();
|
|
_lStickLeft.Label = keyboardConfig.LeftJoyconStick.StickLeft.ToString();
|
|
_lStickRight.Label = keyboardConfig.LeftJoyconStick.StickRight.ToString();
|
|
_lStickButton.Label = keyboardConfig.LeftJoyconStick.StickButton.ToString();
|
|
_dpadUp.Label = keyboardConfig.LeftJoycon.DpadUp.ToString();
|
|
_dpadDown.Label = keyboardConfig.LeftJoycon.DpadDown.ToString();
|
|
_dpadLeft.Label = keyboardConfig.LeftJoycon.DpadLeft.ToString();
|
|
_dpadRight.Label = keyboardConfig.LeftJoycon.DpadRight.ToString();
|
|
_minus.Label = keyboardConfig.LeftJoycon.ButtonMinus.ToString();
|
|
_l.Label = keyboardConfig.LeftJoycon.ButtonL.ToString();
|
|
_zL.Label = keyboardConfig.LeftJoycon.ButtonZl.ToString();
|
|
_lSl.Label = keyboardConfig.LeftJoycon.ButtonSl.ToString();
|
|
_lSr.Label = keyboardConfig.LeftJoycon.ButtonSr.ToString();
|
|
_rStickUp.Label = keyboardConfig.RightJoyconStick.StickUp.ToString();
|
|
_rStickDown.Label = keyboardConfig.RightJoyconStick.StickDown.ToString();
|
|
_rStickLeft.Label = keyboardConfig.RightJoyconStick.StickLeft.ToString();
|
|
_rStickRight.Label = keyboardConfig.RightJoyconStick.StickRight.ToString();
|
|
_rStickButton.Label = keyboardConfig.RightJoyconStick.StickButton.ToString();
|
|
_a.Label = keyboardConfig.RightJoycon.ButtonA.ToString();
|
|
_b.Label = keyboardConfig.RightJoycon.ButtonB.ToString();
|
|
_x.Label = keyboardConfig.RightJoycon.ButtonX.ToString();
|
|
_y.Label = keyboardConfig.RightJoycon.ButtonY.ToString();
|
|
_plus.Label = keyboardConfig.RightJoycon.ButtonPlus.ToString();
|
|
_r.Label = keyboardConfig.RightJoycon.ButtonR.ToString();
|
|
_zR.Label = keyboardConfig.RightJoycon.ButtonZr.ToString();
|
|
_rSl.Label = keyboardConfig.RightJoycon.ButtonSl.ToString();
|
|
_rSr.Label = keyboardConfig.RightJoycon.ButtonSr.ToString();
|
|
break;
|
|
|
|
case StandardControllerInputConfig controllerConfig:
|
|
if (!_controllerType.SetActiveId(controllerConfig.ControllerType.ToString()))
|
|
{
|
|
_controllerType.SetActiveId(_playerIndex == PlayerIndex.Handheld
|
|
? ControllerType.Handheld.ToString()
|
|
: ControllerType.ProController.ToString());
|
|
}
|
|
|
|
_lStick.Label = controllerConfig.LeftJoyconStick.Joystick.ToString();
|
|
_invertLStickX.Active = controllerConfig.LeftJoyconStick.InvertStickX;
|
|
_invertLStickY.Active = controllerConfig.LeftJoyconStick.InvertStickY;
|
|
_rotateL90CW.Active = controllerConfig.LeftJoyconStick.Rotate90CW;
|
|
_lStickButton.Label = controllerConfig.LeftJoyconStick.StickButton.ToString();
|
|
_dpadUp.Label = controllerConfig.LeftJoycon.DpadUp.ToString();
|
|
_dpadDown.Label = controllerConfig.LeftJoycon.DpadDown.ToString();
|
|
_dpadLeft.Label = controllerConfig.LeftJoycon.DpadLeft.ToString();
|
|
_dpadRight.Label = controllerConfig.LeftJoycon.DpadRight.ToString();
|
|
_minus.Label = controllerConfig.LeftJoycon.ButtonMinus.ToString();
|
|
_l.Label = controllerConfig.LeftJoycon.ButtonL.ToString();
|
|
_zL.Label = controllerConfig.LeftJoycon.ButtonZl.ToString();
|
|
_lSl.Label = controllerConfig.LeftJoycon.ButtonSl.ToString();
|
|
_lSr.Label = controllerConfig.LeftJoycon.ButtonSr.ToString();
|
|
_rStick.Label = controllerConfig.RightJoyconStick.Joystick.ToString();
|
|
_invertRStickX.Active = controllerConfig.RightJoyconStick.InvertStickX;
|
|
_invertRStickY.Active = controllerConfig.RightJoyconStick.InvertStickY;
|
|
_rotateR90CW.Active = controllerConfig.RightJoyconStick.Rotate90CW;
|
|
_rStickButton.Label = controllerConfig.RightJoyconStick.StickButton.ToString();
|
|
_a.Label = controllerConfig.RightJoycon.ButtonA.ToString();
|
|
_b.Label = controllerConfig.RightJoycon.ButtonB.ToString();
|
|
_x.Label = controllerConfig.RightJoycon.ButtonX.ToString();
|
|
_y.Label = controllerConfig.RightJoycon.ButtonY.ToString();
|
|
_plus.Label = controllerConfig.RightJoycon.ButtonPlus.ToString();
|
|
_r.Label = controllerConfig.RightJoycon.ButtonR.ToString();
|
|
_zR.Label = controllerConfig.RightJoycon.ButtonZr.ToString();
|
|
_rSl.Label = controllerConfig.RightJoycon.ButtonSl.ToString();
|
|
_rSr.Label = controllerConfig.RightJoycon.ButtonSr.ToString();
|
|
_controllerStrongRumble.Value = controllerConfig.Rumble.StrongRumble;
|
|
_controllerWeakRumble.Value = controllerConfig.Rumble.WeakRumble;
|
|
_enableRumble.Active = controllerConfig.Rumble.EnableRumble;
|
|
_controllerDeadzoneLeft.Value = controllerConfig.DeadzoneLeft;
|
|
_controllerDeadzoneRight.Value = controllerConfig.DeadzoneRight;
|
|
_controllerRangeLeft.Value = controllerConfig.RangeLeft;
|
|
_controllerRangeRight.Value = controllerConfig.RangeRight;
|
|
_controllerTriggerThreshold.Value = controllerConfig.TriggerThreshold;
|
|
_sensitivity.Value = controllerConfig.Motion.Sensitivity;
|
|
_gyroDeadzone.Value = controllerConfig.Motion.GyroDeadzone;
|
|
_enableMotion.Active = controllerConfig.Motion.EnableMotion;
|
|
_enableCemuHook.Active = controllerConfig.Motion.MotionBackend == MotionInputBackendType.CemuHook;
|
|
|
|
// If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
|
|
if (_controllerRangeLeft.Value <= 0.0 && _controllerRangeRight.Value <= 0.0)
|
|
{
|
|
_controllerRangeLeft.Value = 1.0;
|
|
_controllerRangeRight.Value = 1.0;
|
|
|
|
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
|
|
}
|
|
|
|
if (controllerConfig.Motion is CemuHookMotionConfigController cemuHookMotionConfig)
|
|
{
|
|
_slotNumber.Value = cemuHookMotionConfig.Slot;
|
|
_altSlotNumber.Value = cemuHookMotionConfig.AltSlot;
|
|
_mirrorInput.Active = cemuHookMotionConfig.MirrorInput;
|
|
_dsuServerHost.Buffer.Text = cemuHookMotionConfig.DsuServerHost;
|
|
_dsuServerPort.Buffer.Text = cemuHookMotionConfig.DsuServerPort.ToString();
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
private InputConfig GetValues()
|
|
{
|
|
if (_inputDevice.ActiveId.StartsWith("keyboard"))
|
|
{
|
|
#pragma warning disable CA1806, IDE0055 // Disable formatting
|
|
Enum.TryParse(_lStickUp.Label, out Key lStickUp);
|
|
Enum.TryParse(_lStickDown.Label, out Key lStickDown);
|
|
Enum.TryParse(_lStickLeft.Label, out Key lStickLeft);
|
|
Enum.TryParse(_lStickRight.Label, out Key lStickRight);
|
|
Enum.TryParse(_lStickButton.Label, out Key lStickButton);
|
|
Enum.TryParse(_dpadUp.Label, out Key lDPadUp);
|
|
Enum.TryParse(_dpadDown.Label, out Key lDPadDown);
|
|
Enum.TryParse(_dpadLeft.Label, out Key lDPadLeft);
|
|
Enum.TryParse(_dpadRight.Label, out Key lDPadRight);
|
|
Enum.TryParse(_minus.Label, out Key lButtonMinus);
|
|
Enum.TryParse(_l.Label, out Key lButtonL);
|
|
Enum.TryParse(_zL.Label, out Key lButtonZl);
|
|
Enum.TryParse(_lSl.Label, out Key lButtonSl);
|
|
Enum.TryParse(_lSr.Label, out Key lButtonSr);
|
|
|
|
Enum.TryParse(_rStickUp.Label, out Key rStickUp);
|
|
Enum.TryParse(_rStickDown.Label, out Key rStickDown);
|
|
Enum.TryParse(_rStickLeft.Label, out Key rStickLeft);
|
|
Enum.TryParse(_rStickRight.Label, out Key rStickRight);
|
|
Enum.TryParse(_rStickButton.Label, out Key rStickButton);
|
|
Enum.TryParse(_a.Label, out Key rButtonA);
|
|
Enum.TryParse(_b.Label, out Key rButtonB);
|
|
Enum.TryParse(_x.Label, out Key rButtonX);
|
|
Enum.TryParse(_y.Label, out Key rButtonY);
|
|
Enum.TryParse(_plus.Label, out Key rButtonPlus);
|
|
Enum.TryParse(_r.Label, out Key rButtonR);
|
|
Enum.TryParse(_zR.Label, out Key rButtonZr);
|
|
Enum.TryParse(_rSl.Label, out Key rButtonSl);
|
|
Enum.TryParse(_rSr.Label, out Key rButtonSr);
|
|
#pragma warning restore CA1806, IDE0055
|
|
|
|
return new StandardKeyboardInputConfig
|
|
{
|
|
Backend = InputBackendType.WindowKeyboard,
|
|
Version = InputConfig.CurrentVersion,
|
|
Id = _inputDevice.ActiveId.Split("/")[1],
|
|
ControllerType = Enum.Parse<ControllerType>(_controllerType.ActiveId),
|
|
PlayerIndex = _playerIndex,
|
|
LeftJoycon = new LeftJoyconCommonConfig<Key>
|
|
{
|
|
ButtonMinus = lButtonMinus,
|
|
ButtonL = lButtonL,
|
|
ButtonZl = lButtonZl,
|
|
ButtonSl = lButtonSl,
|
|
ButtonSr = lButtonSr,
|
|
DpadUp = lDPadUp,
|
|
DpadDown = lDPadDown,
|
|
DpadLeft = lDPadLeft,
|
|
DpadRight = lDPadRight,
|
|
},
|
|
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
|
|
{
|
|
StickUp = lStickUp,
|
|
StickDown = lStickDown,
|
|
StickLeft = lStickLeft,
|
|
StickRight = lStickRight,
|
|
StickButton = lStickButton,
|
|
},
|
|
RightJoycon = new RightJoyconCommonConfig<Key>
|
|
{
|
|
ButtonA = rButtonA,
|
|
ButtonB = rButtonB,
|
|
ButtonX = rButtonX,
|
|
ButtonY = rButtonY,
|
|
ButtonPlus = rButtonPlus,
|
|
ButtonR = rButtonR,
|
|
ButtonZr = rButtonZr,
|
|
ButtonSl = rButtonSl,
|
|
ButtonSr = rButtonSr,
|
|
},
|
|
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
|
{
|
|
StickUp = rStickUp,
|
|
StickDown = rStickDown,
|
|
StickLeft = rStickLeft,
|
|
StickRight = rStickRight,
|
|
StickButton = rStickButton,
|
|
},
|
|
};
|
|
}
|
|
|
|
if (_inputDevice.ActiveId.StartsWith("controller"))
|
|
{
|
|
#pragma warning disable CA1806, IDE0055 // Disable formatting
|
|
Enum.TryParse(_lStick.Label, out ConfigStickInputId lStick);
|
|
Enum.TryParse(_lStickButton.Label, out ConfigGamepadInputId lStickButton);
|
|
Enum.TryParse(_minus.Label, out ConfigGamepadInputId lButtonMinus);
|
|
Enum.TryParse(_l.Label, out ConfigGamepadInputId lButtonL);
|
|
Enum.TryParse(_zL.Label, out ConfigGamepadInputId lButtonZl);
|
|
Enum.TryParse(_lSl.Label, out ConfigGamepadInputId lButtonSl);
|
|
Enum.TryParse(_lSr.Label, out ConfigGamepadInputId lButtonSr);
|
|
Enum.TryParse(_dpadUp.Label, out ConfigGamepadInputId lDPadUp);
|
|
Enum.TryParse(_dpadDown.Label, out ConfigGamepadInputId lDPadDown);
|
|
Enum.TryParse(_dpadLeft.Label, out ConfigGamepadInputId lDPadLeft);
|
|
Enum.TryParse(_dpadRight.Label, out ConfigGamepadInputId lDPadRight);
|
|
|
|
Enum.TryParse(_rStick.Label, out ConfigStickInputId rStick);
|
|
Enum.TryParse(_rStickButton.Label, out ConfigGamepadInputId rStickButton);
|
|
Enum.TryParse(_a.Label, out ConfigGamepadInputId rButtonA);
|
|
Enum.TryParse(_b.Label, out ConfigGamepadInputId rButtonB);
|
|
Enum.TryParse(_x.Label, out ConfigGamepadInputId rButtonX);
|
|
Enum.TryParse(_y.Label, out ConfigGamepadInputId rButtonY);
|
|
Enum.TryParse(_plus.Label, out ConfigGamepadInputId rButtonPlus);
|
|
Enum.TryParse(_r.Label, out ConfigGamepadInputId rButtonR);
|
|
Enum.TryParse(_zR.Label, out ConfigGamepadInputId rButtonZr);
|
|
Enum.TryParse(_rSl.Label, out ConfigGamepadInputId rButtonSl);
|
|
Enum.TryParse(_rSr.Label, out ConfigGamepadInputId rButtonSr);
|
|
|
|
int.TryParse(_dsuServerPort.Buffer.Text, out int port);
|
|
#pragma warning restore CA1806, IDE0055
|
|
|
|
MotionConfigController motionConfig;
|
|
|
|
if (_enableCemuHook.Active)
|
|
{
|
|
motionConfig = new CemuHookMotionConfigController
|
|
{
|
|
MotionBackend = MotionInputBackendType.CemuHook,
|
|
EnableMotion = _enableMotion.Active,
|
|
Sensitivity = (int)_sensitivity.Value,
|
|
GyroDeadzone = _gyroDeadzone.Value,
|
|
MirrorInput = _mirrorInput.Active,
|
|
Slot = (int)_slotNumber.Value,
|
|
AltSlot = (int)_altSlotNumber.Value,
|
|
DsuServerHost = _dsuServerHost.Buffer.Text,
|
|
DsuServerPort = port,
|
|
};
|
|
}
|
|
else
|
|
{
|
|
motionConfig = new StandardMotionConfigController
|
|
{
|
|
MotionBackend = MotionInputBackendType.GamepadDriver,
|
|
EnableMotion = _enableMotion.Active,
|
|
Sensitivity = (int)_sensitivity.Value,
|
|
GyroDeadzone = _gyroDeadzone.Value,
|
|
};
|
|
}
|
|
|
|
return new StandardControllerInputConfig
|
|
{
|
|
Backend = InputBackendType.GamepadSDL2,
|
|
Version = InputConfig.CurrentVersion,
|
|
Id = _inputDevice.ActiveId.Split("/")[1].Split(" ")[0],
|
|
ControllerType = Enum.Parse<ControllerType>(_controllerType.ActiveId),
|
|
PlayerIndex = _playerIndex,
|
|
DeadzoneLeft = (float)_controllerDeadzoneLeft.Value,
|
|
DeadzoneRight = (float)_controllerDeadzoneRight.Value,
|
|
RangeLeft = (float)_controllerRangeLeft.Value,
|
|
RangeRight = (float)_controllerRangeRight.Value,
|
|
TriggerThreshold = (float)_controllerTriggerThreshold.Value,
|
|
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
|
|
{
|
|
ButtonMinus = lButtonMinus,
|
|
ButtonL = lButtonL,
|
|
ButtonZl = lButtonZl,
|
|
ButtonSl = lButtonSl,
|
|
ButtonSr = lButtonSr,
|
|
DpadUp = lDPadUp,
|
|
DpadDown = lDPadDown,
|
|
DpadLeft = lDPadLeft,
|
|
DpadRight = lDPadRight,
|
|
},
|
|
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
|
{
|
|
InvertStickX = _invertLStickX.Active,
|
|
Joystick = lStick,
|
|
InvertStickY = _invertLStickY.Active,
|
|
StickButton = lStickButton,
|
|
Rotate90CW = _rotateL90CW.Active,
|
|
},
|
|
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
|
{
|
|
ButtonA = rButtonA,
|
|
ButtonB = rButtonB,
|
|
ButtonX = rButtonX,
|
|
ButtonY = rButtonY,
|
|
ButtonPlus = rButtonPlus,
|
|
ButtonR = rButtonR,
|
|
ButtonZr = rButtonZr,
|
|
ButtonSl = rButtonSl,
|
|
ButtonSr = rButtonSr,
|
|
},
|
|
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
|
{
|
|
InvertStickX = _invertRStickX.Active,
|
|
Joystick = rStick,
|
|
InvertStickY = _invertRStickY.Active,
|
|
StickButton = rStickButton,
|
|
Rotate90CW = _rotateR90CW.Active,
|
|
},
|
|
Motion = motionConfig,
|
|
Rumble = new RumbleConfigController
|
|
{
|
|
StrongRumble = (float)_controllerStrongRumble.Value,
|
|
WeakRumble = (float)_controllerWeakRumble.Value,
|
|
EnableRumble = _enableRumble.Active,
|
|
},
|
|
};
|
|
}
|
|
|
|
if (!_inputDevice.ActiveId.StartsWith("disabled"))
|
|
{
|
|
GtkDialog.CreateErrorDialog("Invalid data detected in one or more fields; the configuration was not saved.");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private string GetProfileBasePath()
|
|
{
|
|
if (_inputDevice.ActiveId.StartsWith("keyboard"))
|
|
{
|
|
return System.IO.Path.Combine(AppDataManager.ProfilesDirPath, "keyboard");
|
|
}
|
|
else if (_inputDevice.ActiveId.StartsWith("controller"))
|
|
{
|
|
return System.IO.Path.Combine(AppDataManager.ProfilesDirPath, "controller");
|
|
}
|
|
|
|
return AppDataManager.ProfilesDirPath;
|
|
}
|
|
|
|
//
|
|
// Events
|
|
//
|
|
private void InputDevice_Changed(object sender, EventArgs args)
|
|
{
|
|
SetAvailableOptions();
|
|
SetControllerSpecificFields();
|
|
|
|
_selectedGamepad?.Dispose();
|
|
_selectedGamepad = null;
|
|
|
|
if (_inputDevice.ActiveId != null)
|
|
{
|
|
SetProfiles();
|
|
|
|
string id = GetCurrentGamepadId();
|
|
|
|
if (_inputDevice.ActiveId.StartsWith("keyboard"))
|
|
{
|
|
if (_inputConfig is StandardKeyboardInputConfig)
|
|
{
|
|
SetValues(_inputConfig);
|
|
}
|
|
|
|
if (_mainWindow.InputManager.KeyboardDriver is GTK3KeyboardDriver)
|
|
{
|
|
// 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 = _gtk3KeyboardDriver.GetGamepad(id);
|
|
}
|
|
else
|
|
{
|
|
_selectedGamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
|
|
}
|
|
}
|
|
else if (_inputDevice.ActiveId.StartsWith("controller"))
|
|
{
|
|
if (_inputConfig is StandardControllerInputConfig)
|
|
{
|
|
SetValues(_inputConfig);
|
|
}
|
|
|
|
_selectedGamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
private string GetCurrentGamepadId()
|
|
{
|
|
if (_inputDevice.ActiveId == null || _inputDevice.ActiveId == "disabled")
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return _inputDevice.ActiveId.Split("/")[1].Split(" ")[0];
|
|
}
|
|
|
|
private void Controller_Changed(object sender, EventArgs args)
|
|
{
|
|
SetControllerSpecificFields();
|
|
}
|
|
|
|
private IButtonAssigner CreateButtonAssigner(bool forStick)
|
|
{
|
|
IButtonAssigner assigner;
|
|
|
|
if (_inputDevice.ActiveId.StartsWith("keyboard"))
|
|
{
|
|
assigner = new KeyboardKeyAssigner((IKeyboard)_selectedGamepad);
|
|
}
|
|
else if (_inputDevice.ActiveId.StartsWith("controller"))
|
|
{
|
|
assigner = new GamepadButtonAssigner(_selectedGamepad, (float)_controllerTriggerThreshold.Value, forStick);
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("Controller not supported");
|
|
}
|
|
|
|
return assigner;
|
|
}
|
|
|
|
private void HandleButtonPressed(ToggleButton button, bool forStick)
|
|
{
|
|
if (_isWaitingForInput)
|
|
{
|
|
button.Active = false;
|
|
|
|
return;
|
|
}
|
|
|
|
_mousePressed = false;
|
|
|
|
ButtonPressEvent += MouseClick;
|
|
|
|
IButtonAssigner assigner = CreateButtonAssigner(forStick);
|
|
|
|
_isWaitingForInput = true;
|
|
|
|
// Open GTK3 keyboard for cancel operations
|
|
IKeyboard keyboard = (IKeyboard)_gtk3KeyboardDriver.GetGamepad("0");
|
|
|
|
Thread inputThread = new(() =>
|
|
{
|
|
assigner.Initialize();
|
|
|
|
while (true)
|
|
{
|
|
Thread.Sleep(10);
|
|
assigner.ReadInput();
|
|
|
|
if (_mousePressed || keyboard.IsPressed(Ryujinx.Input.Key.Escape) || assigner.HasAnyButtonPressed() || assigner.ShouldCancel())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
string pressedButton = assigner.GetPressedButton();
|
|
|
|
Application.Invoke(delegate
|
|
{
|
|
if (_middleMousePressed)
|
|
{
|
|
button.Label = "Unbound";
|
|
}
|
|
else if (pressedButton != "")
|
|
{
|
|
button.Label = pressedButton;
|
|
}
|
|
|
|
_middleMousePressed = false;
|
|
|
|
ButtonPressEvent -= MouseClick;
|
|
keyboard.Dispose();
|
|
|
|
button.Active = false;
|
|
_isWaitingForInput = false;
|
|
});
|
|
})
|
|
{
|
|
Name = "GUI.InputThread",
|
|
IsBackground = true,
|
|
};
|
|
inputThread.Start();
|
|
}
|
|
|
|
private void Button_Pressed(object sender, EventArgs args)
|
|
{
|
|
HandleButtonPressed((ToggleButton)sender, false);
|
|
}
|
|
|
|
private void ButtonForStick_Pressed(object sender, EventArgs args)
|
|
{
|
|
HandleButtonPressed((ToggleButton)sender, true);
|
|
}
|
|
|
|
private void MouseClick(object sender, ButtonPressEventArgs args)
|
|
{
|
|
_mousePressed = true;
|
|
_middleMousePressed = args.Event.Button == 2;
|
|
}
|
|
|
|
private void SetProfiles()
|
|
{
|
|
_profile.RemoveAll();
|
|
|
|
string basePath = GetProfileBasePath();
|
|
|
|
if (!Directory.Exists(basePath))
|
|
{
|
|
Directory.CreateDirectory(basePath);
|
|
}
|
|
|
|
if (_inputDevice.ActiveId == null || _inputDevice.ActiveId.Equals("disabled"))
|
|
{
|
|
_profile.Append("default", "None");
|
|
}
|
|
else
|
|
{
|
|
_profile.Append("default", "Default");
|
|
|
|
foreach (string profile in Directory.GetFiles(basePath, "*.*", SearchOption.AllDirectories))
|
|
{
|
|
_profile.Append(System.IO.Path.GetFileName(profile), System.IO.Path.GetFileNameWithoutExtension(profile));
|
|
}
|
|
}
|
|
|
|
_profile.SetActiveId("default");
|
|
}
|
|
|
|
private void ProfileLoad_Activated(object sender, EventArgs args)
|
|
{
|
|
((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
|
|
|
|
if (_inputDevice.ActiveId == "disabled" || _profile.ActiveId == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
InputConfig config = null;
|
|
int pos = _profile.Active;
|
|
|
|
if (_profile.ActiveId == "default")
|
|
{
|
|
if (_inputDevice.ActiveId.StartsWith("keyboard"))
|
|
{
|
|
config = new StandardKeyboardInputConfig
|
|
{
|
|
Version = InputConfig.CurrentVersion,
|
|
Backend = InputBackendType.WindowKeyboard,
|
|
Id = null,
|
|
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 (_inputDevice.ActiveId.StartsWith("controller"))
|
|
{
|
|
config = new StandardControllerInputConfig
|
|
{
|
|
Version = InputConfig.CurrentVersion,
|
|
Backend = InputBackendType.GamepadSDL2,
|
|
Id = null,
|
|
ControllerType = ControllerType.JoyconPair,
|
|
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,
|
|
Rotate90CW = false,
|
|
},
|
|
|
|
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
|
{
|
|
ButtonA = ConfigGamepadInputId.B,
|
|
ButtonB = ConfigGamepadInputId.A,
|
|
ButtonX = ConfigGamepadInputId.Y,
|
|
ButtonY = 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,
|
|
Rotate90CW = false,
|
|
},
|
|
|
|
Motion = new StandardMotionConfigController
|
|
{
|
|
MotionBackend = MotionInputBackendType.GamepadDriver,
|
|
EnableMotion = true,
|
|
Sensitivity = 100,
|
|
GyroDeadzone = 1,
|
|
},
|
|
Rumble = new RumbleConfigController
|
|
{
|
|
StrongRumble = 1f,
|
|
WeakRumble = 1f,
|
|
EnableRumble = false,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
string path = System.IO.Path.Combine(GetProfileBasePath(), _profile.ActiveId);
|
|
|
|
if (!File.Exists(path))
|
|
{
|
|
if (pos >= 0)
|
|
{
|
|
_profile.Remove(pos);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
|
|
}
|
|
catch (JsonException) { }
|
|
}
|
|
|
|
SetValues(config);
|
|
}
|
|
|
|
private void ProfileAdd_Activated(object sender, EventArgs args)
|
|
{
|
|
((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
|
|
|
|
if (_inputDevice.ActiveId == "disabled")
|
|
{
|
|
return;
|
|
}
|
|
|
|
InputConfig inputConfig = GetValues();
|
|
ProfileDialog profileDialog = new();
|
|
|
|
if (inputConfig == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (profileDialog.Run() == (int)ResponseType.Ok)
|
|
{
|
|
string path = System.IO.Path.Combine(GetProfileBasePath(), profileDialog.FileName);
|
|
string jsonString = JsonHelper.Serialize(inputConfig, _serializerContext.InputConfig);
|
|
|
|
File.WriteAllText(path, jsonString);
|
|
}
|
|
|
|
profileDialog.Dispose();
|
|
|
|
SetProfiles();
|
|
}
|
|
|
|
private void ProfileRemove_Activated(object sender, EventArgs args)
|
|
{
|
|
((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
|
|
|
|
if (_inputDevice.ActiveId == "disabled" || _profile.ActiveId == "default" || _profile.ActiveId == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
MessageDialog confirmDialog = GtkDialog.CreateConfirmationDialog("Deleting Profile", "This action is irreversible, are you sure you want to continue?");
|
|
|
|
if (confirmDialog.Run() == (int)ResponseType.Yes)
|
|
{
|
|
string path = System.IO.Path.Combine(GetProfileBasePath(), _profile.ActiveId);
|
|
|
|
if (File.Exists(path))
|
|
{
|
|
File.Delete(path);
|
|
}
|
|
|
|
SetProfiles();
|
|
}
|
|
}
|
|
|
|
private void SaveToggle_Activated(object sender, EventArgs args)
|
|
{
|
|
InputConfig inputConfig = GetValues();
|
|
|
|
var newConfig = new List<InputConfig>();
|
|
newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value);
|
|
|
|
if (_inputConfig == null && inputConfig != null)
|
|
{
|
|
newConfig.Add(inputConfig);
|
|
}
|
|
else
|
|
{
|
|
if (_inputDevice.ActiveId == "disabled")
|
|
{
|
|
newConfig.Remove(_inputConfig);
|
|
}
|
|
else if (inputConfig != null)
|
|
{
|
|
int index = newConfig.IndexOf(_inputConfig);
|
|
|
|
newConfig[index] = inputConfig;
|
|
}
|
|
}
|
|
|
|
_mainWindow.RendererWidget?.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);
|
|
|
|
Dispose();
|
|
}
|
|
|
|
private void CloseToggle_Activated(object sender, EventArgs args)
|
|
{
|
|
Dispose();
|
|
}
|
|
}
|
|
}
|