From 67940f69868a62a861a96b26fde305fb6c1f737d Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Sat, 30 Aug 2025 13:55:18 +0200 Subject: [PATCH 01/12] added ControllerManagement for iOS cleanup code: * removed unused properties of IGameController and GamepadControllerBase * removed generic in GameControllerServiceBase; use IGameController --- .../Extensions/InputDeviceExtensions.cs | 17 -- .../GameController/GameControllerService.cs | 14 +- .../GameController/GamepadController.cs | 4 - .../GameController/GameControllerService.cs | 6 +- .../GameController/GamepadController.cs | 8 +- .../GameController/GameControllerService.cs | 279 +++--------------- .../GameController/GamepadController.cs | 242 +++++++++++++++ .../GameControllerServiceBase.cs | 26 +- .../GameController/GameControllers.cs | 11 - .../GameController/GamepadControllerBase.cs | 16 +- .../GameController/IGameController.cs | 10 - 11 files changed, 322 insertions(+), 311 deletions(-) delete mode 100644 BrickController2/BrickController2.Android/Extensions/InputDeviceExtensions.cs create mode 100644 BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs 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..9abe20bf 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("ControllerDevice 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..21cb24cc 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs @@ -1,285 +1,94 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using BrickController2.PlatformServices.GameController; using Foundation; using GameController; - -using static BrickController2.PlatformServices.GameController.GameControllers; +using Microsoft.Extensions.Logging; 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 GCController? _gameController; - private event EventHandler? GameControllerEventInternal; private NSObject? _didConnectNotification; private NSObject? _didDisconnectNotification; - public event EventHandler GameControllerEvent - { - 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 - - private void FindController() + public GameControllerService(ILogger logger) + : base(logger) { - lock (_lockObject) - { - _didConnectNotification = GCController.Notifications.ObserveDidConnect((sender, args) => - { - FoundController(); - }); - - GCController.StartWirelessControllerDiscovery(() => { }); - } } - private void FoundController() - { - lock (_lockObject) - { - _gameController = GCController.Controllers.FirstOrDefault(); - - if (_gameController is not null) - { - 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; - } - } - } - } + public override bool IsControllerIdSupported => true; - private GameControllerType GetGameControllerType(GCController controller) + protected override void InitializeCurrentControllers() { - try + // get all available gamepads + if (GCController.Controllers.Any()) { - if (controller.MicroGamepad is not null) - { - return GameControllerType.Micro; - } + AddDevices(GCController.Controllers); } - catch (InvalidCastException) { } - try + // register GCController events + _didDisconnectNotification = GCController.Notifications.ObserveDidDisconnect((sender, args) => { -#pragma warning disable CA1422 // Validate platform compatibility - if (controller.Gamepad is not null) + var controller = args.Notification.Object as GCController; + if (controller != null) { - return GameControllerType.Standard; + ControllerRemoved(controller); } -#pragma warning restore CA1422 // Validate platform compatibility - } - catch (InvalidCastException) { } - - try + }); + _didConnectNotification = GCController.Notifications.ObserveDidConnect((sender, args) => { - if (controller.ExtendedGamepad is not null) + var controller = args.Notification.Object as GCController; + if (controller != null) { - return GameControllerType.Extended; + ControllerAdded(controller); } - } - 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"); + GCController.StartWirelessControllerDiscovery(() => { }); } - private void SetupDigitalButtonInput(GCControllerButtonInput button, string name) - { - 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) + protected override void RemoveAllControllers() { - button.ValueChangedHandler = (btn, value, isPressed) => - { - value = value < 0.1 ? 0.0F : value; - - 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.Axis, name, value)); - } - }; - } + GCController.StopWirelessControllerDiscovery(); + _didConnectNotification?.Dispose(); + _didDisconnectNotification?.Dispose(); + _didConnectNotification = null; + _didDisconnectNotification = null; - private void SetupDPadInput(GCControllerDirectionPad dPad, string name) - { - SetupDigitalAxisInput(dPad.XAxis, $"{name}_X"); - SetupDigitalAxisInput(dPad.YAxis, $"{name}_Y"); + base.RemoveAllControllers(); } - private void SetupDigitalAxisInput(GCControllerAxisInput axis, string name) + private void ControllerRemoved(GCController controller) { - 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)) + if (TryRemove(x => x.ControllerDevice == controller, out var controllerDevice)) { - // ToDo: find ControllerId - string controllerId = GetControllerIdFromIndex(0); - - GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value)); - _lastControllerEventValueMap[name] = value; + _logger.LogInformation("ControllerDevice has been removed ControllerId:{controllerId}", controllerDevice.ControllerId); } - }; + } } - private void SetupJoyInput(GCControllerDirectionPad joy, string name) + private void ControllerAdded(GCController controller) { - SetupAnalogAxisInput(joy.XAxis, $"{name}_X"); - SetupAnalogAxisInput(joy.YAxis, $"{name}_Y"); + AddDevices([controller]); } - private void SetupAnalogAxisInput(GCControllerAxisInput axis, string name) + private void AddDevices(IEnumerable controllers) { - axis.ValueChangedHandler = (ax, value) => + lock (_lockObject) { - value = AdjustControllerValue(value); - - if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) + foreach (var gamepad in controllers) { - // ToDo: find ControllerId - string controllerId = GetControllerIdFromIndex(0); + // get first unused number and apply it + int controllerNumber = GetFirstUnusedControllerNumber(); + var newController = new GamepadController(this, gamepad, controllerNumber); - GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value)); - _lastControllerEventValueMap[name] = value; + AddController(newController); } - }; + } } } } \ 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..18a0f3cb --- /dev/null +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +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 + }; + + private readonly IDictionary _lastControllerEventValueMap = new Dictionary(); + + /// + /// Constructor + /// + /// reference to GameControllerService + /// reference to InputDevice + public GamepadController(GameControllerService service, GCController controller, int controllerNumber) + : base(service, controller) + { + // initialize properties + GameControllerType gameControllerType = GetGameControllerType(controller); + + Name = GetDisplayName(gameControllerType); + ControllerNumber = controllerNumber; + 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 ? 1.0F : 0.0F; + + if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) + { + // ToDo: find ControllerId + //string controllerId = GetControllerIdFromIndex(0); + //GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Button, name, value)); + + RaiseEvent(GameControllerEventType.Button, name, value); + + _lastControllerEventValueMap[name] = value; + } + }; + } + + private void SetupAnalogButtonInput(GCControllerButtonInput button, string name) + { + button.ValueChangedHandler = (btn, value, isPressed) => + { + value = value < 0.1 ? 0.0F : value; + + if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) + { + // ToDo: find ControllerId + //string controllerId = GetControllerIdFromIndex(0); + //GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value)); + + RaiseEvent(GameControllerEventType.Axis, name, value); + + _lastControllerEventValueMap[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) => + { + 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)) + { + // ToDo: find ControllerId + //string controllerId = GetControllerIdFromIndex(0); + //GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value)); + + RaiseEvent(GameControllerEventType.Axis, name, value); + + _lastControllerEventValueMap[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 (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) + { + // ToDo: find ControllerId + //string controllerId = GetControllerIdFromIndex(0); + //GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value)); + + RaiseEvent(GameControllerEventType.Axis, name, value); + + _lastControllerEventValueMap[name] = value; + } + }; + } + + private static string GetDisplayName(GameControllerType device) + { + return device 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..a8f33c5c 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 controllerdevice /// - 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 /// From 436546c7bc0858357fd1896e8d4557198d2e3a51 Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Wed, 3 Sep 2025 11:11:41 +0200 Subject: [PATCH 02/12] removed commented-out code and enshure PlayerIndex is set --- .../GameController/GameControllerService.cs | 40 ++++++++++++++++--- .../GameController/GamepadController.cs | 22 ++-------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs index 21cb24cc..3dfdd811 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs @@ -1,9 +1,10 @@ -using System.Collections.Generic; -using System.Linq; -using BrickController2.PlatformServices.GameController; +using BrickController2.PlatformServices.GameController; using Foundation; using GameController; using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; namespace BrickController2.iOS.PlatformServices.GameController { @@ -82,13 +83,42 @@ private void AddDevices(IEnumerable controllers) { foreach (var gamepad in controllers) { + // If PlayerIndex is unset then assign the next free player index + AssignNextAvailablePlayerIndex(gamepad); + // get first unused number and apply it - int controllerNumber = GetFirstUnusedControllerNumber(); - var newController = new GamepadController(this, gamepad, controllerNumber); + var newController = new GamepadController(this, gamepad); AddController(newController); } } } + + /// + /// If PlayerIndex is unset then assign the next free player index + /// + /// + private void AssignNextAvailablePlayerIndex(GCController controller) + { + if (controller.PlayerIndex != GCControllerPlayerIndex.Unset) + { + return; + } + + var usedIndexes = GCController.Controllers + .Where(c => c.PlayerIndex != GCControllerPlayerIndex.Unset) + .Select(c => c.PlayerIndex) + .ToHashSet(); + + foreach (GCControllerPlayerIndex index in Enum.GetValues(typeof(GCControllerPlayerIndex))) + { + if (index == GCControllerPlayerIndex.Unset) continue; + if (!usedIndexes.Contains(index)) + { + 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 index 18a0f3cb..e488d54e 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs @@ -24,15 +24,15 @@ private enum GameControllerType /// /// reference to GameControllerService /// reference to InputDevice - public GamepadController(GameControllerService service, GCController controller, int controllerNumber) + public GamepadController(GameControllerService service, GCController controller) : base(service, controller) { // initialize properties GameControllerType gameControllerType = GetGameControllerType(controller); Name = GetDisplayName(gameControllerType); - ControllerNumber = controllerNumber; - ControllerId = GetControllerIdFromNumber(controllerNumber); + ControllerNumber = (int)controller.PlayerIndex; + ControllerId = GetControllerIdFromNumber(ControllerNumber); SetupController(controller, gameControllerType); } @@ -146,10 +146,6 @@ private void SetupDigitalButtonInput(GCControllerButtonInput button, string name if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) { - // ToDo: find ControllerId - //string controllerId = GetControllerIdFromIndex(0); - //GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Button, name, value)); - RaiseEvent(GameControllerEventType.Button, name, value); _lastControllerEventValueMap[name] = value; @@ -165,10 +161,6 @@ private void SetupAnalogButtonInput(GCControllerButtonInput button, string name) if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) { - // ToDo: find ControllerId - //string controllerId = GetControllerIdFromIndex(0); - //GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value)); - RaiseEvent(GameControllerEventType.Axis, name, value); _lastControllerEventValueMap[name] = value; @@ -192,10 +184,6 @@ private void SetupDigitalAxisInput(GCControllerAxisInput axis, string name) if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) { - // ToDo: find ControllerId - //string controllerId = GetControllerIdFromIndex(0); - //GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value)); - RaiseEvent(GameControllerEventType.Axis, name, value); _lastControllerEventValueMap[name] = value; @@ -217,10 +205,6 @@ private void SetupAnalogAxisInput(GCControllerAxisInput axis, string name) if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) { - // ToDo: find ControllerId - //string controllerId = GetControllerIdFromIndex(0); - //GameControllerEventInternal?.Invoke(this, new GameControllerEventArgs(controllerId, GameControllerEventType.Axis, name, value)); - RaiseEvent(GameControllerEventType.Axis, name, value); _lastControllerEventValueMap[name] = value; From 56eaa803149dda3f3a8b64dde23835f7a9da64b5 Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Sat, 6 Sep 2025 13:43:34 +0200 Subject: [PATCH 03/12] split "controllerdevice" to "controller device" --- .../PlatformServices/GameController/GamepadControllerBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BrickController2/BrickController2/PlatformServices/GameController/GamepadControllerBase.cs b/BrickController2/BrickController2/PlatformServices/GameController/GamepadControllerBase.cs index a8f33c5c..6948a653 100644 --- a/BrickController2/BrickController2/PlatformServices/GameController/GamepadControllerBase.cs +++ b/BrickController2/BrickController2/PlatformServices/GameController/GamepadControllerBase.cs @@ -36,7 +36,7 @@ protected GamepadControllerBase(IGameControllerServiceInternal controllerService /// - /// Native instance of controllerdevice + /// Native instance of controller device /// public TControllerDevice ControllerDevice { get; } From 1ba447bfb3f54abd2edfb465e87b9265bf6b635a Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Sat, 6 Sep 2025 13:46:01 +0200 Subject: [PATCH 04/12] split "Controllerdevice" to "Controller device" --- .../PlatformServices/GameController/GameControllerService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GameControllerService.cs b/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GameControllerService.cs index 9abe20bf..f65b70b7 100644 --- a/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GameControllerService.cs +++ b/BrickController2/BrickController2.WinUI/PlatformServices/GameController/GameControllerService.cs @@ -55,7 +55,7 @@ private void Gamepad_GamepadRemoved(object? sender, Gamepad gamepad) { if (TryRemove(x => x.ControllerDevice == gamepad, out var controller)) { - _logger.LogInformation("ControllerDevice has been removed ControllerId:{controllerId}", controller.ControllerId); + _logger.LogInformation("Controller device has been removed ControllerId:{controllerId}", controller.ControllerId); } }); } From 9956ceeb07ae792b10c7530d15c2b4b506a6641b Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Sat, 6 Sep 2025 13:48:35 +0200 Subject: [PATCH 05/12] codebase simplified --- .../GameController/GameControllerService.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs index 3dfdd811..c85cfcc4 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs @@ -31,16 +31,14 @@ protected override void InitializeCurrentControllers() // register GCController events _didDisconnectNotification = GCController.Notifications.ObserveDidDisconnect((sender, args) => { - var controller = args.Notification.Object as GCController; - if (controller != null) + if (args.Notification.Object is GCController controller) { ControllerRemoved(controller); } }); _didConnectNotification = GCController.Notifications.ObserveDidConnect((sender, args) => { - var controller = args.Notification.Object as GCController; - if (controller != null) + if (args.Notification.Object is GCController controller) { ControllerAdded(controller); } From 220ec02efa97b8ed792817d3881855bc4131033b Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Sat, 6 Sep 2025 13:51:20 +0200 Subject: [PATCH 06/12] split "ControllerDevice" to "Controller device" --- .../PlatformServices/GameController/GameControllerService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs index c85cfcc4..d0917d62 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs @@ -65,7 +65,7 @@ private void ControllerRemoved(GCController controller) { if (TryRemove(x => x.ControllerDevice == controller, out var controllerDevice)) { - _logger.LogInformation("ControllerDevice has been removed ControllerId:{controllerId}", controllerDevice.ControllerId); + _logger.LogInformation("Controller device has been removed ControllerId:{controllerId}", controllerDevice.ControllerId); } } } From 510a368a983fc0bafb314e1c6ccdcd8ca0647052 Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Sat, 6 Sep 2025 14:19:05 +0200 Subject: [PATCH 07/12] changed variable name "gamepad" to "controller" --- .../GameController/GameControllerService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs index d0917d62..17722ee6 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs @@ -79,13 +79,13 @@ private void AddDevices(IEnumerable controllers) { lock (_lockObject) { - foreach (var gamepad in controllers) + foreach (var controller in controllers) { // If PlayerIndex is unset then assign the next free player index - AssignNextAvailablePlayerIndex(gamepad); + AssignNextAvailablePlayerIndex(controller); // get first unused number and apply it - var newController = new GamepadController(this, gamepad); + var newController = new GamepadController(this, controller); AddController(newController); } From 5373ae0d5dce3f8ac8e67d8d6d97bb42d4f9f7cf Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Sat, 6 Sep 2025 14:32:09 +0200 Subject: [PATCH 08/12] static array of ValidPlayerIndexes --- .../GameController/GameControllerService.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs index 17722ee6..11bfe194 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GameControllerService.cs @@ -10,6 +10,11 @@ namespace BrickController2.iOS.PlatformServices.GameController { internal class GameControllerService : GameControllerServiceBase { + private static readonly GCControllerPlayerIndex[] ValidPlayerIndexes = Enum.GetValues(typeof(GCControllerPlayerIndex)) + .Cast() + .Where(i => i != GCControllerPlayerIndex.Unset) + .ToArray(); + private NSObject? _didConnectNotification; private NSObject? _didDisconnectNotification; @@ -99,18 +104,15 @@ private void AddDevices(IEnumerable controllers) private void AssignNextAvailablePlayerIndex(GCController controller) { if (controller.PlayerIndex != GCControllerPlayerIndex.Unset) - { return; - } var usedIndexes = GCController.Controllers .Where(c => c.PlayerIndex != GCControllerPlayerIndex.Unset) .Select(c => c.PlayerIndex) .ToHashSet(); - foreach (GCControllerPlayerIndex index in Enum.GetValues(typeof(GCControllerPlayerIndex))) + foreach (var index in ValidPlayerIndexes) { - if (index == GCControllerPlayerIndex.Unset) continue; if (!usedIndexes.Contains(index)) { controller.PlayerIndex = index; From aff7c47247b5c36d5613be999a71252b76403d44 Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Wed, 10 Sep 2025 06:08:55 +0200 Subject: [PATCH 09/12] Use GCController.VendorName if available as controller's displayed name --- .../GameController/GamepadController.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs index e488d54e..32f0fb2f 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs @@ -30,7 +30,7 @@ public GamepadController(GameControllerService service, GCController controller) // initialize properties GameControllerType gameControllerType = GetGameControllerType(controller); - Name = GetDisplayName(gameControllerType); + Name = GetDisplayName(controller, gameControllerType); ControllerNumber = (int)controller.PlayerIndex; ControllerId = GetControllerIdFromNumber(ControllerNumber); @@ -212,9 +212,14 @@ private void SetupAnalogAxisInput(GCControllerAxisInput axis, string name) }; } - private static string GetDisplayName(GameControllerType device) + private static string GetDisplayName(GCController controller, GameControllerType gameControllerType) { - return device switch + if (!string.IsNullOrEmpty(controller.VendorName)) + { + return controller.VendorName; + } + + return gameControllerType switch { GameControllerType.Micro => "Micro Gamepad", GameControllerType.Standard => "Standard Gamepad", @@ -222,5 +227,4 @@ private static string GetDisplayName(GameControllerType device) _ => "Unknown Gamepad", }; } - } \ No newline at end of file From 47ea4062bdbc299eda1aff5dac1e0c180146be67 Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Wed, 10 Sep 2025 06:31:25 +0200 Subject: [PATCH 10/12] use HasValueChanged from base class --- .../GameController/GamepadController.cs | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs index 32f0fb2f..10a48dbf 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using BrickController2.PlatformServices.GameController; using GameController; @@ -17,8 +16,6 @@ private enum GameControllerType Extended }; - private readonly IDictionary _lastControllerEventValueMap = new Dictionary(); - /// /// Constructor /// @@ -27,9 +24,9 @@ private enum GameControllerType public GamepadController(GameControllerService service, GCController controller) : base(service, controller) { - // initialize properties GameControllerType gameControllerType = GetGameControllerType(controller); + // initialize properties Name = GetDisplayName(controller, gameControllerType); ControllerNumber = (int)controller.PlayerIndex; ControllerId = GetControllerIdFromNumber(ControllerNumber); @@ -144,11 +141,9 @@ private void SetupDigitalButtonInput(GCControllerButtonInput button, string name { value = isPressed ? 1.0F : 0.0F; - if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) + if (HasValueChanged(name, value)) { RaiseEvent(GameControllerEventType.Button, name, value); - - _lastControllerEventValueMap[name] = value; } }; } @@ -159,11 +154,9 @@ private void SetupAnalogButtonInput(GCControllerButtonInput button, string name) { value = value < 0.1 ? 0.0F : value; - if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) + if (HasValueChanged(name, value)) { RaiseEvent(GameControllerEventType.Axis, name, value); - - _lastControllerEventValueMap[name] = value; } }; } @@ -182,11 +175,9 @@ private void SetupDigitalAxisInput(GCControllerAxisInput axis, string name) else if (value > 0.1F) value = 1.0F; else value = 0.0F; - if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) + if (HasValueChanged(name, value)) { RaiseEvent(GameControllerEventType.Axis, name, value); - - _lastControllerEventValueMap[name] = value; } }; } @@ -203,11 +194,9 @@ private void SetupAnalogAxisInput(GCControllerAxisInput axis, string name) { value = AdjustControllerValue(value); - if (!_lastControllerEventValueMap.ContainsKey(name) || !AreAlmostEqual(_lastControllerEventValueMap[name], value)) + if (HasValueChanged(name, value)) { RaiseEvent(GameControllerEventType.Axis, name, value); - - _lastControllerEventValueMap[name] = value; } }; } From 86b8d19023cc0ce459a66d3cb870bbe35a1f9619 Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Wed, 10 Sep 2025 06:33:51 +0200 Subject: [PATCH 11/12] use of constants BUTTON_PRESSED and BUTTON_RELEASED --- .../PlatformServices/GameController/GamepadController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs index 10a48dbf..d9726e4d 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs @@ -139,7 +139,7 @@ private void SetupDigitalButtonInput(GCControllerButtonInput button, string name { button.ValueChangedHandler = (btn, value, isPressed) => { - value = isPressed ? 1.0F : 0.0F; + value = isPressed ? BUTTON_PRESSED : BUTTON_RELEASED; if (HasValueChanged(name, value)) { From e3e78a2f850f86126ee6ad758b402b50afc5711b Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Wed, 10 Sep 2025 06:45:18 +0200 Subject: [PATCH 12/12] use switch-expression and constants to adjust value --- .../GameController/GamepadController.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs index d9726e4d..d490c26d 100644 --- a/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs +++ b/BrickController2/BrickController2.iOS/PlatformServices/GameController/GamepadController.cs @@ -171,9 +171,13 @@ private void SetupDigitalAxisInput(GCControllerAxisInput axis, string name) { axis.ValueChangedHandler = (ax, value) => { - if (value < -0.1F) value = -1.0F; - else if (value > 0.1F) value = 1.0F; - else value = 0.0F; + // adjust value + value = value switch + { + < -0.1f => AXIS_MIN_VALUE, + > 0.1f => AXIS_MAX_VALUE, + _ => AXIS_ZERO_VALUE + }; if (HasValueChanged(name, value)) {