Skip to content

Commit

Permalink
fix(reg): Fix pointer capture broken on Firefox
Browse files Browse the repository at this point in the history
  • Loading branch information
dr1rrb committed May 11, 2023
1 parent 65f2ccb commit ccb7a46
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 78 deletions.
18 changes: 14 additions & 4 deletions src/Uno.UI/UI/Xaml/Input/Pointer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Text;
using System.Threading;
using Uno;

using PointerIdentifier = Windows.Devices.Input.PointerIdentifier;

#if HAS_UNO_WINUI
using Microsoft.UI.Input;
Expand All @@ -27,7 +27,17 @@ public Pointer(uint id, PointerDeviceType type, bool isInContact, bool isInRange
IsInContact = isInContact;
IsInRange = isInRange;

UniqueId = new Windows.Devices.Input.PointerIdentifier((Windows.Devices.Input.PointerDeviceType)type, id);
UniqueId = new PointerIdentifier((Windows.Devices.Input.PointerDeviceType)type, id);
}

internal Pointer(PointerIdentifier uniqueId, bool isInContact, bool isInRange)
{
PointerId = uniqueId.Id;
PointerDeviceType = uniqueId.Type;
IsInContact = isInContact;
IsInRange = isInRange;

UniqueId = uniqueId;
}

#if __WASM__
Expand All @@ -36,14 +46,14 @@ internal Pointer(uint id, PointerDeviceType type)
PointerId = id;
PointerDeviceType = type;

UniqueId = new Windows.Devices.Input.PointerIdentifier((Windows.Devices.Input.PointerDeviceType)type, id);
UniqueId = new PointerIdentifier((Windows.Devices.Input.PointerDeviceType)type, id);
}
#endif

/// <summary>
/// A unique identifier which contains <see cref="PointerDeviceType"/> and <see cref="PointerId"/>.
/// </summary>
internal Windows.Devices.Input.PointerIdentifier UniqueId { get; }
internal PointerIdentifier UniqueId { get; }

public uint PointerId { get; }

Expand Down
5 changes: 2 additions & 3 deletions src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ partial class PointerRoutedEventArgs

internal PointerRoutedEventArgs(
double timestamp,
uint pointerId,
PointerDeviceType pointerType,
PointerIdentifier pointerUniqueId,
Point absolutePosition,
bool isInContact,
bool isInRange,
Expand All @@ -46,7 +45,7 @@ internal PointerRoutedEventArgs(
_wheel = wheel;

FrameId = ToFrameId(timestamp);
Pointer = new Pointer(pointerId, pointerType, isInContact, isInRange);
Pointer = new Pointer(pointerUniqueId, isInContact, isInRange);
KeyModifiers = keys;
OriginalSource = source;
}
Expand Down
24 changes: 22 additions & 2 deletions src/Uno.UI/UI/Xaml/Internal/PointerCapture.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,36 @@

using System;
using System.Linq;
using Windows.Devices.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Uno.Foundation.Logging;

namespace Uno.UI.Xaml.Core;

internal partial class PointerCapture
{
partial void CaptureNative(UIElement target, Pointer pointer)
=> WindowManagerInterop.SetPointerCapture(target.HtmlId, pointer.PointerId);
{
if (PointerIdentifierPool.TryGetNative(pointer.UniqueId, out var native))
{
WindowManagerInterop.SetPointerCapture(target.HtmlId, native.Id);
}
else if (this.Log().IsEnabled(LogLevel.Warning))
{
this.Log().Warn($"Cannot capture pointer, could not find native pointer id for managed pointer id {pointer.UniqueId}");
}
}

partial void ReleaseNative(UIElement target, Pointer pointer)
=> WindowManagerInterop.ReleasePointerCapture(target.HtmlId, pointer.PointerId);
{
if (PointerIdentifierPool.TryGetNative(pointer.UniqueId, out var native))
{
WindowManagerInterop.ReleasePointerCapture(target.HtmlId, native.Id);
}
else if (this.Log().IsEnabled(LogLevel.Warning))
{
this.Log().Warn($"Cannot release pointer, could not find native pointer id for managed pointer id {pointer.UniqueId}");
}
}
}
6 changes: 2 additions & 4 deletions src/Uno.UI/UI/Xaml/Internal/RootVisual.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,7 @@ private static void ProcessPointerDown(PointerRoutedEventArgs args)

#if __WASM__
private static void ProcessPointerCancelledWasm(PointerRoutedEventArgs args)
{
RemoveActivePointer(args.Pointer.UniqueId);
}
=> PointerIdentifierPool.ReleaseManaged(args.Pointer.UniqueId);
#endif

internal void ProcessPointerUp(PointerRoutedEventArgs args, bool isAfterHandledUp = false)
Expand Down Expand Up @@ -200,7 +198,7 @@ internal void ProcessPointerUp(PointerRoutedEventArgs args, bool isAfterHandledU
ReleaseCaptures(args.Reset(canBubbleNatively: false));

#if __WASM__
RemoveActivePointer(args.Pointer.UniqueId);
PointerIdentifierPool.ReleaseManaged(args.Pointer.UniqueId);
#endif
}

Expand Down
39 changes: 2 additions & 37 deletions src/Uno.UI/UI/Xaml/UIElement.Pointers.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,41 +242,7 @@ public static void OnNativePointerEvent()
}
}

private static readonly Dictionary<PointerIdentifier, PointerIdentifier> _nativeToManagedPointerId = new();
private static readonly Dictionary<PointerIdentifier, PointerIdentifier> _managedToNativePointerId = new();
private static uint _lastUsedId;

private static uint TransformPointerId(PointerIdentifier nativeId)
{
if (_nativeToManagedPointerId.TryGetValue(nativeId, out var managedId))
{
return managedId.Id;
}

managedId = new PointerIdentifier(nativeId.Type, ++_lastUsedId);
_managedToNativePointerId[managedId] = nativeId;
_nativeToManagedPointerId[nativeId] = managedId;

return managedId.Id;
}

internal static void RemoveActivePointer(PointerIdentifier managedId)
{
if (_managedToNativePointerId.TryGetValue(managedId, out var nativeId))
{
_managedToNativePointerId.Remove(managedId);
_nativeToManagedPointerId.Remove(nativeId);

if (_managedToNativePointerId.Count == 0)
{
_lastUsedId = 0; // We reset the pointer ID only when there is no active pointer.
}
}
else if (typeof(UIElement).Log().IsEnabled(LogLevel.Warning))
{
typeof(UIElement).Log().Warn($"Received an invalid managed pointer id {managedId}");
}
}


private static PointerRoutedEventArgs ToPointerArgs(
UIElement snd,
Expand All @@ -287,7 +253,7 @@ private static PointerRoutedEventArgs ToPointerArgs(
const int exitOrUp = (int)(NativePointerEvent.pointerout | NativePointerEvent.pointerup);

var pointerType = (PointerDeviceType)args.deviceType;
var pointerId = TransformPointerId(new PointerIdentifier((Windows.Devices.Input.PointerDeviceType)pointerType, (uint)args.pointerId));
var pointerId = PointerIdentifierPool.RentManaged(new PointerIdentifier(pointerType, (uint)args.pointerId));

var src = GetElementFromHandle(args.srcHandle) ?? (UIElement)snd;
var position = new Point(args.x, args.y);
Expand All @@ -314,7 +280,6 @@ private static PointerRoutedEventArgs ToPointerArgs(
return new PointerRoutedEventArgs(
args.timestamp,
pointerId,
pointerType,
position,
isInContact,
isInRange,
Expand Down
55 changes: 27 additions & 28 deletions src/Uno.UWP/Devices/Input/PointerIdentifier.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
using System;
using System.Linq;

namespace Windows.Devices.Input
namespace Windows.Devices.Input;

internal readonly struct PointerIdentifier : IEquatable<PointerIdentifier>
{
internal readonly struct PointerIdentifier : IEquatable<PointerIdentifier>
{
private readonly long _uid;
private readonly long _uid;

public PointerIdentifier(PointerDeviceType type, uint id)
{
_uid = (long)type << 32 | id;
}
public PointerIdentifier(PointerDeviceType type, uint id)
{
_uid = (long)type << 32 | id;
}

public uint Id => unchecked((uint)(_uid & 0xFFFF_FFFF));
public uint Id => unchecked((uint)(_uid & 0xFFFF_FFFF));

public PointerDeviceType Type => unchecked((PointerDeviceType)(_uid >> 32));
public PointerDeviceType Type => unchecked((PointerDeviceType)(_uid >> 32));

/// <inheritdoc />
public override int GetHashCode()
=> _uid.GetHashCode();
/// <inheritdoc />
public override int GetHashCode()
=> _uid.GetHashCode();

/// <inheritdoc />
public override bool Equals(object obj)
=> obj is PointerIdentifier other && Equals(this, other);
/// <inheritdoc />
public override bool Equals(object obj)
=> obj is PointerIdentifier other && Equals(this, other);

/// <inheritdoc />
public bool Equals(PointerIdentifier other)
=> Equals(this, other);
/// <inheritdoc />
public bool Equals(PointerIdentifier other)
=> Equals(this, other);

private static bool Equals(PointerIdentifier left, PointerIdentifier right)
=> left._uid == right._uid;
private static bool Equals(PointerIdentifier left, PointerIdentifier right)
=> left._uid == right._uid;

public static bool operator ==(PointerIdentifier left, PointerIdentifier right)
=> Equals(left, right);
public static bool operator ==(PointerIdentifier left, PointerIdentifier right)
=> Equals(left, right);

public static bool operator !=(PointerIdentifier left, PointerIdentifier right)
=> !Equals(left, right);
public static bool operator !=(PointerIdentifier left, PointerIdentifier right)
=> !Equals(left, right);

public static implicit operator long(PointerIdentifier identifier)
=> identifier._uid;
}
public static implicit operator long(PointerIdentifier identifier)
=> identifier._uid;
}
48 changes: 48 additions & 0 deletions src/Uno.UWP/Devices/Input/PointerIdentifierPool.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Uno.Foundation.Logging;

namespace Windows.Devices.Input;

internal static class PointerIdentifierPool
{
private static readonly Dictionary<PointerIdentifier, PointerIdentifier> _nativeToManagedPointerId = new();
private static readonly Dictionary<PointerIdentifier, PointerIdentifier> _managedToNativePointerId = new();
private static uint _lastUsedId;

public static PointerIdentifier RentManaged(PointerIdentifier nativeId)
{
if (_nativeToManagedPointerId.TryGetValue(nativeId, out var managedId))
{
return managedId;
}

managedId = new PointerIdentifier(nativeId.Type, ++_lastUsedId);
_managedToNativePointerId[managedId] = nativeId;
_nativeToManagedPointerId[nativeId] = managedId;

return managedId;
}

public static bool TryGetNative(PointerIdentifier managedId, out PointerIdentifier nativeId)
=> _managedToNativePointerId.TryGetValue(managedId, out nativeId);

public static void ReleaseManaged(PointerIdentifier managedId)
{
if (_managedToNativePointerId.TryGetValue(managedId, out var nativeId))
{
_managedToNativePointerId.Remove(managedId);
_nativeToManagedPointerId.Remove(nativeId);

if (_managedToNativePointerId.Count == 0)
{
_lastUsedId = 0; // We reset the pointer ID only when there is no active pointer.
}
}
else if (typeof(PointerIdentifierPool).Log().IsEnabled(LogLevel.Warning))
{
typeof(PointerIdentifierPool).Log().Warn($"Received an invalid managed pointer id {managedId}");
}
}
}

0 comments on commit ccb7a46

Please sign in to comment.