Controller Input handling refactoring (#1751)

* This should fix issue #1374 in Linux

Changes:
- Bind buttons by detecting the transition from down to up.
- Bind axis by detecting movement from value higher than 50% to a value lower than 50%.

Caveats:
- I have tested only with DS3 in Linux (Fedora 32).
- ZL and ZR detection works by accident. This code doesn't take negative axis into account.
  The reason it works is because axis are managed in absolute value. So when pressing ZL/ZR
  axis value goes from -1 to 1 (or 1 to 0 and back to 1) and this hits the axis detector.
- Likely I have broken all the other controllers xD (testing needed).

* Assign keyboardPressed

* Make a more robust detection of pressed buttons when using a controller

* Add interface to bind buttons from Joystick and Keyboard

* Fix style issues after code review by @AcK77  (Thanks!)

* Move new classes to Ryujinx.Ui.Input namespace

* Use explicit types instead of var

* Update Ryujinx/Ui/Input/JoystickButtonAssigner.cs

Co-authored-by: Mary <thog@protonmail.com>

* Update Ryujinx/Ui/Input/JoystickButtonAssigner.cs

Co-authored-by: Mary <thog@protonmail.com>

* Update Ryujinx/Ui/Input/JoystickButtonAssigner.cs

Co-authored-by: Mary <thog@protonmail.com>

* Update Ryujinx/Ui/Input/JoystickButtonAssigner.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Add a new empty line before

* Up

Co-authored-by: Jose Padilla <jose@prensalink.com>
Co-authored-by: Mary <thog@protonmail.com>
Co-authored-by: Ac_K <Acoustik666@gmail.com>
This commit is contained in:
Jose Padilla 2021-02-21 00:22:55 +01:00 committed by GitHub
parent d5081e3f93
commit ad7d22777f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 344 additions and 116 deletions

View file

@ -4,6 +4,7 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Utilities;
using Ryujinx.Configuration;
using Ryujinx.Ui.Input;
using Ryujinx.Ui.Widgets;
using System;
using System.Collections.Generic;
@ -584,73 +585,6 @@ namespace Ryujinx.Ui.Windows
return null;
}
private static bool IsAnyKeyPressed(out Key pressedKey, int index)
{
KeyboardState keyboardState = KeyboardController.GetKeyboardState(index);
foreach (Key key in Enum.GetValues(typeof(Key)))
{
if (keyboardState.IsKeyDown((OpenTK.Input.Key)key))
{
pressedKey = key;
return true;
}
}
pressedKey = Key.Unbound;
return false;
}
private static bool IsAnyButtonPressed(out ControllerInputId pressedButton, int index, double triggerThreshold)
{
JoystickState joystickState = Joystick.GetState(index);
JoystickCapabilities joystickCapabilities = Joystick.GetCapabilities(index);
//Buttons
for (int i = 0; i != joystickCapabilities.ButtonCount; i++)
{
if (joystickState.IsButtonDown(i))
{
Enum.TryParse($"Button{i}", out pressedButton);
return true;
}
}
//Axis
for (int i = 0; i != joystickCapabilities.AxisCount; i++)
{
if (joystickState.GetAxis(i) > 0.5f && joystickState.GetAxis(i) > triggerThreshold)
{
Enum.TryParse($"Axis{i}", out pressedButton);
return true;
}
}
//Hats
for (int i = 0; i != joystickCapabilities.HatCount; i++)
{
JoystickHatState hatState = joystickState.GetHat((JoystickHat)i);
string pos = null;
if (hatState.IsUp) pos = "Up";
if (hatState.IsDown) pos = "Down";
if (hatState.IsLeft) pos = "Left";
if (hatState.IsRight) pos = "Right";
if (pos == null) continue;
Enum.TryParse($"Hat{i}{pos}", out pressedButton);
return true;
}
pressedButton = ControllerInputId.Unbound;
return false;
}
private string GetProfileBasePath()
{
string path = AppDataManager.ProfilesDirPath;
@ -690,6 +624,31 @@ namespace Ryujinx.Ui.Windows
_refreshInputDevicesButton.SetStateFlags(StateFlags.Normal, true);
}
private ButtonAssigner CreateButtonAssigner()
{
int index = int.Parse(_inputDevice.ActiveId.Split("/")[1]);
ButtonAssigner assigner;
if (_inputDevice.ActiveId.StartsWith("keyboard"))
{
assigner = new KeyboardKeyAssigner(index);
}
else if (_inputDevice.ActiveId.StartsWith("controller"))
{
// TODO: triggerThresold is passed but not used by JoystickButtonAssigner. Should it be used for key binding?.
// Note that, like left and right sticks, ZL and ZR triggers are treated as axis.
// The problem is then how to decide which axis should use triggerThresold.
assigner = new JoystickButtonAssigner(index, _controllerTriggerThreshold.Value);
}
else
{
throw new Exception("Controller not supported");
}
return assigner;
}
private void Button_Pressed(object sender, EventArgs args)
{
if (_isWaitingForInput)
@ -697,67 +656,41 @@ namespace Ryujinx.Ui.Windows
return;
}
ButtonAssigner assigner = CreateButtonAssigner();
_isWaitingForInput = true;
Thread inputThread = new Thread(() =>
{
Button button = (ToggleButton)sender;
assigner.Init();
if (_inputDevice.ActiveId.StartsWith("keyboard"))
while (true)
{
Key pressedKey;
Thread.Sleep(10);
assigner.ReadInput();
int index = int.Parse(_inputDevice.ActiveId.Split("/")[1]);
while (!IsAnyKeyPressed(out pressedKey, index))
if (assigner.HasAnyButtonPressed() || assigner.ShouldCancel())
{
if (Mouse.GetState().IsAnyButtonDown || Keyboard.GetState().IsKeyDown(OpenTK.Input.Key.Escape))
{
Application.Invoke(delegate
{
button.SetStateFlags(StateFlags.Normal, true);
});
_isWaitingForInput = false;
return;
}
break;
}
Application.Invoke(delegate
{
button.Label = pressedKey.ToString();
button.SetStateFlags(StateFlags.Normal, true);
});
}
else if (_inputDevice.ActiveId.StartsWith("controller"))
{
ControllerInputId pressedButton;
int index = int.Parse(_inputDevice.ActiveId.Split("/")[1]);
while (!IsAnyButtonPressed(out pressedButton, index, _controllerTriggerThreshold.Value))
{
if (Mouse.GetState().IsAnyButtonDown || Keyboard.GetState().IsAnyKeyDown)
{
Application.Invoke(delegate
{
button.SetStateFlags(StateFlags.Normal, true);
});
_isWaitingForInput = false;
return;
}
}
Application.Invoke(delegate
{
button.Label = pressedButton.ToString();
button.SetStateFlags(StateFlags.Normal, true);
});
}
_isWaitingForInput = false;
string pressedButton = assigner.GetPressedButton();
ToggleButton button = (ToggleButton) sender;
Application.Invoke(delegate
{
if (pressedButton != "")
{
button.Label = pressedButton;
}
button.Active = false;
_isWaitingForInput = false;
});
});
inputThread.Name = "GUI.InputThread";
inputThread.IsBackground = true;
inputThread.Start();