diff --git a/BrickController2/BrickController2.Android/Extensions/InputDeviceExtensions.cs b/BrickController2/BrickController2.Android/Extensions/InputDeviceExtensions.cs
deleted file mode 100644
index 1ddd31af..00000000
--- a/BrickController2/BrickController2.Android/Extensions/InputDeviceExtensions.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Android.Views;
-
-namespace BrickController2.Droid.Extensions;
-
-public static class InputDeviceExtensions
-{
- ///
- /// Get an unique persistant identifier string for the given inputdevice
- ///
- /// inputdevice
- /// deviceidentifier
- public static string GetUniquePersistentDeviceId(this InputDevice? inputDevice) =>
- // https://developer.android.com/develop/ui/views/touch-and-input/game-controllers/multiple-controllers
- // Note: On devices running Android 4.1(API level 16) and higher, you can obtain an input device’s descriptor using getDescriptor(), which returns a unique persistent
- // string value for the input device.Unlike a device ID, the descriptor value won't change even if the input device is disconnected, reconnected, or reconfigured.
- inputDevice?.Descriptor ?? "NoDescriptor";
-}
diff --git a/BrickController2/BrickController2.Android/PlatformServices/GameController/GameControllerService.cs b/BrickController2/BrickController2.Android/PlatformServices/GameController/GameControllerService.cs
index 7e2f2988..f92642c2 100644
--- a/BrickController2/BrickController2.Android/PlatformServices/GameController/GameControllerService.cs
+++ b/BrickController2/BrickController2.Android/PlatformServices/GameController/GameControllerService.cs
@@ -7,7 +7,7 @@
namespace BrickController2.Droid.PlatformServices.GameController
{
- internal class GameControllerService : GameControllerServiceBase
+ internal class GameControllerService : GameControllerServiceBase
{
private readonly InputManager _inputManager;
@@ -36,9 +36,9 @@ internal void MainActivityOnInputDeviceAdded(int deviceId)
/// deviceId of InputDevice
internal void MainActivityOnInputDeviceRemoved(int deviceId)
{
- if (TryRemove(x => x.Gamepad.Id == deviceId, out var controller))
+ if (TryRemove(x => x.ControllerDevice.Id == deviceId, out var controller))
{
- _logger.LogInformation("Gamepad has been removed DeviceId:{id}, ControllerId:{controllerId}",
+ _logger.LogInformation("ControllerDevice has been removed DeviceId:{id}, ControllerId:{controllerId}",
deviceId, controller.ControllerId);
}
}
@@ -64,14 +64,14 @@ internal void MainActivityOnInputDeviceChanged(int deviceId)
else if (controller != null)
{
// handle change - remove and then add it again
- TryRemove(x => x.Gamepad.Id == deviceId, out _);
+ TryRemove(x => x.ControllerDevice.Id == deviceId, out _);
}
AddGameControllerDevice(device);
}
}
- else if (TryRemove(x => x.Gamepad.Id == deviceId, out var controller))
+ else if (TryRemove(x => x.ControllerDevice.Id == deviceId, out var controller))
{
- _logger.LogInformation("Gamepad has been removed DeviceId:{id}, ControllerId:{controllerId}",
+ _logger.LogInformation("ControllerDevice has been removed DeviceId:{id}, ControllerId:{controllerId}",
deviceId, controller.ControllerId);
}
}
@@ -122,7 +122,7 @@ private void AddGameControllerDevice(InputDevice gamepad)
}
private bool TryGetControllerByDeviceId(int deviceId, [MaybeNullWhen(false)] out GamepadController controller)
- => TryGetController(x => x.Gamepad.Id == deviceId, out controller);
+ => TryGetController(x => x.ControllerDevice.Id == deviceId, out controller);
private static bool TryGetGamepadDevice(int deviceId, [MaybeNullWhen(false)] out InputDevice device)
{
diff --git a/BrickController2/BrickController2.Android/PlatformServices/GameController/GamepadController.cs b/BrickController2/BrickController2.Android/PlatformServices/GameController/GamepadController.cs
index 2e0a3e19..01240f4d 100644
--- a/BrickController2/BrickController2.Android/PlatformServices/GameController/GamepadController.cs
+++ b/BrickController2/BrickController2.Android/PlatformServices/GameController/GamepadController.cs
@@ -1,5 +1,4 @@
using Android.Views;
-using BrickController2.Droid.Extensions;
using BrickController2.PlatformServices.GameController;
using System;
using System.Collections.Generic;
@@ -25,11 +24,8 @@ public GamepadController(GameControllerService service, InputDevice gamePad)
{
// initialize properties
Name = GetDisplayName(gamePad);
- VendorId = gamePad.VendorId;
- ProductId = gamePad.ProductId;
ControllerNumber = gamePad.ControllerNumber;
ControllerId = GetControllerIdFromNumber(gamePad.ControllerNumber);
- UniquePersistantDeviceId = gamePad.GetUniquePersistentDeviceId();
}
internal bool OnButtonEvent(KeyEvent e, float buttonValue)
diff --git a/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GameControllerService.cs b/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GameControllerService.cs
index 296a37ec..f65b70b7 100644
--- a/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GameControllerService.cs
+++ b/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GameControllerService.cs
@@ -8,7 +8,7 @@
namespace BrickController2.Windows.PlatformServices.GameController;
-internal class GameControllerService : GameControllerServiceBase, IGameControllerService
+internal class GameControllerService : GameControllerServiceBase, IGameControllerService
{
private readonly IMainThreadService _mainThreadService;
private readonly IDispatcherProvider _dispatcherProvider;
@@ -53,9 +53,9 @@ private void Gamepad_GamepadRemoved(object? sender, Gamepad gamepad)
// ensure stopped in UI thread
_ = _mainThreadService.RunOnMainThread(() =>
{
- if (TryRemove(x => x.Gamepad == gamepad, out var controller))
+ if (TryRemove(x => x.ControllerDevice == gamepad, out var controller))
{
- _logger.LogInformation("Gamepad has been removed ControllerId:{controllerId}", controller.ControllerId);
+ _logger.LogInformation("Controller device has been removed ControllerId:{controllerId}", controller.ControllerId);
}
});
}
diff --git a/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GamepadController.cs b/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GamepadController.cs
index ef203590..4972f8ba 100644
--- a/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GamepadController.cs
+++ b/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GamepadController.cs
@@ -24,14 +24,10 @@ internal class GamepadController : GamepadControllerBase
public GamepadController(GameControllerService service, Gamepad gamepad, RawGameController rawController, int controllerNumber, IDispatcherTimer timer)
: base(service, gamepad)
{
+ Name = rawController.DisplayName;
ControllerNumber = controllerNumber;
ControllerId = GetControllerIdFromNumber(controllerNumber);
- UniquePersistantDeviceId = rawController.NonRoamableId;
- Name = rawController.DisplayName;
- VendorId = rawController.HardwareVendorId;
- ProductId = rawController.HardwareProductId;
-
_timer = timer;
_timer.Interval = DefaultInterval;
@@ -55,7 +51,7 @@ public override void Stop()
private void Timer_Tick(object? sender, object e)
{
- var currentReading = Gamepad.GetCurrentReading();
+ var currentReading = ControllerDevice.GetCurrentReading();
var currentEvents = currentReading
.Enumerate()
diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs
index e138df48..11bfe194 100644
--- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs
+++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs
@@ -1,285 +1,124 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using BrickController2.PlatformServices.GameController;
+using BrickController2.PlatformServices.GameController;
using Foundation;
using GameController;
-
-using static BrickController2.PlatformServices.GameController.GameControllers;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
namespace BrickController2.iOS.PlatformServices.GameController
{
- public class GameControllerService : IGameControllerService
+ internal class GameControllerService : GameControllerServiceBase
{
- private enum GameControllerType
- {
- Unknown,
- Micro,
- Standard,
- Extended
- };
-
- private readonly object _lockObject = new object();
-
- private readonly IDictionary _lastControllerEventValueMap = new Dictionary();
+ private static readonly GCControllerPlayerIndex[] ValidPlayerIndexes = Enum.GetValues(typeof(GCControllerPlayerIndex))
+ .Cast()
+ .Where(i => i != GCControllerPlayerIndex.Unset)
+ .ToArray();
- private GCController? _gameController;
- private event EventHandler? GameControllerEventInternal;
private NSObject? _didConnectNotification;
private NSObject? _didDisconnectNotification;
- public event EventHandler GameControllerEvent
+ public GameControllerService(ILogger logger)
+ : base(logger)
{
- add
- {
- lock (_lockObject)
- {
- if (GameControllerEventInternal is null)
- {
- if (GCController.Controllers.Length == 0)
- {
- FindController();
- }
- else
- {
- FoundController();
- }
- }
-
- GameControllerEventInternal += value;
- }
- }
-
- remove
- {
- lock (_lockObject)
- {
- GameControllerEventInternal -= value;
-
- if (GameControllerEventInternal is null)
- {
- GCController.StopWirelessControllerDiscovery();
- _didConnectNotification?.Dispose();
- _didDisconnectNotification?.Dispose();
- _didConnectNotification = null;
- _didDisconnectNotification = null;
- _gameController?.Dispose();
- _gameController = null;
- }
- }
- }
}
- public event EventHandler? GameControllersChangedEvent;
-
- public bool IsControllerIdSupported => false; // ToDo: implement ControllerManagement
+ public override bool IsControllerIdSupported => true;
- private void FindController()
+ protected override void InitializeCurrentControllers()
{
- lock (_lockObject)
+ // get all available gamepads
+ if (GCController.Controllers.Any())
{
- _didConnectNotification = GCController.Notifications.ObserveDidConnect((sender, args) =>
- {
- FoundController();
- });
-
- GCController.StartWirelessControllerDiscovery(() => { });
+ AddDevices(GCController.Controllers);
}
- }
- private void FoundController()
- {
- lock (_lockObject)
+ // register GCController events
+ _didDisconnectNotification = GCController.Notifications.ObserveDidDisconnect((sender, args) =>
{
- _gameController = GCController.Controllers.FirstOrDefault();
-
- if (_gameController is not null)
+ if (args.Notification.Object is GCController controller)
{
- GCController.StopWirelessControllerDiscovery();
- _didConnectNotification?.Dispose();
- _didConnectNotification = null;
-
- _didDisconnectNotification = GCController.Notifications.ObserveDidDisconnect((sender, args) =>
- {
- FindController();
- });
-
- switch (GetGameControllerType(_gameController))
- {
- case GameControllerType.Micro:
- SetupMicroGamePad(_gameController.MicroGamepad!);
- break;
-
- case GameControllerType.Standard:
-#pragma warning disable CA1422 // Validate platform compatibility
- SetupGamePad(_gameController.Gamepad!);
-#pragma warning restore CA1422 // Validate platform compatibility
- break;
-
- case GameControllerType.Extended:
- SetupExtendedGamePad(_gameController.ExtendedGamepad!);
- break;
- }
+ ControllerRemoved(controller);
}
- }
- }
-
- private GameControllerType GetGameControllerType(GCController controller)
- {
- try
+ });
+ _didConnectNotification = GCController.Notifications.ObserveDidConnect((sender, args) =>
{
- if (controller.MicroGamepad is not null)
+ if (args.Notification.Object is GCController controller)
{
- return GameControllerType.Micro;
+ ControllerAdded(controller);
}
- }
- catch (InvalidCastException) { }
+ });
- try
- {
-#pragma warning disable CA1422 // Validate platform compatibility
- if (controller.Gamepad is not null)
- {
- return GameControllerType.Standard;
- }
-#pragma warning restore CA1422 // Validate platform compatibility
- }
- catch (InvalidCastException) { }
-
- try
- {
- if (controller.ExtendedGamepad is not null)
- {
- return GameControllerType.Extended;
- }
- }
- catch (InvalidCastException) { }
-
- return GameControllerType.Unknown;
- }
-
- private void SetupMicroGamePad(GCMicroGamepad gamePad)
- {
- SetupDigitalButtonInput(gamePad.ButtonA, "Button_A");
- SetupDigitalButtonInput(gamePad.ButtonX, "Button_X");
-
- SetupDPadInput(gamePad.Dpad, "DPad");
+ GCController.StartWirelessControllerDiscovery(() => { });
}
- private void SetupGamePad(GCGamepad gamePad)
- {
-#pragma warning disable CA1422 // Validate platform compatibility
- SetupDigitalButtonInput(gamePad.ButtonA, "Button_A");
- SetupDigitalButtonInput(gamePad.ButtonB, "Button_B");
- SetupDigitalButtonInput(gamePad.ButtonX, "Button_X");
- SetupDigitalButtonInput(gamePad.ButtonY, "Button_Y");
-
- SetupDigitalButtonInput(gamePad.LeftShoulder, "LeftShoulder");
- SetupDigitalButtonInput(gamePad.RightShoulder, "RightShoulder");
- SetupDPadInput(gamePad.DPad, "DPad");
-#pragma warning restore CA1422 // Validate platform compatibility
- }
-
- private void SetupExtendedGamePad(GCExtendedGamepad gamePad)
+ protected override void RemoveAllControllers()
{
- SetupDigitalButtonInput(gamePad.ButtonA, "Button_A");
- SetupDigitalButtonInput(gamePad.ButtonB, "Button_B");
- SetupDigitalButtonInput(gamePad.ButtonX, "Button_X");
- SetupDigitalButtonInput(gamePad.ButtonY, "Button_Y");
-
- SetupDigitalButtonInput(gamePad.LeftShoulder, "LeftShoulder");
- SetupDigitalButtonInput(gamePad.RightShoulder, "RightShoulder");
+ GCController.StopWirelessControllerDiscovery();
+ _didConnectNotification?.Dispose();
+ _didDisconnectNotification?.Dispose();
+ _didConnectNotification = null;
+ _didDisconnectNotification = null;
- SetupAnalogButtonInput(gamePad.LeftTrigger, "LeftTrigger");
- SetupAnalogButtonInput(gamePad.RightTrigger, "RightTrigger");
-
- SetupDPadInput(gamePad.DPad, "DPad");
-
- SetupJoyInput(gamePad.LeftThumbstick, "LeftThumbStick");
- SetupJoyInput(gamePad.RightThumbstick, "RightThumbStick");
+ base.RemoveAllControllers();
}
- private void SetupDigitalButtonInput(GCControllerButtonInput button, string name)
+ private void ControllerRemoved(GCController controller)
{
- button.ValueChangedHandler = (btn, value, isPressed) =>
- {
- value = isPressed ? 1.0F : 0.0F;
-
- if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value))
- {
- // ToDo: find ControllerId
- string controllerId = GetControllerIdFromIndex(0);
-
- _lastControllerEventValueMap[name] = value;
- GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Button, name, value));
- }
- };
- }
-
- private void SetupAnalogButtonInput(GCControllerButtonInput button, string name)
- {
- button.ValueChangedHandler = (btn, value, isPressed) =>
+ lock (_lockObject)
{
- value = value < 0.1 ? 0.0F : value;
-
- if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value))
+ if (TryRemove(x => x.ControllerDevice == controller, out var controllerDevice))
{
- // ToDo: find ControllerId
- string controllerId = GetControllerIdFromIndex(0);
-
- _lastControllerEventValueMap[name] = value;
- GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value));
+ _logger.LogInformation("Controller device has been removed ControllerId:{controllerId}", controllerDevice.ControllerId);
}
- };
+ }
}
- private void SetupDPadInput(GCControllerDirectionPad dPad, string name)
+ private void ControllerAdded(GCController controller)
{
- SetupDigitalAxisInput(dPad.XAxis, $"{name}_X");
- SetupDigitalAxisInput(dPad.YAxis, $"{name}_Y");
+ AddDevices([controller]);
}
- private void SetupDigitalAxisInput(GCControllerAxisInput axis, string name)
+ private void AddDevices(IEnumerable controllers)
{
- axis.ValueChangedHandler = (ax, value) =>
+ lock (_lockObject)
{
- if (value < -0.1F) value = -1.0F;
- else if (value > 0.1F) value = 1.0F;
- else value = 0.0F;
-
- if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value))
+ foreach (var controller in controllers)
{
- // ToDo: find ControllerId
- string controllerId = GetControllerIdFromIndex(0);
+ // If PlayerIndex is unset then assign the next free player index
+ AssignNextAvailablePlayerIndex(controller);
+
+ // get first unused number and apply it
+ var newController = new GamepadController(this, controller);
- GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value));
- _lastControllerEventValueMap[name] = value;
+ AddController(newController);
}
- };
+ }
}
- private void SetupJoyInput(GCControllerDirectionPad joy, string name)
+ ///
+ /// If PlayerIndex is unset then assign the next free player index
+ ///
+ ///
+ private void AssignNextAvailablePlayerIndex(GCController controller)
{
- SetupAnalogAxisInput(joy.XAxis, $"{name}_X");
- SetupAnalogAxisInput(joy.YAxis, $"{name}_Y");
- }
+ if (controller.PlayerIndex != GCControllerPlayerIndex.Unset)
+ return;
- private void SetupAnalogAxisInput(GCControllerAxisInput axis, string name)
- {
- axis.ValueChangedHandler = (ax, value) =>
- {
- value = AdjustControllerValue(value);
+ var usedIndexes = GCController.Controllers
+ .Where(c => c.PlayerIndex != GCControllerPlayerIndex.Unset)
+ .Select(c => c.PlayerIndex)
+ .ToHashSet();
- if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value))
+ foreach (var index in ValidPlayerIndexes)
+ {
+ if (!usedIndexes.Contains(index))
{
- // ToDo: find ControllerId
- string controllerId = GetControllerIdFromIndex(0);
-
- GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value));
- _lastControllerEventValueMap[name] = value;
+ controller.PlayerIndex = index;
+ break;
}
- };
+ }
}
}
}
\ No newline at end of file
diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs
new file mode 100644
index 00000000..d490c26d
--- /dev/null
+++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs
@@ -0,0 +1,223 @@
+using System;
+using BrickController2.PlatformServices.GameController;
+using GameController;
+
+using static BrickController2.PlatformServices.GameController.GameControllers;
+
+using BrickController2.iOS.PlatformServices.GameController;
+
+internal class GamepadController : GamepadControllerBase, IDisposable
+{
+ private enum GameControllerType
+ {
+ Unknown,
+ Micro,
+ Standard,
+ Extended
+ };
+
+ ///
+ /// Constructor
+ ///
+ /// reference to GameControllerService
+ /// reference to InputDevice
+ public GamepadController(GameControllerService service, GCController controller)
+ : base(service, controller)
+ {
+ GameControllerType gameControllerType = GetGameControllerType(controller);
+
+ // initialize properties
+ Name = GetDisplayName(controller, gameControllerType);
+ ControllerNumber = (int)controller.PlayerIndex;
+ ControllerId = GetControllerIdFromNumber(ControllerNumber);
+
+ SetupController(controller, gameControllerType);
+ }
+
+ public void Dispose()
+ {
+ ControllerDevice.Dispose();
+ }
+
+ private void SetupController(GCController gameController, GameControllerType gameControllerType)
+ {
+ switch (gameControllerType)
+ {
+ case GameControllerType.Micro:
+ SetupMicroGamePad(gameController.MicroGamepad!);
+ break;
+
+ case GameControllerType.Standard:
+#pragma warning disable CA1422 // Validate platform compatibility
+ SetupGamePad(gameController.Gamepad!);
+#pragma warning restore CA1422 // Validate platform compatibility
+ break;
+
+ case GameControllerType.Extended:
+ SetupExtendedGamePad(gameController.ExtendedGamepad!);
+ break;
+ }
+ }
+
+ private GameControllerType GetGameControllerType(GCController controller)
+ {
+ try
+ {
+ if (controller.MicroGamepad is not null)
+ {
+ return GameControllerType.Micro;
+ }
+ }
+ catch (InvalidCastException) { }
+
+ try
+ {
+#pragma warning disable CA1422 // Validate platform compatibility
+ if (controller.Gamepad is not null)
+ {
+ return GameControllerType.Standard;
+ }
+#pragma warning restore CA1422 // Validate platform compatibility
+ }
+ catch (InvalidCastException) { }
+
+ try
+ {
+ if (controller.ExtendedGamepad is not null)
+ {
+ return GameControllerType.Extended;
+ }
+ }
+ catch (InvalidCastException) { }
+
+ return GameControllerType.Unknown;
+ }
+
+ private void SetupMicroGamePad(GCMicroGamepad gamePad)
+ {
+ SetupDigitalButtonInput(gamePad.ButtonA, "Button_A");
+ SetupDigitalButtonInput(gamePad.ButtonX, "Button_X");
+
+ SetupDPadInput(gamePad.Dpad, "DPad");
+ }
+
+ private void SetupGamePad(GCGamepad gamePad)
+ {
+#pragma warning disable CA1422 // Validate platform compatibility
+ SetupDigitalButtonInput(gamePad.ButtonA, "Button_A");
+ SetupDigitalButtonInput(gamePad.ButtonB, "Button_B");
+ SetupDigitalButtonInput(gamePad.ButtonX, "Button_X");
+ SetupDigitalButtonInput(gamePad.ButtonY, "Button_Y");
+
+ SetupDigitalButtonInput(gamePad.LeftShoulder, "LeftShoulder");
+ SetupDigitalButtonInput(gamePad.RightShoulder, "RightShoulder");
+
+ SetupDPadInput(gamePad.DPad, "DPad");
+#pragma warning restore CA1422 // Validate platform compatibility
+ }
+
+ private void SetupExtendedGamePad(GCExtendedGamepad gamePad)
+ {
+ SetupDigitalButtonInput(gamePad.ButtonA, "Button_A");
+ SetupDigitalButtonInput(gamePad.ButtonB, "Button_B");
+ SetupDigitalButtonInput(gamePad.ButtonX, "Button_X");
+ SetupDigitalButtonInput(gamePad.ButtonY, "Button_Y");
+
+ SetupDigitalButtonInput(gamePad.LeftShoulder, "LeftShoulder");
+ SetupDigitalButtonInput(gamePad.RightShoulder, "RightShoulder");
+
+ SetupAnalogButtonInput(gamePad.LeftTrigger, "LeftTrigger");
+ SetupAnalogButtonInput(gamePad.RightTrigger, "RightTrigger");
+
+ SetupDPadInput(gamePad.DPad, "DPad");
+
+ SetupJoyInput(gamePad.LeftThumbstick, "LeftThumbStick");
+ SetupJoyInput(gamePad.RightThumbstick, "RightThumbStick");
+ }
+
+ private void SetupDigitalButtonInput(GCControllerButtonInput button, string name)
+ {
+ button.ValueChangedHandler = (btn, value, isPressed) =>
+ {
+ value = isPressed ? BUTTON_PRESSED : BUTTON_RELEASED;
+
+ if (HasValueChanged(name, value))
+ {
+ RaiseEvent(GameControllerEventType.Button, name, value);
+ }
+ };
+ }
+
+ private void SetupAnalogButtonInput(GCControllerButtonInput button, string name)
+ {
+ button.ValueChangedHandler = (btn, value, isPressed) =>
+ {
+ value = value < 0.1 ? 0.0F : value;
+
+ if (HasValueChanged(name, value))
+ {
+ RaiseEvent(GameControllerEventType.Axis, name, value);
+ }
+ };
+ }
+
+ private void SetupDPadInput(GCControllerDirectionPad dPad, string name)
+ {
+ SetupDigitalAxisInput(dPad.XAxis, $"{name}_X");
+ SetupDigitalAxisInput(dPad.YAxis, $"{name}_Y");
+ }
+
+ private void SetupDigitalAxisInput(GCControllerAxisInput axis, string name)
+ {
+ axis.ValueChangedHandler = (ax, value) =>
+ {
+ // adjust value
+ value = value switch
+ {
+ < -0.1f => AXIS_MIN_VALUE,
+ > 0.1f => AXIS_MAX_VALUE,
+ _ => AXIS_ZERO_VALUE
+ };
+
+ if (HasValueChanged(name, value))
+ {
+ RaiseEvent(GameControllerEventType.Axis, name, value);
+ }
+ };
+ }
+
+ private void SetupJoyInput(GCControllerDirectionPad joy, string name)
+ {
+ SetupAnalogAxisInput(joy.XAxis, $"{name}_X");
+ SetupAnalogAxisInput(joy.YAxis, $"{name}_Y");
+ }
+
+ private void SetupAnalogAxisInput(GCControllerAxisInput axis, string name)
+ {
+ axis.ValueChangedHandler = (ax, value) =>
+ {
+ value = AdjustControllerValue(value);
+
+ if (HasValueChanged(name, value))
+ {
+ RaiseEvent(GameControllerEventType.Axis, name, value);
+ }
+ };
+ }
+
+ private static string GetDisplayName(GCController controller, GameControllerType gameControllerType)
+ {
+ if (!string.IsNullOrEmpty(controller.VendorName))
+ {
+ return controller.VendorName;
+ }
+
+ return gameControllerType switch
+ {
+ GameControllerType.Micro => "Micro Gamepad",
+ GameControllerType.Standard => "Standard Gamepad",
+ GameControllerType.Extended => "Extended Gamepad",
+ _ => "Unknown Gamepad",
+ };
+ }
+}
\ No newline at end of file
diff --git a/BrickController2/BrickController2/PlatformServices/GameController/GameControllerServiceBase.cs b/BrickController2/BrickController2/PlatformServices/GameController/GameControllerServiceBase.cs
index a9f08f8d..a37c145a 100644
--- a/BrickController2/BrickController2/PlatformServices/GameController/GameControllerServiceBase.cs
+++ b/BrickController2/BrickController2/PlatformServices/GameController/GameControllerServiceBase.cs
@@ -10,8 +10,7 @@ namespace BrickController2.PlatformServices.GameController;
///
/// Base class for implementation of
///
-public abstract class GameControllerServiceBase : IGameControllerServiceInternal
- where TGameController : class, IGameController
+public abstract class GameControllerServiceBase : IGameControllerServiceInternal
{
protected readonly object _lockObject = new();
protected readonly ILogger _logger;
@@ -21,7 +20,7 @@ public abstract class GameControllerServiceBase : IGameControll
///
/// Collection of available gamepads having
///
- private readonly List _availableControllers = [];
+ private readonly List _availableControllers = [];
protected GameControllerServiceBase(ILogger logger)
{
@@ -97,6 +96,8 @@ protected virtual void RemoveAllControllers()
foreach (var controller in _availableControllers)
{
controller.Stop();
+
+ (controller as IDisposable)?.Dispose();
}
_availableControllers.Clear();
// notify removal
@@ -119,7 +120,7 @@ protected int GetFirstUnusedControllerNumber()
}
}
- protected void AddController(TGameController controller)
+ protected void AddController(IGameController controller)
{
lock (_lockObject)
{
@@ -130,27 +131,36 @@ protected void AddController(TGameController controller)
}
}
- protected bool TryRemove(Predicate predicate, [MaybeNullWhen(false)] out TGameController controller)
+ protected bool TryRemove(Predicate predicate, [MaybeNullWhen(false)] out TGameController controller)
+ where TGameController : class, IGameController
{
lock (_lockObject)
{
// remove and stop the controller
- if (_availableControllers.Remove(predicate, out controller))
+ if (_availableControllers.Remove(x => x is TGameController tc && predicate(tc), out var removed))
{
+ controller = (TGameController)removed; // safe due to pattern match above
controller.Stop();
+
// notify removal
OnGameControllersChangedEvent(NotifyGameControllersChangedAction.Disconnected, controller);
+
+ (controller as IDisposable)?.Dispose();
+
return true;
}
+
+ controller = null;
return false;
}
}
- protected bool TryGetController(Predicate predicate, [MaybeNullWhen(false)] out TGameController controller)
+ protected bool TryGetController(Predicate predicate, [MaybeNullWhen(false)] out TGameController controller)
+ where TGameController : class, IGameController
{
lock (_lockObject)
{
- controller = _availableControllers.FirstOrDefault(x => predicate(x));
+ controller = _availableControllers.OfType().FirstOrDefault(x => predicate(x));
return controller is not null;
}
}
diff --git a/BrickController2/BrickController2/PlatformServices/GameController/GameControllers.cs b/BrickController2/BrickController2/PlatformServices/GameController/GameControllers.cs
index 9ca61de9..a4dfefaf 100644
--- a/BrickController2/BrickController2/PlatformServices/GameController/GameControllers.cs
+++ b/BrickController2/BrickController2/PlatformServices/GameController/GameControllers.cs
@@ -14,17 +14,6 @@ public static class GameControllers
public const float AXIS_MIN_VALUE = - 1.0f;
public const float AXIS_MAX_VALUE = 1.0f;
- ///
- /// Creates an identifier string for the controller from the given index
- ///
- /// zero-based index
- /// Identifier
- public static string GetControllerIdFromIndex(int controllerIndex)
- {
- // controllerIndex == 0 -> "Controller 1"
- return $"Controller {controllerIndex + 1}";
- }
-
///
/// Creates an identifier string for the controller from the given
///
diff --git a/BrickController2/BrickController2/PlatformServices/GameController/GamepadControllerBase.cs b/BrickController2/BrickController2/PlatformServices/GameController/GamepadControllerBase.cs
index 55a82f59..6948a653 100644
--- a/BrickController2/BrickController2/PlatformServices/GameController/GamepadControllerBase.cs
+++ b/BrickController2/BrickController2/PlatformServices/GameController/GamepadControllerBase.cs
@@ -4,7 +4,7 @@
namespace BrickController2.PlatformServices.GameController;
-public abstract class GamepadControllerBase : IGameController where TGamepad : class
+public abstract class GamepadControllerBase : IGameController where TControllerDevice : class
{
/// stored last value per axis to detect changes
private readonly Dictionary _lastAxisValues = [];
@@ -13,10 +13,10 @@ public abstract class GamepadControllerBase : IGameController where TG
private readonly IGameControllerServiceInternal _controllerService;
protected GamepadControllerBase(IGameControllerServiceInternal controllerService,
- TGamepad gamepad)
+ TControllerDevice controllerDevice)
{
_controllerService = controllerService;
- Gamepad = gamepad;
+ ControllerDevice = controllerDevice;
}
///
@@ -30,19 +30,15 @@ protected GamepadControllerBase(IGameControllerServiceInternal controllerService
public string ControllerId { get; protected init; } = default!;
///
- /// Unique and persistant identifier of device
+ /// DisplayName of the controller
///
- public string UniquePersistantDeviceId { get; protected init; } = default!;
-
public string Name { get; protected init; } = default!;
- public int VendorId { get; protected init; }
- public int ProductId { get; protected init; }
///
- /// Native instance of gamepad
+ /// Native instance of controller device
///
- public TGamepad Gamepad { get; }
+ public TControllerDevice ControllerDevice { get; }
public virtual void Start()
{
diff --git a/BrickController2/BrickController2/PlatformServices/GameController/IGameController.cs b/BrickController2/BrickController2/PlatformServices/GameController/IGameController.cs
index f0c8e60f..61139b65 100644
--- a/BrickController2/BrickController2/PlatformServices/GameController/IGameController.cs
+++ b/BrickController2/BrickController2/PlatformServices/GameController/IGameController.cs
@@ -18,16 +18,6 @@ public interface IGameController
///
string Name { get; }
- ///
- /// Vendor ID of the game controller.
- ///
- int VendorId { get; }
-
- ///
- /// Product ID of the game controller.
- ///
- int ProductId { get; }
-
///
/// Start the controller and publishing of its events
///