feat(TouchHandler): Add pointerType info to touch event data (#773)
Adds a pointerType field to the native event for the gesture responder handlers. Basically, e.nativeEvent.pointerType is oneOf ["mouse", "pen", "touch"]. I'll need to follow up with documentation and examples for this. Adds behavior to serialize button information from the pointer event. E.g., a right-click will result in `isRightButton: true` on the pointer event data, similar to `isLeftButton` and `isMiddleButton` for left and middle buttons respectively. When using the pen, there is `isEraser` and `isBarrelButtonPressed`, as well as a `force` field (similar to the iOS 3D touch API) for press firmness. Each of these fields are not serialized if they are `false`, which will be the case for the majority of them most of the time (i.e., there is no impact on serialized data payload for touch, but a slight penalty for enumerating the properties at serialization time). *With the exception of `isLeftButton` and `force`, which is omnipresent in all the pointer event payloads. I don't believe this is a complete solution for right-click handling, but, in theory, building a proper API to support right-click and context menus could be built as JavaScript components on top of these layers. Fixes #772 Fixes #774
This commit is contained in:
Родитель
393334bd71
Коммит
b33642b885
|
@ -163,6 +163,7 @@
|
|||
<Compile Include="ReactPage.cs" />
|
||||
<Compile Include="ReactRootView.cs" />
|
||||
<Compile Include="Touch\IOnInterceptTouchEventListener.cs" />
|
||||
<Compile Include="Touch\PointerDeviceTypeExtensions.cs" />
|
||||
<Compile Include="Touch\TouchHandler.cs" />
|
||||
<Compile Include="Tracing\LoggingActivityBuilder.cs" />
|
||||
<Compile Include="Tracing\LoggingActivityBuilderExtensions.generated.cs">
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
using Windows.Devices.Input;
|
||||
|
||||
namespace ReactNative.Touch
|
||||
{
|
||||
static class PointerDeviceTypeExtensions
|
||||
{
|
||||
public static string GetPointerDeviceTypeName(this PointerDeviceType pointerDeviceType)
|
||||
{
|
||||
switch (pointerDeviceType)
|
||||
{
|
||||
case PointerDeviceType.Touch:
|
||||
return "touch";
|
||||
case PointerDeviceType.Pen:
|
||||
return "pen";
|
||||
case PointerDeviceType.Mouse:
|
||||
return "mouse";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ using ReactNative.UIManager;
|
|||
using ReactNative.UIManager.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Input;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
@ -46,17 +48,25 @@ namespace ReactNative.Touch
|
|||
throw new InvalidOperationException("A pointer with this ID already exists.");
|
||||
}
|
||||
|
||||
var reactView = GetReactViewTarget(e);
|
||||
var originalSource = e.OriginalSource as DependencyObject;
|
||||
var rootPoint = e.GetCurrentPoint(_view);
|
||||
var reactView = GetReactViewTarget(originalSource, rootPoint.Position);
|
||||
if (reactView != null && _view.CapturePointer(e.Pointer))
|
||||
{
|
||||
var reactTag = reactView.GetReactCompoundView().GetReactTagAtPoint(reactView,
|
||||
e.GetCurrentPoint(reactView).Position);
|
||||
var viewPoint = e.GetCurrentPoint(reactView);
|
||||
var reactTag = reactView.GetReactCompoundView().GetReactTagAtPoint(reactView, viewPoint.Position);
|
||||
var pointer = new ReactPointer();
|
||||
pointer.Target = reactTag;
|
||||
pointer.PointerId = e.Pointer.PointerId;
|
||||
pointer.Identifier = ++_pointerIDs;
|
||||
pointer.PointerType = e.Pointer.PointerDeviceType.GetPointerDeviceTypeName();
|
||||
pointer.IsLeftButton = viewPoint.Properties.IsLeftButtonPressed;
|
||||
pointer.IsRightButton = viewPoint.Properties.IsRightButtonPressed;
|
||||
pointer.IsMiddleButton = viewPoint.Properties.IsMiddleButtonPressed;
|
||||
pointer.IsHorizontalMouseWheel = viewPoint.Properties.IsHorizontalMouseWheel;
|
||||
pointer.IsEraser = viewPoint.Properties.IsEraser;
|
||||
pointer.ReactView = reactView;
|
||||
UpdatePointerForEvent(pointer, e);
|
||||
UpdatePointerForEvent(pointer, rootPoint, viewPoint);
|
||||
|
||||
var pointerIndex = _pointers.Count;
|
||||
_pointers.Add(pointer);
|
||||
|
@ -123,16 +133,15 @@ namespace ReactNative.Touch
|
|||
return -1;
|
||||
}
|
||||
|
||||
private UIElement GetReactViewTarget(PointerRoutedEventArgs e)
|
||||
private UIElement GetReactViewTarget(DependencyObject originalSource, Point point)
|
||||
{
|
||||
// If the target is not a child of the root view, then this pointer
|
||||
// event does not belong to React.
|
||||
if (!RootViewHelper.IsReactSubview(e.OriginalSource as DependencyObject))
|
||||
if (!RootViewHelper.IsReactSubview(originalSource))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var point = e.GetCurrentPoint(_view).Position;
|
||||
var sources = VisualTreeHelper.FindElementsInHostCoordinates(point, _view);
|
||||
|
||||
// Get the first React view that does not have pointer events set
|
||||
|
@ -167,15 +176,23 @@ namespace ReactNative.Touch
|
|||
|
||||
private void UpdatePointerForEvent(ReactPointer pointer, PointerRoutedEventArgs e)
|
||||
{
|
||||
var viewPoint = e.GetCurrentPoint(_view);
|
||||
var positionInRoot = viewPoint.Position;
|
||||
var positionInView = e.GetCurrentPoint(pointer.ReactView).Position;
|
||||
var rootPoint = e.GetCurrentPoint(_view);
|
||||
var viewPoint = e.GetCurrentPoint(pointer.ReactView);
|
||||
UpdatePointerForEvent(pointer, rootPoint, viewPoint);
|
||||
}
|
||||
|
||||
private void UpdatePointerForEvent(ReactPointer pointer, PointerPoint rootPoint, PointerPoint viewPoint)
|
||||
{
|
||||
var positionInRoot = rootPoint.Position;
|
||||
var positionInView = viewPoint.Position;
|
||||
|
||||
pointer.PageX = (float)positionInRoot.X;
|
||||
pointer.PageY = (float)positionInRoot.Y;
|
||||
pointer.LocationX = (float)positionInView.X;
|
||||
pointer.LocationY = (float)positionInView.Y;
|
||||
pointer.Timestamp = viewPoint.Timestamp / 1000; // Convert microseconds to milliseconds;
|
||||
pointer.Timestamp = rootPoint.Timestamp / 1000; // Convert microseconds to milliseconds;
|
||||
pointer.Force = rootPoint.Properties.Pressure;
|
||||
pointer.IsBarrelButtonPressed = rootPoint.Properties.IsBarrelButtonPressed;
|
||||
}
|
||||
|
||||
private void DispatchTouchEvent(TouchEventType touchEventType, List<ReactPointer> activePointers, int pointerIndex)
|
||||
|
@ -312,6 +329,30 @@ namespace ReactNative.Touch
|
|||
|
||||
[JsonProperty(PropertyName = "pageY")]
|
||||
public float PageY { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "pointerType")]
|
||||
public string PointerType { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "force")]
|
||||
public double Force { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "isLeftButton", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool IsLeftButton { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "isRightButton", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool IsRightButton { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "isMiddleButton", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool IsMiddleButton { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "isBarrelButtonPressed", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool IsBarrelButtonPressed { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "isHorizontalScrollWheel", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool IsHorizontalMouseWheel { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "isEraser", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool IsEraser { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче