Skip to content

Commit

Permalink
feat(Gamepad): GamepadAdded/Removed for WASM
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund committed Jun 1, 2022
1 parent dd0a1b2 commit 1160c40
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/Uno.UI/LinkerDefinition.Wasm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
<type fullname="Windows.Devices.Midi.MidiInPort">
<method name="DispatchMessage" />
</type>
<type fullname="Windows.Gaming.Input.Gamepad">
<method name="DispatchGamepadAdded" />
<method name="DispatchGamepadRemoved" />
</type>
<type fullname="Uno.Devices.Enumeration.Internal.Providers.Midi.MidiDeviceConnectionWatcher">
<method name="DispatchStateChanged" />
</type>
Expand Down
51 changes: 51 additions & 0 deletions src/Uno.UI/ts/Windows/Gaming/Input/Gamepad.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
namespace Windows.Gaming.Input {
export class Gamepad {

private static dispatchGamepadAdded: (id: string) => number;
private static dispatchGamepadRemoved: (id: string) => number;

public static getConnectedGamepadIds(): string {
const gamepads = navigator.getGamepads();
const separator = ";";
var result = '';
for (var i = 0; i < gamepads.length; i++) {
if (gamepads[i]) {
result += gamepads[i].index + separator;
}
}
return result;
}

public static startGamepadAdded() {
window.addEventListener("gamepadconnected", Gamepad.onGamepadConnected);
}

public static endGamepadAdded() {
window.removeEventListener("gamepadconnected", Gamepad.onGamepadConnected);
}

public static startGamepadRemoved() {
window.addEventListener("gamepaddisconnected", Gamepad.onGamepadDisconnected);
}

public static endGamepadRemoved() {
window.removeEventListener("gamepaddisconnected", Gamepad.onGamepadDisconnected);
}

private static onGamepadConnected(e : any) {
if (!Gamepad.dispatchGamepadAdded) {
Gamepad.dispatchGamepadAdded = (<any>Module).mono_bind_static_method(
"[Uno] Windows.Gaming.Input.Gamepad:DispatchGamepadAdded");
}
Gamepad.dispatchGamepadAdded(e.gamepad.index.toString());
}

private static onGamepadDisconnected(e : any) {
if (!Gamepad.dispatchGamepadRemoved) {
Gamepad.dispatchGamepadRemoved = (<any>Module).mono_bind_static_method(
"[Uno] Windows.Gaming.Input.Gamepad:DispatchGamepadRemoved");
}
Gamepad.dispatchGamepadRemoved(e.gamepad.index.toString());
}
}
}
2 changes: 1 addition & 1 deletion src/Uno.UWP/Gaming/Input/Gamepad.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if __ANDROID__ || __IOS__ || __MACOS__
#if __ANDROID__ || __IOS__ || __MACOS__ || __WASM__
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down
111 changes: 111 additions & 0 deletions src/Uno.UWP/Gaming/Input/Gamepad.wasm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#if __WASM__
using System;
using System.Collections.Generic;
using System.Linq;
using Uno;
using Uno.Extensions;
using Uno.Foundation;

namespace Windows.Gaming.Input
{
public partial class Gamepad
{
private const string JsType = "Windows.Gaming.Input.Gamepad";
private const char IdSeparator = ';';

private readonly static Dictionary<string, Gamepad> _gamepadCache =
new Dictionary<string, Gamepad>();

private readonly string _id;

private Gamepad(string id)
{
_id = id;
}

[Preserve]
public static int DispatchGamepadAdded(string id)
{
Gamepad gamepad;
lock (_gamepadCache)
{
if (!_gamepadCache.TryGetValue(id, out gamepad))
{
gamepad = new Gamepad(id);
_gamepadCache.Add(id, gamepad);
}
}
_gamepadAdded?.Invoke(null, gamepad);
return 0;
}

[Preserve]
public static int DispatchGamepadRemoved(string id)
{
Gamepad gamepad;
lock (_gamepadCache)
{
if (!_gamepadCache.TryGetValue(id, out gamepad))
{
gamepad = new Gamepad(id);
_gamepadCache.Add(id, gamepad);
}
}
_gamepadRemoved?.Invoke(null, gamepad);
return 0;
}

private static IReadOnlyList<Gamepad> GetGamepadsInternal()
{
var getConnectedGamepadIdsCommand = $"{JsType}.getConnectedGamepadIds()";
var serializedIds = WebAssemblyRuntime.InvokeJS(getConnectedGamepadIdsCommand);
var connectedGamepadIds = serializedIds.Split(new[] { IdSeparator }, StringSplitOptions.RemoveEmptyEntries);

lock (_gamepadCache)
{
var cachedGCControllers = _gamepadCache.Keys.ToArray();

//remove disconnected
var disconnectedDevices = cachedGCControllers.Except(connectedGamepadIds);
_gamepadCache.RemoveKeys(disconnectedDevices);

//add newly connected
foreach (var id in connectedGamepadIds)
{
if (!_gamepadCache.TryGetValue(id, out var gamepad))
{
gamepad = new Gamepad(id);
_gamepadCache.Add(id, gamepad);
}
}

return _gamepadCache.Values.OrderBy(g => g._id).ToArray();
}
}

private static void StartGamepadAdded()
{
var startGamepadAddedCommand = $"{JsType}.startGamepadAdded()";
WebAssemblyRuntime.InvokeJS(startGamepadAddedCommand);
}

private static void EndGamepadAdded()
{
var endGamepadAddedCommand = $"{JsType}.endGamepadAdded()";
WebAssemblyRuntime.InvokeJS(endGamepadAddedCommand);
}

private static void StartGamepadRemoved()
{
var startGamepadRemovedCommand = $"{JsType}.startGamepadRemoved()";
WebAssemblyRuntime.InvokeJS(startGamepadRemovedCommand);
}

private static void EndGamepadRemoved()
{
var endGamepadRemovedCommand = $"{JsType}.endGamepadRemoved()";
WebAssemblyRuntime.InvokeJS(endGamepadRemovedCommand);
}
}
}
#endif

0 comments on commit 1160c40

Please sign in to comment.