Skip to content

Commit b33642b

Browse files
authored
feat(TouchHandler): Add pointerType info to touch event data (microsoft#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 microsoft#772 Fixes microsoft#774
1 parent 393334b commit b33642b

File tree

3 files changed

+75
-11
lines changed

3 files changed

+75
-11
lines changed

ReactWindows/ReactNative/ReactNative.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
<Compile Include="ReactPage.cs" />
164164
<Compile Include="ReactRootView.cs" />
165165
<Compile Include="Touch\IOnInterceptTouchEventListener.cs" />
166+
<Compile Include="Touch\PointerDeviceTypeExtensions.cs" />
166167
<Compile Include="Touch\TouchHandler.cs" />
167168
<Compile Include="Tracing\LoggingActivityBuilder.cs" />
168169
<Compile Include="Tracing\LoggingActivityBuilderExtensions.generated.cs">
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Windows.Devices.Input;
2+
3+
namespace ReactNative.Touch
4+
{
5+
static class PointerDeviceTypeExtensions
6+
{
7+
public static string GetPointerDeviceTypeName(this PointerDeviceType pointerDeviceType)
8+
{
9+
switch (pointerDeviceType)
10+
{
11+
case PointerDeviceType.Touch:
12+
return "touch";
13+
case PointerDeviceType.Pen:
14+
return "pen";
15+
case PointerDeviceType.Mouse:
16+
return "mouse";
17+
default:
18+
return "unknown";
19+
}
20+
}
21+
}
22+
}

ReactWindows/ReactNative/Touch/TouchHandler.cs

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using ReactNative.UIManager.Events;
55
using System;
66
using System.Collections.Generic;
7+
using Windows.Foundation;
8+
using Windows.UI.Input;
79
using Windows.UI.Xaml;
810
using Windows.UI.Xaml.Input;
911
using Windows.UI.Xaml.Media;
@@ -46,17 +48,25 @@ private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
4648
throw new InvalidOperationException("A pointer with this ID already exists.");
4749
}
4850

49-
var reactView = GetReactViewTarget(e);
51+
var originalSource = e.OriginalSource as DependencyObject;
52+
var rootPoint = e.GetCurrentPoint(_view);
53+
var reactView = GetReactViewTarget(originalSource, rootPoint.Position);
5054
if (reactView != null && _view.CapturePointer(e.Pointer))
5155
{
52-
var reactTag = reactView.GetReactCompoundView().GetReactTagAtPoint(reactView,
53-
e.GetCurrentPoint(reactView).Position);
56+
var viewPoint = e.GetCurrentPoint(reactView);
57+
var reactTag = reactView.GetReactCompoundView().GetReactTagAtPoint(reactView, viewPoint.Position);
5458
var pointer = new ReactPointer();
5559
pointer.Target = reactTag;
5660
pointer.PointerId = e.Pointer.PointerId;
5761
pointer.Identifier = ++_pointerIDs;
62+
pointer.PointerType = e.Pointer.PointerDeviceType.GetPointerDeviceTypeName();
63+
pointer.IsLeftButton = viewPoint.Properties.IsLeftButtonPressed;
64+
pointer.IsRightButton = viewPoint.Properties.IsRightButtonPressed;
65+
pointer.IsMiddleButton = viewPoint.Properties.IsMiddleButtonPressed;
66+
pointer.IsHorizontalMouseWheel = viewPoint.Properties.IsHorizontalMouseWheel;
67+
pointer.IsEraser = viewPoint.Properties.IsEraser;
5868
pointer.ReactView = reactView;
59-
UpdatePointerForEvent(pointer, e);
69+
UpdatePointerForEvent(pointer, rootPoint, viewPoint);
6070

6171
var pointerIndex = _pointers.Count;
6272
_pointers.Add(pointer);
@@ -123,16 +133,15 @@ private int IndexOfPointerWithId(uint pointerId)
123133
return -1;
124134
}
125135

126-
private UIElement GetReactViewTarget(PointerRoutedEventArgs e)
136+
private UIElement GetReactViewTarget(DependencyObject originalSource, Point point)
127137
{
128138
// If the target is not a child of the root view, then this pointer
129139
// event does not belong to React.
130-
if (!RootViewHelper.IsReactSubview(e.OriginalSource as DependencyObject))
140+
if (!RootViewHelper.IsReactSubview(originalSource))
131141
{
132142
return null;
133143
}
134144

135-
var point = e.GetCurrentPoint(_view).Position;
136145
var sources = VisualTreeHelper.FindElementsInHostCoordinates(point, _view);
137146

138147
// Get the first React view that does not have pointer events set
@@ -167,15 +176,23 @@ private UIElement GetReactViewTarget(PointerRoutedEventArgs e)
167176

168177
private void UpdatePointerForEvent(ReactPointer pointer, PointerRoutedEventArgs e)
169178
{
170-
var viewPoint = e.GetCurrentPoint(_view);
171-
var positionInRoot = viewPoint.Position;
172-
var positionInView = e.GetCurrentPoint(pointer.ReactView).Position;
179+
var rootPoint = e.GetCurrentPoint(_view);
180+
var viewPoint = e.GetCurrentPoint(pointer.ReactView);
181+
UpdatePointerForEvent(pointer, rootPoint, viewPoint);
182+
}
183+
184+
private void UpdatePointerForEvent(ReactPointer pointer, PointerPoint rootPoint, PointerPoint viewPoint)
185+
{
186+
var positionInRoot = rootPoint.Position;
187+
var positionInView = viewPoint.Position;
173188

174189
pointer.PageX = (float)positionInRoot.X;
175190
pointer.PageY = (float)positionInRoot.Y;
176191
pointer.LocationX = (float)positionInView.X;
177192
pointer.LocationY = (float)positionInView.Y;
178-
pointer.Timestamp = viewPoint.Timestamp / 1000; // Convert microseconds to milliseconds;
193+
pointer.Timestamp = rootPoint.Timestamp / 1000; // Convert microseconds to milliseconds;
194+
pointer.Force = rootPoint.Properties.Pressure;
195+
pointer.IsBarrelButtonPressed = rootPoint.Properties.IsBarrelButtonPressed;
179196
}
180197

181198
private void DispatchTouchEvent(TouchEventType touchEventType, List<ReactPointer> activePointers, int pointerIndex)
@@ -312,6 +329,30 @@ class ReactPointer
312329

313330
[JsonProperty(PropertyName = "pageY")]
314331
public float PageY { get; set; }
332+
333+
[JsonProperty(PropertyName = "pointerType")]
334+
public string PointerType { get; set; }
335+
336+
[JsonProperty(PropertyName = "force")]
337+
public double Force { get; set; }
338+
339+
[JsonProperty(PropertyName = "isLeftButton", DefaultValueHandling = DefaultValueHandling.Ignore)]
340+
public bool IsLeftButton { get; set; }
341+
342+
[JsonProperty(PropertyName = "isRightButton", DefaultValueHandling = DefaultValueHandling.Ignore)]
343+
public bool IsRightButton { get; set; }
344+
345+
[JsonProperty(PropertyName = "isMiddleButton", DefaultValueHandling = DefaultValueHandling.Ignore)]
346+
public bool IsMiddleButton { get; set; }
347+
348+
[JsonProperty(PropertyName = "isBarrelButtonPressed", DefaultValueHandling = DefaultValueHandling.Ignore)]
349+
public bool IsBarrelButtonPressed { get; set; }
350+
351+
[JsonProperty(PropertyName = "isHorizontalScrollWheel", DefaultValueHandling = DefaultValueHandling.Ignore)]
352+
public bool IsHorizontalMouseWheel { get; set; }
353+
354+
[JsonProperty(PropertyName = "isEraser", DefaultValueHandling = DefaultValueHandling.Ignore)]
355+
public bool IsEraser { get; set; }
315356
}
316357
}
317358
}

0 commit comments

Comments
 (0)