Improved assignment logic in AutoAssignController.cs
This commit is contained in:
parent
62dfbb5dcb
commit
8cc74dab08
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.Models.Input;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ava.Utilities.Configuration;
|
using Ryujinx.Ava.Utilities.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
@ -62,78 +63,158 @@ namespace Ryujinx.Ava.Input
|
|||||||
{
|
{
|
||||||
if (!_configurationState.Hid.EnableAutoAssign) return;
|
if (!_configurationState.Hid.EnableAutoAssign) return;
|
||||||
|
|
||||||
// Get every controller config and update the configuration state
|
|
||||||
List<IGamepad> controllers = _inputManager.GamepadDriver.GetGamepads().ToList();
|
List<IGamepad> controllers = _inputManager.GamepadDriver.GetGamepads().ToList();
|
||||||
List<InputConfig> oldConfig = _configurationState.Hid.InputConfig.Value.Where(x => x != null).ToList();
|
List<InputConfig> oldConfig = _configurationState.Hid.InputConfig.Value.Where(x => x != null).ToList();
|
||||||
|
|
||||||
(List<InputConfig> newConfig, bool hasNewControllersConnected) = GetOrderedConfig(controllers, oldConfig);
|
(List<InputConfig> newConfig, bool hasNewControllersConnected) = GetOrderedConfig(controllers, oldConfig);
|
||||||
|
|
||||||
_viewModel.AppHost?.NpadManager.ReloadConfiguration(newConfig, _configurationState.Hid.EnableKeyboard, _configurationState.Hid.EnableMouse);
|
_viewModel.AppHost?.NpadManager.ReloadConfiguration(newConfig, _configurationState.Hid.EnableKeyboard, _configurationState.Hid.EnableMouse);
|
||||||
|
|
||||||
// update the configuration state only if there are new controllers connected
|
if (hasNewControllersConnected)
|
||||||
if(hasNewControllersConnected)
|
|
||||||
{
|
{
|
||||||
_configurationState.Hid.InputConfig.Value = newConfig;
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we must switch the order of the controllers in oldConfig to match the new order
|
||||||
|
newConfig = ReorderControllers(newConfig, oldConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
_configurationState.Hid.InputConfig.Value = newConfig;
|
||||||
ConfigurationUpdated?.Invoke();
|
ConfigurationUpdated?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures that the order of controllers remains the same unless a new controller is connected.
|
||||||
|
/// </summary>
|
||||||
|
private List<InputConfig> ReorderControllers(List<InputConfig> newConfig, List<InputConfig> oldConfig)
|
||||||
|
{
|
||||||
|
List<InputConfig> reorderedConfig = oldConfig.Select(config => new GamepadInputConfig(config).GetConfig()).ToList();
|
||||||
|
|
||||||
|
foreach (var config in newConfig)
|
||||||
|
{
|
||||||
|
InputConfig substitute = reorderedConfig.FirstOrDefault(x => x.Id == config.Id);
|
||||||
|
InputConfig toBeReplaced = reorderedConfig.FirstOrDefault(x => x.PlayerIndex == config.PlayerIndex);
|
||||||
|
|
||||||
|
if (substitute == null || toBeReplaced == null || substitute.PlayerIndex == toBeReplaced.PlayerIndex) continue;
|
||||||
|
|
||||||
|
(substitute.PlayerIndex, toBeReplaced.PlayerIndex) = (toBeReplaced.PlayerIndex, substitute.PlayerIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reorderedConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Orders controllers, preserving existing mappings while assigning new controllers to available slots.
|
||||||
|
/// </summary>
|
||||||
private (List<InputConfig>, bool) GetOrderedConfig(List<IGamepad> controllers, List<InputConfig> oldConfig)
|
private (List<InputConfig>, bool) GetOrderedConfig(List<IGamepad> controllers, List<InputConfig> oldConfig)
|
||||||
{
|
{
|
||||||
Dictionary<string, InputConfig> oldConfigMap = oldConfig.Where(c => c?.Id != null).ToDictionary(x => x.Id);
|
Dictionary<string, InputConfig> oldConfigMap = oldConfig.Where(c => c?.Id != null)
|
||||||
|
.ToDictionary(x => x.Id);
|
||||||
|
|
||||||
Dictionary<int, InputConfig> playerIndexMap = new();
|
Dictionary<int, InputConfig> playerIndexMap = new();
|
||||||
HashSet<int> usedIndices = new();
|
HashSet<int> usedIndices = new();
|
||||||
int recognizedControllersCount = 0;
|
int recognizedControllersCount = 0;
|
||||||
|
|
||||||
// Assign controllers that have an old config
|
|
||||||
List<IGamepad> remainingControllers = controllers.Where(c => c?.Id != null).ToList();
|
List<IGamepad> remainingControllers = controllers.Where(c => c?.Id != null).ToList();
|
||||||
foreach (var controller in remainingControllers.ToList())
|
|
||||||
|
// Assign controllers that have an existing configuration
|
||||||
|
AssignExistingControllers(remainingControllers, oldConfigMap, playerIndexMap, usedIndices, ref recognizedControllersCount);
|
||||||
|
|
||||||
|
// Assign new controllers
|
||||||
|
AssignNewControllers(remainingControllers, playerIndexMap, usedIndices);
|
||||||
|
|
||||||
|
List<InputConfig> orderedConfigs = playerIndexMap.OrderBy(x => x.Key).Select(x => x.Value).ToList();
|
||||||
|
|
||||||
|
// Sequentially update PlayerIndex and LED colors
|
||||||
|
UpdatePlayerIndicesAndLEDs(orderedConfigs);
|
||||||
|
|
||||||
|
bool hasNewControllersConnected = controllers.Count > recognizedControllersCount;
|
||||||
|
return (orderedConfigs, hasNewControllersConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assigns controllers with existing configurations while keeping their PlayerIndex if available.
|
||||||
|
/// </summary>
|
||||||
|
private void AssignExistingControllers(
|
||||||
|
List<IGamepad> controllers,
|
||||||
|
Dictionary<string, InputConfig> oldConfigMap,
|
||||||
|
Dictionary<int, InputConfig> playerIndexMap,
|
||||||
|
HashSet<int> usedIndices,
|
||||||
|
ref int recognizedControllersCount)
|
||||||
|
{
|
||||||
|
foreach (var controller in controllers.ToList())
|
||||||
{
|
{
|
||||||
if (oldConfigMap.TryGetValue(controller.Id, out InputConfig existingConfig))
|
if (oldConfigMap.TryGetValue(controller.Id, out InputConfig existingConfig))
|
||||||
{
|
{
|
||||||
int desiredIndex = (int)existingConfig.PlayerIndex;
|
int desiredIndex = (int)existingConfig.PlayerIndex;
|
||||||
// Check if the desired index is valid and available
|
|
||||||
|
// Ensure the index is valid and available
|
||||||
if (desiredIndex < 0 || desiredIndex >= MaxControllers || usedIndices.Contains(desiredIndex))
|
if (desiredIndex < 0 || desiredIndex >= MaxControllers || usedIndices.Contains(desiredIndex))
|
||||||
{
|
{
|
||||||
// Find the first available index
|
desiredIndex = GetFirstAvailableIndex(usedIndices);
|
||||||
desiredIndex = Enumerable.Range(0, MaxControllers).First(i => !usedIndices.Contains(i));
|
|
||||||
}
|
}
|
||||||
existingConfig.PlayerIndex = (PlayerIndex)desiredIndex;
|
|
||||||
|
InputConfig config = new GamepadInputConfig(existingConfig).GetConfig();
|
||||||
|
config.PlayerIndex = (PlayerIndex)desiredIndex;
|
||||||
usedIndices.Add(desiredIndex);
|
usedIndices.Add(desiredIndex);
|
||||||
playerIndexMap[desiredIndex] = existingConfig;
|
playerIndexMap[desiredIndex] = config;
|
||||||
recognizedControllersCount++;
|
recognizedControllersCount++;
|
||||||
|
|
||||||
remainingControllers.Remove(controller);
|
controllers.Remove(controller);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign remaining (new) controllers
|
/// <summary>
|
||||||
foreach (var controller in remainingControllers.OrderBy(c => c.Id))
|
/// Assigns new controllers to the first available PlayerIndex.
|
||||||
|
/// </summary>
|
||||||
|
private void AssignNewControllers(
|
||||||
|
List<IGamepad> controllers,
|
||||||
|
Dictionary<int, InputConfig> playerIndexMap,
|
||||||
|
HashSet<int> usedIndices)
|
||||||
|
{
|
||||||
|
foreach (var controller in controllers)
|
||||||
{
|
{
|
||||||
InputConfig config = CreateConfigFromController(controller);
|
InputConfig config = CreateConfigFromController(controller);
|
||||||
int freeIndex = Enumerable.Range(0, MaxControllers).First(i => !usedIndices.Contains(i));
|
int freeIndex = GetFirstAvailableIndex(usedIndices);
|
||||||
config.PlayerIndex = (PlayerIndex)freeIndex;
|
config.PlayerIndex = (PlayerIndex)freeIndex;
|
||||||
usedIndices.Add(freeIndex);
|
usedIndices.Add(freeIndex);
|
||||||
playerIndexMap[freeIndex] = config;
|
playerIndexMap[freeIndex] = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<InputConfig> orderedConfigs = playerIndexMap.OrderBy(x => x.Key).Select(x => x.Value).ToList();
|
|
||||||
|
|
||||||
// Sequential reassignment of PlayerIndex and LED colors
|
|
||||||
int index = 0;
|
|
||||||
foreach (var config in orderedConfigs)
|
|
||||||
{
|
|
||||||
config.PlayerIndex = (PlayerIndex)index;
|
|
||||||
if (config is StandardControllerInputConfig standardConfig)
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Setting color for Player{index+1}");
|
|
||||||
standardConfig.Led = new LedConfigController { EnableLed = true, LedColor = _playerColors[index] };
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasNewControllersConnected = (controllers.Count > recognizedControllersCount);
|
/// <summary>
|
||||||
return (orderedConfigs, hasNewControllersConnected);
|
/// Finds the first available PlayerIndex that isn't in use.
|
||||||
|
/// </summary>
|
||||||
|
private int GetFirstAvailableIndex(HashSet<int> usedIndices)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MaxControllers; i++)
|
||||||
|
{
|
||||||
|
if (!usedIndices.Contains(i)) return i;
|
||||||
|
}
|
||||||
|
return -1; // Should not happen unless MaxControllers is exceeded
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates PlayerIndex and LED configurations sequentially.
|
||||||
|
/// </summary>
|
||||||
|
private void UpdatePlayerIndicesAndLEDs(List<InputConfig> orderedConfigs)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < orderedConfigs.Count; index++)
|
||||||
|
{
|
||||||
|
orderedConfigs[index].PlayerIndex = (PlayerIndex)index;
|
||||||
|
|
||||||
|
if (orderedConfigs[index] is StandardControllerInputConfig standardConfig)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Application, $"Setting color for Player{index + 1}");
|
||||||
|
standardConfig.Led = new LedConfigController
|
||||||
|
{
|
||||||
|
EnableLed = true,
|
||||||
|
LedColor = _playerColors[index]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputConfig CreateConfigFromController(IGamepad controller)
|
private static InputConfig CreateConfigFromController(IGamepad controller)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user