diff --git a/engine/Orbit.Input/GameControllers/GameController.cs b/engine/Orbit.Input/GameControllers/GameController.cs index cb71c59..dc78fd3 100644 --- a/engine/Orbit.Input/GameControllers/GameController.cs +++ b/engine/Orbit.Input/GameControllers/GameController.cs @@ -1,11 +1,13 @@ -namespace Orbit.Input; +using System.Collections.Concurrent; + +namespace Orbit.Input; /// /// Represents a physical game controller that is connected to a device. /// public partial class GameController { - private readonly WeakEventManager weakEventManager = new(); + public string Name { get; private set; } = string.Empty; /// /// Gets the that represents the D-pad on the game controller. @@ -61,34 +63,44 @@ public partial class GameController /// Gets the that represents the right hand shoulder on the controller. /// public Shoulder RightShoulder { get; } - + /// - /// Event that is raised when a button on the game controller is detected as being pressed or released. + /// U /// - public event EventHandler ButtonChanged + public IReadOnlyList> UnmappedButtons => unmappedButtons.Values.ToList().AsReadOnly(); + + private ConcurrentDictionary> unmappedButtons = new (); + + internal void RaiseUnmappedButtonChange(string buttonName, bool isPressed) { - add => weakEventManager.AddEventHandler(value); - remove => weakEventManager.RemoveEventHandler(value); + if (unmappedButtons.TryGetValue(buttonName, out var button) is false) + { + button = new ButtonValue(this, buttonName); + unmappedButtons.TryAdd(buttonName, button); + } + + button.Value = isPressed; } - + + /// + /// Event that is raised when a button on the game controller is detected as being pressed or released. + /// + public event EventHandler? ButtonChanged; + /// /// Event that is raised when a button that supports a varying value on the game controller is detected as being pressed or released to some degree. /// - public event EventHandler ValueChanged - { - add => weakEventManager.AddEventHandler(value); - remove => weakEventManager.RemoveEventHandler(value); - } + public event EventHandler? ValueChanged; internal void RaiseButtonValueChanged(ButtonValue buttonValue) { switch (buttonValue) { case ButtonValue floatValue: - weakEventManager.HandleEvent(this, new GameControllerValueChangedEventArgs(buttonValue.Name, floatValue.Value), nameof(ValueChanged)); + ValueChanged?.Invoke(this, new GameControllerValueChangedEventArgs(buttonValue.Name, floatValue.Value)); break; case ButtonValue boolValue: - weakEventManager.HandleEvent(this, new GameControllerButtonChangedEventArgs(buttonValue.Name, boolValue.Value), nameof(ButtonChanged)); + ButtonChanged?.Invoke(this, new GameControllerButtonChangedEventArgs(buttonValue.Name, boolValue.Value)); break; } } diff --git a/engine/Orbit.Input/Platforms/Android/GameController.cs b/engine/Orbit.Input/Platforms/Android/GameController.cs index a82b34b..3838db4 100644 --- a/engine/Orbit.Input/Platforms/Android/GameController.cs +++ b/engine/Orbit.Input/Platforms/Android/GameController.cs @@ -7,9 +7,10 @@ public partial class GameController { private readonly int deviceId; - public GameController(int deviceId) + public GameController(int deviceId, string name) { this.deviceId = deviceId; + Name = name; Dpad = new Stick(this, nameof(Dpad)); LeftStick = new Stick(this, nameof(LeftStick)); @@ -100,6 +101,10 @@ public bool OnKeyDown(InputEvent inputEvent) case KeyEvent { KeyCode: Keycode.ButtonR1 }: RightShoulder.Button.Value = true; break; + + case KeyEvent keyEvent: + RaiseUnmappedButtonChange(keyEvent.KeyCode.ToString(), false); + break; } return true; @@ -151,6 +156,10 @@ public bool OnKeyUp(InputEvent inputEvent) case KeyEvent { KeyCode: Keycode.ButtonR1 }: RightShoulder.Button.Value = false; break; + + case KeyEvent keyEvent: + RaiseUnmappedButtonChange(keyEvent.KeyCode.ToString(), false); + break; } return true; diff --git a/engine/Orbit.Input/Platforms/Android/GameControllerManager.cs b/engine/Orbit.Input/Platforms/Android/GameControllerManager.cs index e57b70a..c9836e7 100644 --- a/engine/Orbit.Input/Platforms/Android/GameControllerManager.cs +++ b/engine/Orbit.Input/Platforms/Android/GameControllerManager.cs @@ -51,7 +51,7 @@ public partial Task StartDiscovery() if (sources.HasFlag(InputSourceType.Gamepad) || sources.HasFlag(InputSourceType.Joystick)) { - OnGameControllerConnected(new GameController(deviceId)); + OnGameControllerConnected(new GameController(deviceId, device.Name ?? "Unknown")); } } diff --git a/engine/Orbit.Input/Platforms/MacCatalyst/GameController.cs b/engine/Orbit.Input/Platforms/MacCatalyst/GameController.cs index a7f4077..c7f4d78 100644 --- a/engine/Orbit.Input/Platforms/MacCatalyst/GameController.cs +++ b/engine/Orbit.Input/Platforms/MacCatalyst/GameController.cs @@ -1,4 +1,6 @@ using System.Diagnostics; +using System.Runtime.Intrinsics.Arm; + using Foundation; using GameController; @@ -24,8 +26,10 @@ public GameController(GCController controller) East = new ButtonValue(this, nameof(East)); West = new ButtonValue(this, nameof(West)); Pause = new ButtonValue(this, nameof(Pause)); - - if (OperatingSystem.IsMacOSVersionAtLeast(16)) + + Name = controller.VendorName ?? "Unknown"; + + if (OperatingSystem.IsMacCatalystVersionAtLeast(16)) { controller.PhysicalInputProfile.ValueDidChangeHandler += Changed; } @@ -82,6 +86,17 @@ private void Changed(GCPhysicalInputProfile gamepad, GCControllerElement element RightStick.XAxis.Value = directionPad.XAxis.Value; RightStick.YAxis.Value = directionPad.YAxis.Value; break; + + case GCControllerDirectionPad directionPad when directionPad.Aliases.Contains(new NSString("Direction Pad")): + Dpad.XAxis.Value = directionPad.XAxis.Value; + Dpad.YAxis.Value = directionPad.YAxis.Value; + break; + + case GCControllerButtonInput buttonInput: + var buttonName = buttonInput.LocalizedName ?? "Unknown"; + + RaiseUnmappedButtonChange(buttonName, buttonInput.IsPressed); + break; } } } \ No newline at end of file diff --git a/engine/Orbit.Input/Platforms/iOS/GameController.cs b/engine/Orbit.Input/Platforms/iOS/GameController.cs index 3e4c379..e7c0f83 100644 --- a/engine/Orbit.Input/Platforms/iOS/GameController.cs +++ b/engine/Orbit.Input/Platforms/iOS/GameController.cs @@ -29,6 +29,8 @@ public GameController(GCController controller) West = new ButtonValue(this, nameof(West)); Pause = new ButtonValue(this, nameof(Pause)); + Name = controller.VendorName ?? "Unknown"; + if (OperatingSystem.IsIOSVersionAtLeast(16)) { controller.PhysicalInputProfile.ValueDidChangeHandler += Changed; @@ -86,6 +88,12 @@ private void Changed(GCPhysicalInputProfile gamepad, GCControllerElement element RightStick.XAxis.Value = directionPad.XAxis.Value; RightStick.YAxis.Value = directionPad.YAxis.Value; break; + + case GCControllerButtonInput buttonInput: + var buttonName = buttonInput.LocalizedName ?? "Unknown"; + + RaiseUnmappedButtonChange(buttonName, buttonInput.IsPressed); + break; } } } \ No newline at end of file diff --git a/games/Platformer/ChangeViewModel.cs b/games/Platformer/ChangeViewModel.cs new file mode 100644 index 0000000..3a7702e --- /dev/null +++ b/games/Platformer/ChangeViewModel.cs @@ -0,0 +1,11 @@ +namespace Platformer; + +public class ChangeViewModel +{ + public ChangeViewModel(string description) + { + Description = description; + } + + public string Description { get; } +} \ No newline at end of file diff --git a/games/Platformer/GameControllerPage.xaml b/games/Platformer/GameControllerPage.xaml new file mode 100644 index 0000000..09689f1 --- /dev/null +++ b/games/Platformer/GameControllerPage.xaml @@ -0,0 +1,36 @@ + + + + + + + +