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.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
@ -61,79 +62,159 @@ namespace Ryujinx.Ava.Input
|
||||
public void RefreshControllers()
|
||||
{
|
||||
if (!_configurationState.Hid.EnableAutoAssign) return;
|
||||
|
||||
// Get every controller config and update the configuration state
|
||||
|
||||
List<IGamepad> controllers = _inputManager.GamepadDriver.GetGamepads().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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
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();
|
||||
HashSet<int> usedIndices = new();
|
||||
int recognizedControllersCount = 0;
|
||||
|
||||
// Assign controllers that have an old config
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
// Find the first available index
|
||||
desiredIndex = Enumerable.Range(0, MaxControllers).First(i => !usedIndices.Contains(i));
|
||||
desiredIndex = GetFirstAvailableIndex(usedIndices);
|
||||
}
|
||||
existingConfig.PlayerIndex = (PlayerIndex)desiredIndex;
|
||||
|
||||
InputConfig config = new GamepadInputConfig(existingConfig).GetConfig();
|
||||
config.PlayerIndex = (PlayerIndex)desiredIndex;
|
||||
usedIndices.Add(desiredIndex);
|
||||
playerIndexMap[desiredIndex] = existingConfig;
|
||||
playerIndexMap[desiredIndex] = config;
|
||||
recognizedControllersCount++;
|
||||
|
||||
remainingControllers.Remove(controller);
|
||||
|
||||
controllers.Remove(controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assign remaining (new) controllers
|
||||
foreach (var controller in remainingControllers.OrderBy(c => c.Id))
|
||||
/// <summary>
|
||||
/// 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);
|
||||
int freeIndex = Enumerable.Range(0, MaxControllers).First(i => !usedIndices.Contains(i));
|
||||
int freeIndex = GetFirstAvailableIndex(usedIndices);
|
||||
config.PlayerIndex = (PlayerIndex)freeIndex;
|
||||
usedIndices.Add(freeIndex);
|
||||
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)
|
||||
/// <summary>
|
||||
/// Finds the first available PlayerIndex that isn't in use.
|
||||
/// </summary>
|
||||
private int GetFirstAvailableIndex(HashSet<int> usedIndices)
|
||||
{
|
||||
for (int i = 0; i < MaxControllers; i++)
|
||||
{
|
||||
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++;
|
||||
if (!usedIndices.Contains(i)) return i;
|
||||
}
|
||||
return -1; // Should not happen unless MaxControllers is exceeded
|
||||
}
|
||||
|
||||
bool hasNewControllersConnected = (controllers.Count > recognizedControllersCount);
|
||||
return (orderedConfigs, hasNewControllersConnected);
|
||||
/// <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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user