mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-08-03 02:37:12 +02:00
Improve multi-controller support in HID and Controller Applet (#1453)
* Initial commit Enable proper LED patterns Toggle Hotkeys only on focus Ignore Handheld on Docked mode Remove PrimaryController Validate NpadIdType Rewrite NpadDevices to process config in update loop Cleanup * Notify in log periodically when no matched controllers * Remove duplicate StructArrayHelpers in favor of Common.Memory Fix struct padding CS0169 warns in Touchscreen * Remove GTK markup from Controller Applet Use IList instead of List Explicit list capacity in 1ms loop Fix formatting * Restrict ControllerWindow to show valid controller types Add selected player name to ControllerWindow title * ControllerWindow: Fix controller type initial value NpadDevices: Simplify default battery charge * Address AcK's comments Use explicit types and fix formatting * Remove HashSet for SupportedPlayers Fixes potential exceptions due to race * Fix ControllerSupportArg struct packing Also comes with two revisions of struct for 4/8 players max.
This commit is contained in:
parent
da0fad24e8
commit
ff9e84299f
29 changed files with 445 additions and 242 deletions
|
@ -5,6 +5,7 @@ using Ryujinx.Common.Utilities;
|
|||
using Ryujinx.Configuration;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
|
@ -91,6 +92,23 @@ namespace Ryujinx.Ui
|
|||
_virtualFileSystem = virtualFileSystem;
|
||||
_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
|
||||
_lStickX.Clicked += Button_Pressed;
|
||||
_lStickY.Clicked += Button_Pressed;
|
||||
|
@ -278,7 +296,12 @@ namespace Ryujinx.Ui
|
|||
switch (config)
|
||||
{
|
||||
case KeyboardConfig keyboardConfig:
|
||||
_controllerType.SetActiveId(keyboardConfig.ControllerType.ToString());
|
||||
if (!_controllerType.SetActiveId(keyboardConfig.ControllerType.ToString()))
|
||||
{
|
||||
_controllerType.SetActiveId(_playerIndex == PlayerIndex.Handheld
|
||||
? ControllerType.Handheld.ToString()
|
||||
: ControllerType.ProController.ToString());
|
||||
}
|
||||
|
||||
_lStickUp.Label = keyboardConfig.LeftJoycon.StickUp.ToString();
|
||||
_lStickDown.Label = keyboardConfig.LeftJoycon.StickDown.ToString();
|
||||
|
@ -310,7 +333,12 @@ namespace Ryujinx.Ui
|
|||
_rSr.Label = keyboardConfig.RightJoycon.ButtonSr.ToString();
|
||||
break;
|
||||
case ControllerConfig controllerConfig:
|
||||
_controllerType.SetActiveId(controllerConfig.ControllerType.ToString());
|
||||
if (!_controllerType.SetActiveId(controllerConfig.ControllerType.ToString()))
|
||||
{
|
||||
_controllerType.SetActiveId(_playerIndex == PlayerIndex.Handheld
|
||||
? ControllerType.Handheld.ToString()
|
||||
: ControllerType.ProController.ToString());
|
||||
}
|
||||
|
||||
_lStickX.Label = controllerConfig.LeftJoycon.StickX.ToString();
|
||||
_invertLStickX.Active = controllerConfig.LeftJoycon.InvertStickX;
|
||||
|
@ -894,24 +922,31 @@ namespace Ryujinx.Ui
|
|||
{
|
||||
InputConfig inputConfig = GetValues();
|
||||
|
||||
var newConfig = new List<InputConfig>();
|
||||
newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value);
|
||||
|
||||
if (_inputConfig == null && inputConfig != null)
|
||||
{
|
||||
ConfigurationState.Instance.Hid.InputConfig.Value.Add(inputConfig);
|
||||
newConfig.Add(inputConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_inputDevice.ActiveId == "disabled")
|
||||
{
|
||||
ConfigurationState.Instance.Hid.InputConfig.Value.Remove(_inputConfig);
|
||||
newConfig.Remove(_inputConfig);
|
||||
}
|
||||
else if (inputConfig != null)
|
||||
{
|
||||
int index = ConfigurationState.Instance.Hid.InputConfig.Value.IndexOf(_inputConfig);
|
||||
int index = newConfig.IndexOf(_inputConfig);
|
||||
|
||||
ConfigurationState.Instance.Hid.InputConfig.Value[index] = inputConfig;
|
||||
newConfig[index] = inputConfig;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
MainWindow.SaveConfig();
|
||||
|
||||
Dispose();
|
||||
|
|
|
@ -138,13 +138,6 @@
|
|||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">The controller's type</property>
|
||||
<property name="active">0</property>
|
||||
<items>
|
||||
<item id="Handheld" translatable="yes">Handheld</item>
|
||||
<item id="ProController" translatable="yes">Pro Controller</item>
|
||||
<item id="JoyconPair" translatable="yes">Paired Joycons</item>
|
||||
<item id="JoyconLeft" translatable="yes">Left Joycon</item>
|
||||
<item id="JoyconRight" translatable="yes">Right Joycon</item>
|
||||
</items>
|
||||
<signal name="changed" handler="Controller_Changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
|
|
|
@ -405,9 +405,9 @@ namespace Ryujinx.Ui
|
|||
});
|
||||
}
|
||||
|
||||
List<GamepadInput> gamepadInputs = new List<GamepadInput>();
|
||||
List<GamepadInput> gamepadInputs = new List<GamepadInput>(NpadDevices.MaxControllers);
|
||||
|
||||
foreach (InputConfig inputConfig in ConfigurationState.Instance.Hid.InputConfig.Value.ToArray())
|
||||
foreach (InputConfig inputConfig in ConfigurationState.Instance.Hid.InputConfig.Value)
|
||||
{
|
||||
ControllerKeys currentButton = 0;
|
||||
JoystickPosition leftJoystick = new JoystickPosition();
|
||||
|
@ -497,18 +497,21 @@ namespace Ryujinx.Ui
|
|||
});
|
||||
}
|
||||
|
||||
_device.Hid.Npads.SetGamepadsInput(gamepadInputs.ToArray());
|
||||
_device.Hid.Npads.Update(gamepadInputs);
|
||||
|
||||
// Hotkeys
|
||||
HotkeyButtons currentHotkeyButtons = KeyboardController.GetHotkeyButtons(OpenTK.Input.Keyboard.GetState());
|
||||
|
||||
if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) &&
|
||||
!_prevHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync))
|
||||
if(IsFocused)
|
||||
{
|
||||
_device.EnableDeviceVsync = !_device.EnableDeviceVsync;
|
||||
}
|
||||
// Hotkeys
|
||||
HotkeyButtons currentHotkeyButtons = KeyboardController.GetHotkeyButtons(OpenTK.Input.Keyboard.GetState());
|
||||
|
||||
_prevHotkeyButtons = currentHotkeyButtons;
|
||||
if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) &&
|
||||
!_prevHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync))
|
||||
{
|
||||
_device.EnableDeviceVsync = !_device.EnableDeviceVsync;
|
||||
}
|
||||
|
||||
_prevHotkeyButtons = currentHotkeyButtons;
|
||||
}
|
||||
|
||||
//Touchscreen
|
||||
bool hasTouch = false;
|
||||
|
|
|
@ -16,6 +16,62 @@ namespace Ryujinx.Ui
|
|||
_parent = parent;
|
||||
}
|
||||
|
||||
public bool DisplayMessageDialog(ControllerAppletUiArgs args)
|
||||
{
|
||||
string playerCount = args.PlayerCountMin == args.PlayerCountMax
|
||||
? $"exactly {args.PlayerCountMin}"
|
||||
: $"{args.PlayerCountMin}-{args.PlayerCountMax}";
|
||||
|
||||
string message =
|
||||
$"Application requests <b>{playerCount}</b> player(s) with:\n\n"
|
||||
+ $"<tt><b>TYPES:</b> {args.SupportedStyles}</tt>\n\n"
|
||||
+ $"<tt><b>PLAYERS:</b> {string.Join(", ", args.SupportedPlayers)}</tt>\n\n"
|
||||
+ (args.IsDocked ? "Docked mode set. <tt>Handheld</tt> is also invalid.\n\n" : "")
|
||||
+ "<i>Please reconfigure Input now and then press OK.</i>";
|
||||
|
||||
return DisplayMessageDialog("Controller Applet", message);
|
||||
}
|
||||
|
||||
public bool DisplayMessageDialog(string title, string message)
|
||||
{
|
||||
ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);
|
||||
bool okPressed = false;
|
||||
|
||||
Application.Invoke(delegate
|
||||
{
|
||||
MessageDialog msgDialog = null;
|
||||
try
|
||||
{
|
||||
msgDialog = new MessageDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null)
|
||||
{
|
||||
Title = title,
|
||||
Text = message,
|
||||
UseMarkup = true
|
||||
};
|
||||
|
||||
msgDialog.SetDefaultSize(400, 0);
|
||||
|
||||
msgDialog.Response += (object o, ResponseArgs args) =>
|
||||
{
|
||||
if (args.ResponseId == ResponseType.Ok) okPressed = true;
|
||||
dialogCloseEvent.Set();
|
||||
msgDialog?.Dispose();
|
||||
};
|
||||
|
||||
msgDialog.Show();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Error displaying Message Dialog: {e}");
|
||||
dialogCloseEvent.Set();
|
||||
}
|
||||
});
|
||||
|
||||
dialogCloseEvent.WaitOne();
|
||||
|
||||
return okPressed;
|
||||
}
|
||||
|
||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
||||
{
|
||||
ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);
|
||||
|
|
|
@ -507,14 +507,6 @@ namespace Ryujinx.Ui
|
|||
_windowsMultimediaTimerResolution = new WindowsMultimediaTimerResolution(1);
|
||||
}
|
||||
|
||||
device.Hid.Npads.AddControllers(ConfigurationState.Instance.Hid.InputConfig.Value.Select(inputConfig =>
|
||||
new HLE.HOS.Services.Hid.ControllerConfig
|
||||
{
|
||||
Player = (PlayerIndex)inputConfig.PlayerIndex,
|
||||
Type = (ControllerType)inputConfig.ControllerType
|
||||
}
|
||||
).ToArray());
|
||||
|
||||
_glWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
|
||||
|
||||
Application.Invoke(delegate
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue