Skip to content

Commit a34bd86

Browse files
committed
Quick set of debugging to report button presses on controllers
1 parent 926f65d commit a34bd86

File tree

12 files changed

+251
-5
lines changed

12 files changed

+251
-5
lines changed

engine/Orbit.Input/GameControllers/GameController.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace Orbit.Input;
1+
using System.Collections.Concurrent;
2+
3+
namespace Orbit.Input;
24

35
/// <summary>
46
/// Represents a physical game controller that is connected to a device.
@@ -7,6 +9,8 @@ public partial class GameController
79
{
810
private readonly WeakEventManager weakEventManager = new();
911

12+
public string Name { get; private set; } = string.Empty;
13+
1014
/// <summary>
1115
/// Gets the <see cref="Stick"/> that represents the D-pad on the game controller.
1216
/// </summary>
@@ -61,7 +65,25 @@ public partial class GameController
6165
/// Gets the <see cref="Shoulder"/> that represents the right hand shoulder on the controller.
6266
/// </summary>
6367
public Shoulder RightShoulder { get; }
68+
69+
/// <summary>
70+
/// U
71+
/// </summary>
72+
public IReadOnlyList<ButtonValue<bool>> UnmappedButtons => unmappedButtons.Values.ToList().AsReadOnly();
6473

74+
private ConcurrentDictionary<string, ButtonValue<bool>> unmappedButtons = new ();
75+
76+
internal void RaiseUnmappedButtonChange(string buttonName, bool isPressed)
77+
{
78+
if (unmappedButtons.TryGetValue(buttonName, out var button) is false)
79+
{
80+
button = new ButtonValue<bool>(this, buttonName);
81+
unmappedButtons.TryAdd(buttonName, button);
82+
}
83+
84+
button.Value = isPressed;
85+
}
86+
6587
/// <summary>
6688
/// Event that is raised when a button on the game controller is detected as being pressed or released.
6789
/// </summary>

engine/Orbit.Input/Platforms/Android/GameController.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ public partial class GameController
77
{
88
private readonly int deviceId;
99

10-
public GameController(int deviceId)
10+
public GameController(int deviceId, string name)
1111
{
1212
this.deviceId = deviceId;
13+
Name = name;
1314

1415
Dpad = new Stick(this, nameof(Dpad));
1516
LeftStick = new Stick(this, nameof(LeftStick));
@@ -100,6 +101,10 @@ public bool OnKeyDown(InputEvent inputEvent)
100101
case KeyEvent { KeyCode: Keycode.ButtonR1 }:
101102
RightShoulder.Button.Value = true;
102103
break;
104+
105+
case KeyEvent keyEvent:
106+
RaiseUnmappedButtonChange(keyEvent.KeyCode.ToString(), false);
107+
break;
103108
}
104109

105110
return true;
@@ -151,6 +156,10 @@ public bool OnKeyUp(InputEvent inputEvent)
151156
case KeyEvent { KeyCode: Keycode.ButtonR1 }:
152157
RightShoulder.Button.Value = false;
153158
break;
159+
160+
case KeyEvent keyEvent:
161+
RaiseUnmappedButtonChange(keyEvent.KeyCode.ToString(), false);
162+
break;
154163
}
155164

156165
return true;

engine/Orbit.Input/Platforms/Android/GameControllerManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public partial Task StartDiscovery()
5151

5252
if (sources.HasFlag(InputSourceType.Gamepad) || sources.HasFlag(InputSourceType.Joystick))
5353
{
54-
OnGameControllerConnected(new GameController(deviceId));
54+
OnGameControllerConnected(new GameController(deviceId, device.Name ?? "Unknown"));
5555
}
5656
}
5757

engine/Orbit.Input/Platforms/MacCatalyst/GameController.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System.Diagnostics;
2+
using System.Runtime.Intrinsics.Arm;
3+
24
using Foundation;
35
using GameController;
46

@@ -24,13 +26,20 @@ public GameController(GCController controller)
2426
East = new ButtonValue<bool>(this, nameof(East));
2527
West = new ButtonValue<bool>(this, nameof(West));
2628
Pause = new ButtonValue<bool>(this, nameof(Pause));
27-
28-
if (OperatingSystem.IsMacOSVersionAtLeast(16))
29+
30+
Name = controller.VendorName ?? "Unknown";
31+
32+
if (OperatingSystem.IsMacCatalystVersionAtLeast(16))
2933
{
3034
controller.PhysicalInputProfile.ValueDidChangeHandler += Changed;
3135
}
3236
}
3337

38+
private void ValueDidChangeHandler(GCPhysicalInputProfile arg1, GCControllerElement arg2)
39+
{
40+
Changed(arg1, arg2);
41+
}
42+
3443
private void Changed(GCPhysicalInputProfile gamepad, GCControllerElement element)
3544
{
3645
Debug.WriteLine($"{element}");
@@ -82,6 +91,17 @@ private void Changed(GCPhysicalInputProfile gamepad, GCControllerElement element
8291
RightStick.XAxis.Value = directionPad.XAxis.Value;
8392
RightStick.YAxis.Value = directionPad.YAxis.Value;
8493
break;
94+
95+
case GCControllerDirectionPad directionPad when directionPad.Aliases.Contains(new NSString("Direction Pad")):
96+
Dpad.XAxis.Value = directionPad.XAxis.Value;
97+
Dpad.YAxis.Value = directionPad.YAxis.Value;
98+
break;
99+
100+
case GCControllerButtonInput buttonInput:
101+
var buttonName = buttonInput.LocalizedName ?? "Unknown";
102+
103+
RaiseUnmappedButtonChange(buttonName, buttonInput.IsPressed);
104+
break;
85105
}
86106
}
87107
}

engine/Orbit.Input/Platforms/iOS/GameController.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public GameController(GCController controller)
2929
West = new ButtonValue<bool>(this, nameof(West));
3030
Pause = new ButtonValue<bool>(this, nameof(Pause));
3131

32+
Name = controller.VendorName ?? "Unknown";
33+
3234
if (OperatingSystem.IsIOSVersionAtLeast(16))
3335
{
3436
controller.PhysicalInputProfile.ValueDidChangeHandler += Changed;
@@ -86,6 +88,12 @@ private void Changed(GCPhysicalInputProfile gamepad, GCControllerElement element
8688
RightStick.XAxis.Value = directionPad.XAxis.Value;
8789
RightStick.YAxis.Value = directionPad.YAxis.Value;
8890
break;
91+
92+
case GCControllerButtonInput buttonInput:
93+
var buttonName = buttonInput.LocalizedName ?? "Unknown";
94+
95+
RaiseUnmappedButtonChange(buttonName, buttonInput.IsPressed);
96+
break;
8997
}
9098
}
9199
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Platformer;
2+
3+
public class ChangeViewModel
4+
{
5+
public ChangeViewModel(string description)
6+
{
7+
Description = description;
8+
}
9+
10+
public string Description { get; }
11+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<ContentPage
4+
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
5+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
6+
xmlns:local="clr-namespace:Platformer"
7+
x:Class="Platformer.GameControllerPage"
8+
x:DataType="local:GameControllerPageViewModel">
9+
10+
<Grid
11+
RowDefinitions="Auto,*"
12+
ColumnDefinitions="*,Auto">
13+
<Picker
14+
ItemsSource="{Binding GameControllers}"
15+
ItemDisplayBinding="{Binding Name, x:DataType={x:Null}}"
16+
SelectedItem="{Binding SelectedGameController}" />
17+
18+
<Button
19+
Text="Refresh"
20+
Command="{Binding RefreshCommand}"
21+
Grid.Column="1" />
22+
23+
<CollectionView
24+
ItemsSource="{Binding Changes}"
25+
Grid.Row="1"
26+
Grid.ColumnSpan="2">
27+
<CollectionView.ItemTemplate>
28+
<DataTemplate x:DataType="local:ChangeViewModel">
29+
<Label Text="{Binding Description}" />
30+
</DataTemplate>
31+
</CollectionView.ItemTemplate>
32+
</CollectionView>
33+
34+
</Grid>
35+
36+
</ContentPage>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Platformer;
8+
9+
public partial class GameControllerPage : ContentPage
10+
{
11+
public GameControllerPage(GameControllerPageViewModel viewModel)
12+
{
13+
InitializeComponent();
14+
BindingContext = viewModel;
15+
}
16+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System.Collections.ObjectModel;
2+
using System.ComponentModel;
3+
using System.Runtime.CompilerServices;
4+
using System.Windows.Input;
5+
6+
using Orbit.Input;
7+
8+
namespace Platformer;
9+
10+
public class GameControllerPageViewModel : INotifyPropertyChanged
11+
{
12+
private Orbit.Input.GameController? selectedGameController;
13+
private readonly Orbit.Input.GameControllerManager gameControllerManager;
14+
15+
public ObservableCollection<Orbit.Input.GameController> GameControllers { get; } = [];
16+
public ObservableCollection<ChangeViewModel> Changes { get; } = [];
17+
18+
public Orbit.Input.GameController? SelectedGameController
19+
{
20+
get => selectedGameController;
21+
set
22+
{
23+
if (selectedGameController is not null)
24+
{
25+
selectedGameController.ButtonChanged -= SelectedGameControllerOnButtonChanged;
26+
selectedGameController.ValueChanged -= SelectedGameControllerOnValueChanged;
27+
}
28+
29+
if (SetField(ref selectedGameController, value))
30+
{
31+
if (selectedGameController is not null)
32+
{
33+
AddChange($"Connected to controller '{selectedGameController.Name}'");
34+
selectedGameController.ButtonChanged += SelectedGameControllerOnButtonChanged;
35+
selectedGameController.ValueChanged += SelectedGameControllerOnValueChanged;
36+
}
37+
}
38+
}
39+
}
40+
41+
private void SelectedGameControllerOnValueChanged(object? sender, GameControllerValueChangedEventArgs e)
42+
{
43+
AddChange($"'{e.ButtonName}' button changed to {e.Value}");
44+
}
45+
46+
private void SelectedGameControllerOnButtonChanged(object? sender, GameControllerButtonChangedEventArgs e)
47+
{
48+
AddChange($"'{e.ButtonName}' was {(e.IsPressed ? "Pressed" : "Released")}");
49+
}
50+
51+
private void AddChange(string description)
52+
{
53+
Changes.Add(new ChangeViewModel($"{DateTime.Now:O} - {description}"));
54+
}
55+
56+
public ICommand RefreshCommand { get; }
57+
58+
public GameControllerPageViewModel(Orbit.Input.GameControllerManager gameControllerManager)
59+
{
60+
this.gameControllerManager = gameControllerManager;
61+
62+
this.gameControllerManager.GameControllerConnected += GameControllerManagerOnGameControllerConnected;
63+
64+
RefreshCommand = new Command(OnRefresh);
65+
}
66+
67+
private void GameControllerManagerOnGameControllerConnected(object? sender, GameControllerConnectedEventArgs e)
68+
{
69+
GameControllers.Add(e.GameController);
70+
}
71+
72+
private void OnRefresh()
73+
{
74+
try
75+
{
76+
GameControllers.Clear();
77+
78+
_ = this.gameControllerManager.StartDiscovery();
79+
80+
foreach (var gameController in gameControllerManager.GameControllers)
81+
{
82+
GameControllers.Add(gameController);
83+
}
84+
}
85+
catch (Exception e)
86+
{
87+
Console.WriteLine(e);
88+
throw;
89+
}
90+
}
91+
92+
public event PropertyChangedEventHandler? PropertyChanged;
93+
94+
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
95+
{
96+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
97+
}
98+
99+
private bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
100+
{
101+
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
102+
field = value;
103+
OnPropertyChanged(propertyName);
104+
return true;
105+
}
106+
}

games/Platformer/MainPage.xaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@
5353
Pressed="OnJumpButtonPressed"
5454
Released="OnJumpButtonReleased"
5555
Grid.Row="1" />
56+
57+
<Button
58+
Text="Controllers"
59+
HorizontalOptions="End"
60+
VerticalOptions="Start"
61+
Width="40"
62+
Height="40"
63+
Clicked="Button_OnClicked"
64+
Grid.Row="1" />
5665
</Grid>
5766

5867
</ContentPage>

0 commit comments

Comments
 (0)