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:
Eric Rozell 2016-10-13 12:31:59 -04:00 коммит произвёл GitHub
Родитель 393334bd71
Коммит b33642b885
3 изменённых файлов: 75 добавлений и 11 удалений

Просмотреть файл

@ -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; }
}
}
}