1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // Moz headers (alphabetical)
7 #include "MetroInput.h"
8 #include "MetroUtils.h" // Logging, POINT_CEIL_*, ActivateGenericInstance, etc
9 #include "MetroWidget.h" // MetroInput::mWidget
10 #include "mozilla/dom/Touch.h" // Touch
11 #include "nsTArray.h" // Touch lists
12 #include "nsIDOMSimpleGestureEvent.h" // Constants for gesture events
13 #include "InputData.h"
14 #include "UIABridgePrivate.h"
16 // System headers (alphabetical)
17 #include <windows.ui.core.h> // ABI::Window::UI::Core namespace
18 #include <windows.ui.input.h> // ABI::Window::UI::Input namespace
23 using namespace ABI::Windows
; // UI, System, Foundation namespaces
24 using namespace Microsoft
; // WRL namespace (ComPtr, possibly others)
25 using namespace mozilla
;
26 using namespace mozilla::widget::winrt
;
27 using namespace mozilla::dom
;
29 // File-scoped statics (unnamed namespace)
31 // XXX: Set these min values appropriately
32 const double SWIPE_MIN_DISTANCE
= 5.0;
33 const double SWIPE_MIN_VELOCITY
= 5.0;
35 // Convenience typedefs for event handler types
36 typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CEdgeGesture_Windows__CUI__CInput__CEdgeGestureEventArgs_t EdgeGestureHandler
;
37 typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreDispatcher_Windows__CUI__CCore__CAcceleratorKeyEventArgs_t AcceleratorKeyActivatedHandler
;
38 typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs_t PointerEventHandler
;
39 typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CTappedEventArgs_t TappedEventHandler
;
40 typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CRightTappedEventArgs_t RightTappedEventHandler
;
41 typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CManipulationStartedEventArgs_t ManipulationStartedEventHandler
;
42 typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CManipulationUpdatedEventArgs_t ManipulationUpdatedEventHandler
;
43 typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CManipulationCompletedEventArgs_t ManipulationCompletedEventHandler
;
45 // Other convenience typedefs
46 typedef ABI::Windows::UI::Core::ICoreAcceleratorKeys ICoreAcceleratorKeys
;
49 * Creates and returns a new {@link Touch} from the given
50 * ABI::Windows::UI::Input::IPointerPoint. Note that the caller is
51 * responsible for freeing the memory for the Touch returned from
54 * @param aPoint the ABI::Windows::UI::Input::IPointerPoint containing the
55 * metadata from which to create our new {@link Touch}
56 * @return a new {@link Touch} representing the touch point. The caller
57 * is responsible for freeing the memory for this touch point.
60 CreateDOMTouch(UI::Input::IPointerPoint
* aPoint
) {
61 WRL::ComPtr
<UI::Input::IPointerPointProperties
> props
;
62 Foundation::Point position
;
64 Foundation::Rect contactRect
;
67 aPoint
->get_Properties(props
.GetAddressOf());
68 aPoint
->get_Position(&position
);
69 aPoint
->get_PointerId(&pointerId
);
70 props
->get_ContactRect(&contactRect
);
71 props
->get_Pressure(&pressure
);
73 nsIntPoint touchPoint
= MetroUtils::LogToPhys(position
);
74 nsIntPoint touchRadius
;
75 touchRadius
.x
= MetroUtils::LogToPhys(contactRect
.Width
) / 2;
76 touchRadius
.y
= MetroUtils::LogToPhys(contactRect
.Height
) / 2;
77 return new Touch(pointerId
,
79 // Rotation radius and angle.
80 // W3C touch events v1 do not use these.
81 // The draft for W3C touch events v2 explains that
82 // radius and angle should describe the ellipse that
83 // most closely circumscribes the touching area. Since
84 // Windows gives us a bounding rectangle rather than an
85 // ellipse, we provide the ellipse that is most closely
86 // circumscribed by the bounding rectangle that Windows
91 // W3C touch events v1 do not use this.
92 // The current draft for W3C touch events v2 says that
93 // this should be a value between 0.0 and 1.0, which is
94 // consistent with what Windows provides us here.
95 // XXX: Windows defaults to 0.5, but the current W3C
96 // draft says that the value should be 0.0 if no value
102 * Test if a touchpoint position has moved. See Touch.Equals for
105 * @param aTouch previous touch point
106 * @param aPoint new winrt touch point
107 * @return true if the point has moved
110 HasPointMoved(Touch
* aTouch
, UI::Input::IPointerPoint
* aPoint
) {
111 WRL::ComPtr
<UI::Input::IPointerPointProperties
> props
;
112 Foundation::Point position
;
113 Foundation::Rect contactRect
;
116 aPoint
->get_Properties(props
.GetAddressOf());
117 aPoint
->get_Position(&position
);
118 props
->get_ContactRect(&contactRect
);
119 props
->get_Pressure(&pressure
);
120 nsIntPoint touchPoint
= MetroUtils::LogToPhys(position
);
121 nsIntPoint touchRadius
;
122 touchRadius
.x
= MetroUtils::LogToPhys(contactRect
.Width
) / 2;
123 touchRadius
.y
= MetroUtils::LogToPhys(contactRect
.Height
) / 2;
126 return touchPoint
!= aTouch
->mRefPoint
||
127 pressure
!= aTouch
->Force() ||
128 /* mRotationAngle == aTouch->RotationAngle() || */
129 touchRadius
.x
!= aTouch
->RadiusX() ||
130 touchRadius
.y
!= aTouch
->RadiusY();
134 * Converts from the Devices::Input::PointerDeviceType enumeration
135 * to a nsIDOMMouseEvent::MOZ_SOURCE_* value.
137 * @param aDeviceType the value to convert
138 * @param aMozInputSource the converted value
141 MozInputSourceFromDeviceType(
142 Devices::Input::PointerDeviceType
const& aDeviceType
,
143 unsigned short& aMozInputSource
) {
144 if (Devices::Input::PointerDeviceType::PointerDeviceType_Mouse
146 aMozInputSource
= nsIDOMMouseEvent::MOZ_SOURCE_MOUSE
;
147 } else if (Devices::Input::PointerDeviceType::PointerDeviceType_Touch
149 aMozInputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
150 } else if (Devices::Input::PointerDeviceType::PointerDeviceType_Pen
152 aMozInputSource
= nsIDOMMouseEvent::MOZ_SOURCE_PEN
;
157 * This function is for use with mTouches.Enumerate. It will
158 * append each element it encounters to the {@link nsTArray}
159 * of {@link mozilla::dom::Touch}es passed in through the third (void*)
162 * NOTE: This function will set the `mChanged` member of each
163 * element it encounters to `false`, since this function is only
164 * used to populate a touchlist that is about to be dispatched
165 * in a gecko touch event.
167 * @param aKey the key of the current element being enumerated
168 * @param aData the value of the current element being enumerated
169 * @param aTouchList the {@link nsTArray} to append to
172 AppendToTouchList(const unsigned int& aKey
,
173 nsRefPtr
<Touch
>& aData
,
176 nsTArray
<nsRefPtr
<Touch
> > *touches
=
177 static_cast<nsTArray
<nsRefPtr
<Touch
> > *>(aTouchList
);
178 touches
->AppendElement(aData
);
179 aData
->mChanged
= false;
180 return PL_DHASH_NEXT
;
188 MetroInput::MetroInput(MetroWidget
* aWidget
,
189 UI::Core::ICoreWindow
* aWindow
)
194 NS_ASSERTION(aWidget
, "Attempted to create MetroInput for null widget!");
195 NS_ASSERTION(aWindow
, "Attempted to create MetroInput for null window!");
197 mTokenPointerPressed
.value
= 0;
198 mTokenPointerReleased
.value
= 0;
199 mTokenPointerMoved
.value
= 0;
200 mTokenPointerEntered
.value
= 0;
201 mTokenPointerExited
.value
= 0;
202 mTokenEdgeStarted
.value
= 0;
203 mTokenEdgeCanceled
.value
= 0;
204 mTokenEdgeCompleted
.value
= 0;
205 mTokenManipulationStarted
.value
= 0;
206 mTokenManipulationUpdated
.value
= 0;
207 mTokenManipulationCompleted
.value
= 0;
208 mTokenTapped
.value
= 0;
209 mTokenRightTapped
.value
= 0;
211 // Create our Gesture Recognizer
212 ActivateGenericInstance(RuntimeClass_Windows_UI_Input_GestureRecognizer
,
214 NS_ASSERTION(mGestureRecognizer
, "Failed to create GestureRecognizer!");
216 RegisterInputEvents();
219 MetroInput::~MetroInput()
222 UnregisterInputEvents();
226 * When the user swipes her/his finger in from the top of the screen,
227 * we receive this event.
229 * @param sender the CoreDispatcher that fired this event
230 * @param aArgs the event-specific args we use when processing this event
234 MetroInput::OnEdgeGestureStarted(UI::Input::IEdgeGesture
* sender
,
235 UI::Input::IEdgeGestureEventArgs
* aArgs
)
240 nsSimpleGestureEvent
geckoEvent(true,
241 NS_SIMPLE_GESTURE_EDGE_STARTED
,
245 mModifierKeyState
.Update();
246 mModifierKeyState
.InitInputEvent(geckoEvent
);
247 geckoEvent
.time
= ::GetMessageTime();
249 geckoEvent
.inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
252 DispatchEventIgnoreStatus(&geckoEvent
);
257 * This event can be received if the user swipes her/his finger back to
258 * the top of the screen, or continues moving her/his finger such that
259 * the movement is interpreted as a "grab this window" gesture
261 * @param sender the CoreDispatcher that fired this event
262 * @param aArgs the event-specific args we use when processing this event
266 MetroInput::OnEdgeGestureCanceled(UI::Input::IEdgeGesture
* sender
,
267 UI::Input::IEdgeGestureEventArgs
* aArgs
)
272 nsSimpleGestureEvent
geckoEvent(true,
273 NS_SIMPLE_GESTURE_EDGE_CANCELED
,
277 mModifierKeyState
.Update();
278 mModifierKeyState
.InitInputEvent(geckoEvent
);
279 geckoEvent
.time
= ::GetMessageTime();
281 geckoEvent
.inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
284 DispatchEventIgnoreStatus(&geckoEvent
);
289 * This event is received if the user presses ctrl+Z or lifts her/his
290 * finger after causing an EdgeGestureStarting event to fire.
292 * @param sender the CoreDispatcher that fired this event
293 * @param aArgs the event-specific args we use when processing this event
297 MetroInput::OnEdgeGestureCompleted(UI::Input::IEdgeGesture
* sender
,
298 UI::Input::IEdgeGestureEventArgs
* aArgs
)
303 nsSimpleGestureEvent
geckoEvent(true,
304 NS_SIMPLE_GESTURE_EDGE_COMPLETED
,
308 mModifierKeyState
.Update();
309 mModifierKeyState
.InitInputEvent(geckoEvent
);
310 geckoEvent
.time
= ::GetMessageTime();
312 UI::Input::EdgeGestureKind value
;
313 aArgs
->get_Kind(&value
);
315 if (value
== UI::Input::EdgeGestureKind::EdgeGestureKind_Keyboard
) {
316 geckoEvent
.inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD
;
318 geckoEvent
.inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
322 DispatchEventIgnoreStatus(&geckoEvent
);
327 * This helper function is used by our processing of PointerPressed,
328 * PointerReleased, and PointerMoved events.
329 * It dispatches a gecko event in response to the input received. This
330 * function should only be called for non-touch (i.e. pen or mouse) input
333 * @param aPoint the PointerPoint for the input event
336 MetroInput::OnPointerNonTouch(UI::Input::IPointerPoint
* aPoint
) {
337 WRL::ComPtr
<UI::Input::IPointerPointProperties
> props
;
338 UI::Input::PointerUpdateKind pointerUpdateKind
;
340 aPoint
->get_Properties(props
.GetAddressOf());
341 props
->get_PointerUpdateKind(&pointerUpdateKind
);
343 nsMouseEvent
* event
=
344 new nsMouseEvent(true,
348 nsMouseEvent::eNormal
);
350 switch (pointerUpdateKind
) {
351 case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonPressed
:
352 // We don't bother setting mouseEvent.button because it is already
353 // set to nsMouseEvent::buttonType::eLeftButton whose value is 0.
354 event
->message
= NS_MOUSE_BUTTON_DOWN
;
356 case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonPressed
:
357 event
->button
= nsMouseEvent::buttonType::eMiddleButton
;
358 event
->message
= NS_MOUSE_BUTTON_DOWN
;
360 case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonPressed
:
361 event
->button
= nsMouseEvent::buttonType::eRightButton
;
362 event
->message
= NS_MOUSE_BUTTON_DOWN
;
364 case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonReleased
:
365 // We don't bother setting mouseEvent.button because it is already
366 // set to nsMouseEvent::buttonType::eLeftButton whose value is 0.
367 event
->message
= NS_MOUSE_BUTTON_UP
;
369 case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonReleased
:
370 event
->button
= nsMouseEvent::buttonType::eMiddleButton
;
371 event
->message
= NS_MOUSE_BUTTON_UP
;
373 case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonReleased
:
374 event
->button
= nsMouseEvent::buttonType::eRightButton
;
375 event
->message
= NS_MOUSE_BUTTON_UP
;
378 InitGeckoMouseEventFromPointerPoint(event
, aPoint
);
379 DispatchAsyncEventIgnoreStatus(event
);
383 MetroInput::InitTouchEventTouchList(nsTouchEvent
* aEvent
)
386 mTouches
.Enumerate(&AppendToTouchList
,
387 static_cast<void*>(&aEvent
->touches
));
390 // This event is raised when the user pushes the left mouse button, presses a
391 // pen to the surface, or presses a touch screen.
393 MetroInput::OnPointerPressed(UI::Core::ICoreWindow
* aSender
,
394 UI::Core::IPointerEventArgs
* aArgs
)
400 WRL::ComPtr
<UI::Input::IPointerPoint
> currentPoint
;
401 WRL::ComPtr
<Devices::Input::IPointerDevice
> device
;
402 Devices::Input::PointerDeviceType deviceType
;
404 aArgs
->get_CurrentPoint(currentPoint
.GetAddressOf());
405 currentPoint
->get_PointerDevice(device
.GetAddressOf());
406 device
->get_PointerDeviceType(&deviceType
);
408 // For mouse and pen input, simply call our helper function
410 Devices::Input::PointerDeviceType::PointerDeviceType_Touch
) {
411 OnPointerNonTouch(currentPoint
.Get());
412 mGestureRecognizer
->ProcessDownEvent(currentPoint
.Get());
416 // This is touch input.
417 // Create the new touch point and add it to our event.
419 currentPoint
->get_PointerId(&pointerId
);
420 nsRefPtr
<Touch
> touch
= CreateDOMTouch(currentPoint
.Get());
421 touch
->mChanged
= true;
422 mTouches
.Put(pointerId
, touch
);
424 nsTouchEvent
* touchEvent
=
425 new nsTouchEvent(true, NS_TOUCH_START
, mWidget
.Get());
427 if (mTouches
.Count() == 1) {
428 // If this is the first touchstart of a touch session reset some
429 // tracking flags and dispatch the event with a custom callback
430 // so we can check preventDefault result.
431 mTouchStartDefaultPrevented
= false;
432 mTouchMoveDefaultPrevented
= false;
433 mIsFirstTouchMove
= true;
434 InitTouchEventTouchList(touchEvent
);
435 DispatchAsyncTouchEventWithCallback(touchEvent
, &MetroInput::OnPointerPressedCallback
);
437 InitTouchEventTouchList(touchEvent
);
438 DispatchAsyncTouchEventIgnoreStatus(touchEvent
);
441 if (!mTouchStartDefaultPrevented
) {
442 mGestureRecognizer
->ProcessDownEvent(currentPoint
.Get());
448 MetroInput::OnPointerPressedCallback()
450 nsEventStatus status
= DeliverNextQueuedTouchEvent();
451 mTouchStartDefaultPrevented
= (nsEventStatus_eConsumeNoDefault
== status
);
452 // If content cancelled the first touchstart don't generate any gesture based
453 // input - clear the recognizer state without sending any events.
454 if (mTouchStartDefaultPrevented
) {
455 mGestureRecognizer
->CompleteGesture();
459 // This event is raised when the user moves the mouse, moves a pen that is
460 // in contact with the surface, or moves a finger that is in contact with
463 MetroInput::OnPointerMoved(UI::Core::ICoreWindow
* aSender
,
464 UI::Core::IPointerEventArgs
* aArgs
)
470 WRL::ComPtr
<UI::Input::IPointerPoint
> currentPoint
;
471 WRL::ComPtr
<Devices::Input::IPointerDevice
> device
;
472 Devices::Input::PointerDeviceType deviceType
;
474 aArgs
->get_CurrentPoint(currentPoint
.GetAddressOf());
475 currentPoint
->get_PointerDevice(device
.GetAddressOf());
476 device
->get_PointerDeviceType(&deviceType
);
478 // For mouse and pen input, simply call our helper function
480 Devices::Input::PointerDeviceType::PointerDeviceType_Touch
) {
481 OnPointerNonTouch(currentPoint
.Get());
482 WRL::ComPtr
<Foundation::Collections::IVector
<UI::Input::PointerPoint
*>>
484 aArgs
->GetIntermediatePoints(pointerPoints
.GetAddressOf());
485 mGestureRecognizer
->ProcessMoveEvents(pointerPoints
.Get());
489 // This is touch input.
490 // Get the touch associated with this touch point.
492 currentPoint
->get_PointerId(&pointerId
);
493 nsRefPtr
<Touch
> touch
= mTouches
.Get(pointerId
);
495 // Some old drivers cause us to receive a PointerMoved event for a touchId
496 // after we've already received a PointerReleased event for that touchId.
497 // To work around those busted drivers, we simply ignore TouchMoved events
498 // for touchIds that we are not currently tracking. See bug 819223.
503 // If the point hasn't moved, filter it out per the spec. Pres shell does
504 // this as well, but we need to know when our first touchmove is going to
505 // get delivered so we can check the result.
506 if (!HasPointMoved(touch
, currentPoint
.Get())) {
510 // If we've accumulated a batch of pointer moves and we're now on a new batch
511 // at a new position send the previous batch. (perf opt)
512 if (!mIsFirstTouchMove
&& touch
->mChanged
) {
513 nsTouchEvent
* touchEvent
=
514 new nsTouchEvent(true, NS_TOUCH_MOVE
, mWidget
.Get());
515 InitTouchEventTouchList(touchEvent
);
516 DispatchAsyncTouchEventIgnoreStatus(touchEvent
);
519 touch
= CreateDOMTouch(currentPoint
.Get());
520 touch
->mChanged
= true;
521 // replacing old touch point in mTouches map
522 mTouches
.Put(pointerId
, touch
);
524 nsTouchEvent
* touchEvent
=
525 new nsTouchEvent(true, NS_TOUCH_MOVE
, mWidget
.Get());
527 // If this is the first touch move of our session, we should check the result.
528 // Note we may lose some touch move data here for the recognizer since we want
529 // to wait until we have the result of the first touchmove dispatch. For gesture
530 // based events this shouldn't break anything.
531 if (mIsFirstTouchMove
) {
532 InitTouchEventTouchList(touchEvent
);
533 DispatchAsyncTouchEventWithCallback(touchEvent
, &MetroInput::OnFirstPointerMoveCallback
);
534 mIsFirstTouchMove
= false;
536 // Only feed move input to the recognizer if the first touchstart and
537 // subsequent touchmove return results were not eConsumeNoDefault.
538 if (!mTouchStartDefaultPrevented
&& !mTouchMoveDefaultPrevented
) {
539 WRL::ComPtr
<Foundation::Collections::IVector
<UI::Input::PointerPoint
*>>
541 aArgs
->GetIntermediatePoints(pointerPoints
.GetAddressOf());
542 mGestureRecognizer
->ProcessMoveEvents(pointerPoints
.Get());
550 MetroInput::OnFirstPointerMoveCallback()
552 nsTouchEvent
* event
= static_cast<nsTouchEvent
*>(mInputEventQueue
.PopFront());
554 nsEventStatus status
;
555 mWidget
->DispatchEvent(event
, status
);
556 mTouchMoveDefaultPrevented
= (nsEventStatus_eConsumeNoDefault
== status
);
560 // This event is raised when the user lifts the left mouse button, lifts a
561 // pen from the surface, or lifts her/his finger from a touch screen.
563 MetroInput::OnPointerReleased(UI::Core::ICoreWindow
* aSender
,
564 UI::Core::IPointerEventArgs
* aArgs
)
570 WRL::ComPtr
<UI::Input::IPointerPoint
> currentPoint
;
571 WRL::ComPtr
<Devices::Input::IPointerDevice
> device
;
572 Devices::Input::PointerDeviceType deviceType
;
574 aArgs
->get_CurrentPoint(currentPoint
.GetAddressOf());
575 currentPoint
->get_PointerDevice(device
.GetAddressOf());
576 device
->get_PointerDeviceType(&deviceType
);
578 // For mouse and pen input, simply call our helper function
580 Devices::Input::PointerDeviceType::PointerDeviceType_Touch
) {
581 OnPointerNonTouch(currentPoint
.Get());
582 mGestureRecognizer
->ProcessUpEvent(currentPoint
.Get());
586 // This is touch input.
587 // Get the touch associated with this touch point.
589 currentPoint
->get_PointerId(&pointerId
);
590 nsRefPtr
<Touch
> touch
= mTouches
.Get(pointerId
);
592 // Purge any pending moves for this pointer
593 if (touch
->mChanged
) {
594 nsTouchEvent
* touchEvent
=
595 new nsTouchEvent(true, NS_TOUCH_MOVE
, mWidget
.Get());
596 InitTouchEventTouchList(touchEvent
);
597 DispatchAsyncTouchEventIgnoreStatus(touchEvent
);
600 // Remove this touch point from our map. Eventually all touch points are
601 // removed for this session since we receive released events for every
603 mTouches
.Remove(pointerId
);
605 // touchend events only have a single touch; the touch that has been removed
606 nsTouchEvent
* touchEvent
=
607 new nsTouchEvent(true, NS_TOUCH_END
, mWidget
.Get());
608 touchEvent
->touches
.AppendElement(CreateDOMTouch(currentPoint
.Get()));
609 DispatchAsyncTouchEventIgnoreStatus(touchEvent
);
611 // If content didn't cancel the first touchstart feed touchend data to the
613 if (!mTouchStartDefaultPrevented
) {
614 mGestureRecognizer
->ProcessUpEvent(currentPoint
.Get());
621 MetroInput::InitGeckoMouseEventFromPointerPoint(
622 nsMouseEvent
* aEvent
,
623 UI::Input::IPointerPoint
* aPointerPoint
) {
624 NS_ASSERTION(aPointerPoint
, "InitGeckoMouseEventFromPointerPoint "
625 "called with null PointerPoint!");
627 WRL::ComPtr
<UI::Input::IPointerPointProperties
> props
;
628 WRL::ComPtr
<Devices::Input::IPointerDevice
> device
;
629 Devices::Input::PointerDeviceType deviceType
;
630 Foundation::Point position
;
633 boolean canBeDoubleTap
;
635 aPointerPoint
->get_Position(&position
);
636 aPointerPoint
->get_Timestamp(×tamp
);
637 aPointerPoint
->get_PointerDevice(device
.GetAddressOf());
638 device
->get_PointerDeviceType(&deviceType
);
639 aPointerPoint
->get_Properties(props
.GetAddressOf());
640 props
->get_Pressure(&pressure
);
641 mGestureRecognizer
->CanBeDoubleTap(aPointerPoint
, &canBeDoubleTap
);
643 aEvent
->refPoint
= LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position
));
645 if (!canBeDoubleTap
) {
646 aEvent
->clickCount
= 1;
648 aEvent
->clickCount
= 2;
650 aEvent
->pressure
= pressure
;
652 MozInputSourceFromDeviceType(deviceType
, aEvent
->inputSource
);
655 // This event is raised when a precise pointer moves into the bounding box of
656 // our window. For touch input, this will be raised before the PointerPressed
659 MetroInput::OnPointerEntered(UI::Core::ICoreWindow
* aSender
,
660 UI::Core::IPointerEventArgs
* aArgs
)
666 WRL::ComPtr
<UI::Input::IPointerPoint
> currentPoint
;
667 WRL::ComPtr
<Devices::Input::IPointerDevice
> device
;
668 Devices::Input::PointerDeviceType deviceType
;
670 aArgs
->get_CurrentPoint(currentPoint
.GetAddressOf());
671 currentPoint
->get_PointerDevice(device
.GetAddressOf());
672 device
->get_PointerDeviceType(&deviceType
);
674 // We only dispatch mouseenter and mouseexit events for mouse and pen input.
676 Devices::Input::PointerDeviceType::PointerDeviceType_Touch
) {
677 nsMouseEvent
* event
= new nsMouseEvent(true,
681 nsMouseEvent::eNormal
);
682 InitGeckoMouseEventFromPointerPoint(event
, currentPoint
.Get());
683 DispatchAsyncEventIgnoreStatus(event
);
688 // This event is raised when a precise pointer leaves the bounding box of
689 // our window. For touch input, this will be raised before the
690 // PointerReleased event.
692 MetroInput::OnPointerExited(UI::Core::ICoreWindow
* aSender
,
693 UI::Core::IPointerEventArgs
* aArgs
)
699 WRL::ComPtr
<UI::Input::IPointerPoint
> currentPoint
;
700 WRL::ComPtr
<Devices::Input::IPointerDevice
> device
;
701 Devices::Input::PointerDeviceType deviceType
;
703 aArgs
->get_CurrentPoint(currentPoint
.GetAddressOf());
704 currentPoint
->get_PointerDevice(device
.GetAddressOf());
705 device
->get_PointerDeviceType(&deviceType
);
707 // We only dispatch mouseenter and mouseexit events for mouse and pen input.
709 Devices::Input::PointerDeviceType::PointerDeviceType_Touch
) {
710 nsMouseEvent
* event
= new nsMouseEvent(true,
714 nsMouseEvent::eNormal
);
715 InitGeckoMouseEventFromPointerPoint(event
, currentPoint
.Get());
716 DispatchAsyncEventIgnoreStatus(event
);
722 * This helper function is called by our processing of "manipulation events".
723 * Manipulation events are how Windows sends us information about swipes,
724 * magnification gestures, and rotation gestures.
726 * @param aDelta the gesture change since the last update
727 * @param aPosition the position at which the gesture is taking place
728 * @param aMagEventType the event type of the gecko magnification gesture to
730 * @param aRotEventType the event type of the gecko rotation gesture to send
733 MetroInput::ProcessManipulationDelta(
734 UI::Input::ManipulationDelta
const& aDelta
,
735 Foundation::Point
const& aPosition
,
736 uint32_t aMagEventType
,
737 uint32_t aRotEventType
) {
738 // If we ONLY have translation (no rotation, no expansion), then this
739 // gesture isn't a two-finger gesture. We ignore it here, since the only
740 // thing it could eventually be is a swipe, and we deal with swipes in
741 // OnManipulationCompleted.
742 if ((aDelta
.Translation
.X
!= 0.0f
743 || aDelta
.Translation
.Y
!= 0.0f
)
744 && (aDelta
.Rotation
== 0.0f
745 && aDelta
.Expansion
== 0.0f
)) {
749 // Send a gecko event indicating the magnification since the last update.
750 nsSimpleGestureEvent
* magEvent
=
751 new nsSimpleGestureEvent(true, aMagEventType
, mWidget
.Get(), 0, 0.0);
753 magEvent
->delta
= aDelta
.Expansion
;
754 magEvent
->inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
755 magEvent
->refPoint
= LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition
));
756 DispatchAsyncEventIgnoreStatus(magEvent
);
758 // Send a gecko event indicating the rotation since the last update.
759 nsSimpleGestureEvent
* rotEvent
=
760 new nsSimpleGestureEvent(true, aRotEventType
, mWidget
.Get(), 0, 0.0);
762 rotEvent
->delta
= aDelta
.Rotation
;
763 rotEvent
->inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
764 rotEvent
->refPoint
= LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition
));
765 if (rotEvent
->delta
>= 0) {
766 rotEvent
->direction
= nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE
;
768 rotEvent
->direction
= nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE
;
770 DispatchAsyncEventIgnoreStatus(rotEvent
);
773 // This event is raised when a gesture is detected to have started. The
774 // data that is in "aArgs->Cumulative" represents the initial update, so
775 // it is equivalent to what we will receive later during ManipulationUpdated
778 MetroInput::OnManipulationStarted(
779 UI::Input::IGestureRecognizer
* aSender
,
780 UI::Input::IManipulationStartedEventArgs
* aArgs
)
785 UI::Input::ManipulationDelta delta
;
786 Foundation::Point position
;
788 aArgs
->get_Cumulative(&delta
);
789 aArgs
->get_Position(&position
);
791 ProcessManipulationDelta(delta
,
793 NS_SIMPLE_GESTURE_MAGNIFY_START
,
794 NS_SIMPLE_GESTURE_ROTATE_START
);
798 // This event is raised to inform us of changes in the gesture
799 // that is occurring. We simply pass "aArgs->Delta" (which gives us the
800 // changes since the last update or start event), and "aArgs->Position"
801 // to our helper function.
803 MetroInput::OnManipulationUpdated(
804 UI::Input::IGestureRecognizer
* aSender
,
805 UI::Input::IManipulationUpdatedEventArgs
* aArgs
)
810 UI::Input::ManipulationDelta delta
;
811 Foundation::Point position
;
813 aArgs
->get_Delta(&delta
);
814 aArgs
->get_Position(&position
);
816 ProcessManipulationDelta(delta
,
818 NS_SIMPLE_GESTURE_MAGNIFY_UPDATE
,
819 NS_SIMPLE_GESTURE_ROTATE_UPDATE
);
823 // Gecko expects a "finished" event to be sent that has the cumulative
824 // changes since the gesture began. The idea is that consumers could hook
825 // only this last event and still effectively support magnification and
826 // rotation. We accomplish sending this "finished" event by calling our
827 // helper function with a cumulative "delta" value.
829 // After sending the "finished" event, this function detects and sends
832 MetroInput::OnManipulationCompleted(
833 UI::Input::IGestureRecognizer
* aSender
,
834 UI::Input::IManipulationCompletedEventArgs
* aArgs
)
840 UI::Input::ManipulationDelta delta
;
841 Foundation::Point position
;
842 Devices::Input::PointerDeviceType deviceType
;
844 aArgs
->get_Position(&position
);
845 aArgs
->get_Cumulative(&delta
);
846 aArgs
->get_PointerDeviceType(&deviceType
);
848 // Send the "finished" events. Note that we are setting
849 // delta to the cumulative ManipulationDelta.
850 ProcessManipulationDelta(delta
,
852 NS_SIMPLE_GESTURE_MAGNIFY
,
853 NS_SIMPLE_GESTURE_ROTATE
);
855 // If any rotation or expansion has occurred, we know we're not dealing
856 // with a swipe gesture, so let's bail early. Also, the GestureRecognizer
857 // will send us Manipulation events even for mouse input under certain
858 // conditions. I was able to initiate swipe events consistently by
859 // clicking as I threw the mouse from one side of the screen to the other.
860 // Thus the check for mouse input here.
861 if (delta
.Rotation
!= 0.0f
862 || delta
.Expansion
!= 0.0f
864 Devices::Input::PointerDeviceType::PointerDeviceType_Mouse
) {
868 // No rotation or expansion occurred, so it is possible that we have a
869 // swipe gesture. We must check that the distance the user's finger
870 // traveled and the velocity with which it traveled exceed our thresholds
871 // for classifying the movement as a swipe.
872 UI::Input::ManipulationVelocities velocities
;
873 aArgs
->get_Velocities(&velocities
);
875 bool isHorizontalSwipe
=
876 abs(velocities
.Linear
.X
) >= SWIPE_MIN_VELOCITY
877 && abs(delta
.Translation
.X
) >= SWIPE_MIN_DISTANCE
;
878 bool isVerticalSwipe
=
879 abs(velocities
.Linear
.Y
) >= SWIPE_MIN_VELOCITY
880 && abs(delta
.Translation
.Y
) >= SWIPE_MIN_DISTANCE
;
882 // If our thresholds were exceeded for both a vertical and a horizontal
883 // swipe, it means the user is flinging her/his finger around and we
884 // should just ignore the input.
885 if (isHorizontalSwipe
&& isVerticalSwipe
) {
889 if (isHorizontalSwipe
) {
890 nsSimpleGestureEvent
* swipeEvent
=
891 new nsSimpleGestureEvent(true, NS_SIMPLE_GESTURE_SWIPE
,
892 mWidget
.Get(), 0, 0.0);
893 swipeEvent
->direction
= delta
.Translation
.X
> 0
894 ? nsIDOMSimpleGestureEvent::DIRECTION_RIGHT
895 : nsIDOMSimpleGestureEvent::DIRECTION_LEFT
;
896 swipeEvent
->delta
= delta
.Translation
.X
;
897 swipeEvent
->inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
898 swipeEvent
->refPoint
= LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position
));
899 DispatchAsyncEventIgnoreStatus(swipeEvent
);
902 if (isVerticalSwipe
) {
903 nsSimpleGestureEvent
* swipeEvent
=
904 new nsSimpleGestureEvent(true, NS_SIMPLE_GESTURE_SWIPE
,
905 mWidget
.Get(), 0, 0.0);
906 swipeEvent
->direction
= delta
.Translation
.Y
> 0
907 ? nsIDOMSimpleGestureEvent::DIRECTION_DOWN
908 : nsIDOMSimpleGestureEvent::DIRECTION_UP
;
909 swipeEvent
->delta
= delta
.Translation
.Y
;
910 swipeEvent
->inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
911 swipeEvent
->refPoint
= LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position
));
912 DispatchAsyncEventIgnoreStatus(swipeEvent
);
918 // This event is raised when a sequence of pointer events has been
919 // interpreted by the GestureRecognizer as a tap (this could be a mouse
920 // click, a pen tap, or a tap on a touch surface).
922 MetroInput::OnTapped(UI::Input::IGestureRecognizer
* aSender
,
923 UI::Input::ITappedEventArgs
* aArgs
)
929 Devices::Input::PointerDeviceType deviceType
;
930 aArgs
->get_PointerDeviceType(&deviceType
);
932 // For mouse and pen input, we send mousedown/mouseup/mousemove
933 // events as soon as we detect the input event. For touch input, a set of
934 // mousedown/mouseup events will be sent only once a tap has been detected.
935 if (deviceType
!= Devices::Input::PointerDeviceType::PointerDeviceType_Touch
) {
939 Foundation::Point position
;
940 aArgs
->get_Position(&position
);
942 LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position
)));
946 // This event is raised when a sequence of pointer events has been
947 // interpreted by the GestureRecognizer as a right tap.
948 // This could be a mouse right-click, a right-click on a pen, or
949 // a tap-and-hold on a touch surface.
951 MetroInput::OnRightTapped(UI::Input::IGestureRecognizer
* aSender
,
952 UI::Input::IRightTappedEventArgs
* aArgs
)
958 Devices::Input::PointerDeviceType deviceType
;
959 aArgs
->get_PointerDeviceType(&deviceType
);
961 Foundation::Point position
;
962 aArgs
->get_Position(&position
);
964 LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position
)));
970 MetroInput::HandleSingleTap(const LayoutDeviceIntPoint
& aPoint
)
977 nsMouseEvent
* mouseEvent
= new nsMouseEvent(true,
981 nsMouseEvent::eNormal
);
982 mouseEvent
->refPoint
= aPoint
;
983 mouseEvent
->clickCount
= 1;
984 mouseEvent
->inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
985 DispatchAsyncEventIgnoreStatus(mouseEvent
);
987 // Send the mousedown
988 mouseEvent
= new nsMouseEvent(true,
989 NS_MOUSE_BUTTON_DOWN
,
992 nsMouseEvent::eNormal
);
993 mouseEvent
->refPoint
= aPoint
;
994 mouseEvent
->clickCount
= 1;
995 mouseEvent
->inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
996 mouseEvent
->button
= nsMouseEvent::buttonType::eLeftButton
;
997 DispatchAsyncEventIgnoreStatus(mouseEvent
);
999 mouseEvent
= new nsMouseEvent(true,
1002 nsMouseEvent::eReal
,
1003 nsMouseEvent::eNormal
);
1004 mouseEvent
->refPoint
= aPoint
;
1005 mouseEvent
->clickCount
= 1;
1006 mouseEvent
->inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
1007 mouseEvent
->button
= nsMouseEvent::buttonType::eLeftButton
;
1008 DispatchAsyncEventIgnoreStatus(mouseEvent
);
1010 // Send one more mousemove to avoid getting a hover state.
1011 // In the Metro environment for any application, a tap does not imply a
1012 // mouse cursor move. In desktop environment for any application a tap
1013 // does imply a cursor move.
1015 if (GetCursorPos(&point
)) {
1016 ScreenToClient((HWND
)mWidget
->GetNativeData(NS_NATIVE_WINDOW
), &point
);
1017 mouseEvent
= new nsMouseEvent(true,
1020 nsMouseEvent::eReal
,
1021 nsMouseEvent::eNormal
);
1022 mouseEvent
->refPoint
= LayoutDeviceIntPoint(point
.x
, point
.y
);
1023 mouseEvent
->clickCount
= 1;
1024 mouseEvent
->inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
1025 DispatchAsyncEventIgnoreStatus(mouseEvent
);
1031 MetroInput::HandleLongTap(const LayoutDeviceIntPoint
& aPoint
)
1037 nsMouseEvent
* contextEvent
= new nsMouseEvent(true,
1040 nsMouseEvent::eReal
,
1041 nsMouseEvent::eNormal
);
1042 contextEvent
->refPoint
= aPoint
;
1043 contextEvent
->inputSource
= nsIDOMMouseEvent::MOZ_SOURCE_TOUCH
;
1044 DispatchAsyncEventIgnoreStatus(contextEvent
);
1048 * Implementation Details
1050 nsEventStatus
MetroInput::sThrowawayStatus
;
1053 MetroInput::DispatchAsyncEventIgnoreStatus(nsInputEvent
* aEvent
)
1055 aEvent
->time
= ::GetMessageTime();
1056 mModifierKeyState
.Update();
1057 mModifierKeyState
.InitInputEvent(*aEvent
);
1058 mInputEventQueue
.Push(aEvent
);
1059 nsCOMPtr
<nsIRunnable
> runnable
=
1060 NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedEventIgnoreStatus
);
1061 NS_DispatchToCurrentThread(runnable
);
1065 MetroInput::DeliverNextQueuedEventIgnoreStatus()
1067 nsGUIEvent
* event
= static_cast<nsGUIEvent
*>(mInputEventQueue
.PopFront());
1069 DispatchEventIgnoreStatus(event
);
1074 MetroInput::DeliverNextQueuedEvent()
1076 nsGUIEvent
* event
= static_cast<nsGUIEvent
*>(mInputEventQueue
.PopFront());
1078 nsEventStatus status
;
1079 mWidget
->DispatchEvent(event
, status
);
1085 MetroInput::DispatchAsyncTouchEventIgnoreStatus(nsTouchEvent
* aEvent
)
1087 aEvent
->time
= ::GetMessageTime();
1088 mModifierKeyState
.Update();
1089 mModifierKeyState
.InitInputEvent(*aEvent
);
1090 mInputEventQueue
.Push(aEvent
);
1091 nsCOMPtr
<nsIRunnable
> runnable
=
1092 NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedTouchEvent
);
1093 NS_DispatchToCurrentThread(runnable
);
1097 MetroInput::DeliverNextQueuedTouchEvent()
1099 nsTouchEvent
* event
= static_cast<nsTouchEvent
*>(mInputEventQueue
.PopFront());
1101 nsEventStatus status
;
1102 mWidget
->DispatchEvent(event
, status
);
1103 // Deliver to the apz if content has *not* cancelled touchstart or the first touchmove.
1104 if (!mTouchStartDefaultPrevented
&& !mTouchMoveDefaultPrevented
&& MetroWidget::sAPZC
) {
1105 MultiTouchInput
inputData(*event
);
1106 MetroWidget::sAPZC
->ReceiveInputEvent(inputData
);
1113 MetroInput::DispatchAsyncTouchEventWithCallback(nsTouchEvent
* aEvent
, void (MetroInput::*Callback
)())
1115 aEvent
->time
= ::GetMessageTime();
1116 mModifierKeyState
.Update();
1117 mModifierKeyState
.InitInputEvent(*aEvent
);
1118 mInputEventQueue
.Push(aEvent
);
1119 nsCOMPtr
<nsIRunnable
> runnable
=
1120 NS_NewRunnableMethod(this, Callback
);
1121 NS_DispatchToCurrentThread(runnable
);
1125 MetroInput::DispatchEventIgnoreStatus(nsGUIEvent
*aEvent
) {
1126 mWidget
->DispatchEvent(aEvent
, sThrowawayStatus
);
1130 MetroInput::UnregisterInputEvents() {
1131 // Unregister ourselves for the edge swipe event
1132 WRL::ComPtr
<UI::Input::IEdgeGestureStatics
> edgeStatics
;
1133 if (SUCCEEDED(Foundation::GetActivationFactory(
1134 WRL::Wrappers::HStringReference(
1135 RuntimeClass_Windows_UI_Input_EdgeGesture
).Get(),
1136 edgeStatics
.GetAddressOf()))) {
1137 WRL::ComPtr
<UI::Input::IEdgeGesture
> edge
;
1138 if (SUCCEEDED(edgeStatics
->GetForCurrentView(edge
.GetAddressOf()))) {
1139 edge
->remove_Starting(mTokenEdgeStarted
);
1140 edge
->remove_Canceled(mTokenEdgeCanceled
);
1141 edge
->remove_Completed(mTokenEdgeCompleted
);
1144 // Unregister ourselves from the window events. This is extremely important;
1145 // once this object is destroyed we don't want Windows to try to send events
1147 mWindow
->remove_PointerPressed(mTokenPointerPressed
);
1148 mWindow
->remove_PointerReleased(mTokenPointerReleased
);
1149 mWindow
->remove_PointerMoved(mTokenPointerMoved
);
1150 mWindow
->remove_PointerEntered(mTokenPointerEntered
);
1151 mWindow
->remove_PointerExited(mTokenPointerExited
);
1153 // Unregistering from the gesture recognizer events probably isn't as
1154 // necessary since we're about to destroy the gesture recognizer, but
1156 mGestureRecognizer
->remove_ManipulationStarted(mTokenManipulationStarted
);
1157 mGestureRecognizer
->remove_ManipulationUpdated(mTokenManipulationUpdated
);
1158 mGestureRecognizer
->remove_ManipulationCompleted(
1159 mTokenManipulationCompleted
);
1160 mGestureRecognizer
->remove_Tapped(mTokenTapped
);
1161 mGestureRecognizer
->remove_RightTapped(mTokenRightTapped
);
1165 MetroInput::RegisterInputEvents()
1167 NS_ASSERTION(mWindow
, "Must have a window to register for input events!");
1168 NS_ASSERTION(mGestureRecognizer
,
1169 "Must have a GestureRecognizer for input events!");
1170 // Register for edge swipe
1171 WRL::ComPtr
<UI::Input::IEdgeGestureStatics
> edgeStatics
;
1172 Foundation::GetActivationFactory(
1173 WRL::Wrappers::HStringReference(
1174 RuntimeClass_Windows_UI_Input_EdgeGesture
)
1176 edgeStatics
.GetAddressOf());
1177 WRL::ComPtr
<UI::Input::IEdgeGesture
> edge
;
1178 edgeStatics
->GetForCurrentView(edge
.GetAddressOf());
1181 WRL::Callback
<EdgeGestureHandler
>(
1183 &MetroInput::OnEdgeGestureStarted
).Get(),
1184 &mTokenEdgeStarted
);
1187 WRL::Callback
<EdgeGestureHandler
>(
1189 &MetroInput::OnEdgeGestureCanceled
).Get(),
1190 &mTokenEdgeCanceled
);
1192 edge
->add_Completed(
1193 WRL::Callback
<EdgeGestureHandler
>(
1195 &MetroInput::OnEdgeGestureCompleted
).Get(),
1196 &mTokenEdgeCompleted
);
1198 // Set up our Gesture Recognizer to raise events for the gestures we
1200 mGestureRecognizer
->put_GestureSettings(
1201 UI::Input::GestureSettings::GestureSettings_Tap
1202 | UI::Input::GestureSettings::GestureSettings_DoubleTap
1203 | UI::Input::GestureSettings::GestureSettings_RightTap
1204 | UI::Input::GestureSettings::GestureSettings_Hold
1205 | UI::Input::GestureSettings::GestureSettings_ManipulationTranslateX
1206 | UI::Input::GestureSettings::GestureSettings_ManipulationTranslateY
1207 | UI::Input::GestureSettings::GestureSettings_ManipulationScale
1208 | UI::Input::GestureSettings::GestureSettings_ManipulationRotate
);
1210 // Register for the pointer events on our Window
1211 mWindow
->add_PointerPressed(
1212 WRL::Callback
<PointerEventHandler
>(
1214 &MetroInput::OnPointerPressed
).Get(),
1215 &mTokenPointerPressed
);
1217 mWindow
->add_PointerReleased(
1218 WRL::Callback
<PointerEventHandler
>(
1220 &MetroInput::OnPointerReleased
).Get(),
1221 &mTokenPointerReleased
);
1223 mWindow
->add_PointerMoved(
1224 WRL::Callback
<PointerEventHandler
>(
1226 &MetroInput::OnPointerMoved
).Get(),
1227 &mTokenPointerMoved
);
1229 mWindow
->add_PointerEntered(
1230 WRL::Callback
<PointerEventHandler
>(
1232 &MetroInput::OnPointerEntered
).Get(),
1233 &mTokenPointerEntered
);
1235 mWindow
->add_PointerExited(
1236 WRL::Callback
<PointerEventHandler
>(
1238 &MetroInput::OnPointerExited
).Get(),
1239 &mTokenPointerExited
);
1241 // Register for the events raised by our Gesture Recognizer
1242 mGestureRecognizer
->add_Tapped(
1243 WRL::Callback
<TappedEventHandler
>(
1245 &MetroInput::OnTapped
).Get(),
1248 mGestureRecognizer
->add_RightTapped(
1249 WRL::Callback
<RightTappedEventHandler
>(
1251 &MetroInput::OnRightTapped
).Get(),
1252 &mTokenRightTapped
);
1254 mGestureRecognizer
->add_ManipulationStarted(
1255 WRL::Callback
<ManipulationStartedEventHandler
>(
1257 &MetroInput::OnManipulationStarted
).Get(),
1258 &mTokenManipulationStarted
);
1260 mGestureRecognizer
->add_ManipulationUpdated(
1261 WRL::Callback
<ManipulationUpdatedEventHandler
>(
1263 &MetroInput::OnManipulationUpdated
).Get(),
1264 &mTokenManipulationUpdated
);
1266 mGestureRecognizer
->add_ManipulationCompleted(
1267 WRL::Callback
<ManipulationCompletedEventHandler
>(
1269 &MetroInput::OnManipulationCompleted
).Get(),
1270 &mTokenManipulationCompleted
);