Bug 907098 - Don't send input events to apz if touchstart or the first touchmove...
[gecko.git] / widget / windows / winrt / MetroInput.cpp
blobfd359f3ebfebb1151f2faf7fafcde57a15d19183
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
20 //#define DEBUG_INPUT
22 // Using declarations
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)
30 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;
48 /**
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
52 * this function.
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.
59 Touch*
60 CreateDOMTouch(UI::Input::IPointerPoint* aPoint) {
61 WRL::ComPtr<UI::Input::IPointerPointProperties> props;
62 Foundation::Point position;
63 uint32_t pointerId;
64 Foundation::Rect contactRect;
65 float pressure;
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,
78 touchPoint,
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
87 // gave us.
88 touchRadius,
89 0.0f,
90 // Pressure
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
97 // known.
98 pressure);
102 * Test if a touchpoint position has moved. See Touch.Equals for
103 * criteria.
105 * @param aTouch previous touch point
106 * @param aPoint new winrt touch point
107 * @return true if the point has moved
109 bool
110 HasPointMoved(Touch* aTouch, UI::Input::IPointerPoint* aPoint) {
111 WRL::ComPtr<UI::Input::IPointerPointProperties> props;
112 Foundation::Point position;
113 Foundation::Rect contactRect;
114 float pressure;
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;
125 // from Touch.Equals
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
140 void
141 MozInputSourceFromDeviceType(
142 Devices::Input::PointerDeviceType const& aDeviceType,
143 unsigned short& aMozInputSource) {
144 if (Devices::Input::PointerDeviceType::PointerDeviceType_Mouse
145 == aDeviceType) {
146 aMozInputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
147 } else if (Devices::Input::PointerDeviceType::PointerDeviceType_Touch
148 == aDeviceType) {
149 aMozInputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
150 } else if (Devices::Input::PointerDeviceType::PointerDeviceType_Pen
151 == aDeviceType) {
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*)
160 * parameter.
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
171 PLDHashOperator
172 AppendToTouchList(const unsigned int& aKey,
173 nsRefPtr<Touch>& aData,
174 void *aTouchList)
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;
184 namespace mozilla {
185 namespace widget {
186 namespace winrt {
188 MetroInput::MetroInput(MetroWidget* aWidget,
189 UI::Core::ICoreWindow* aWindow)
190 : mWidget(aWidget),
191 mWindow(aWindow)
193 LogFunction();
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,
213 mGestureRecognizer);
214 NS_ASSERTION(mGestureRecognizer, "Failed to create GestureRecognizer!");
216 RegisterInputEvents();
219 MetroInput::~MetroInput()
221 LogFunction();
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
231 * @returns S_OK
233 HRESULT
234 MetroInput::OnEdgeGestureStarted(UI::Input::IEdgeGesture* sender,
235 UI::Input::IEdgeGestureEventArgs* aArgs)
237 #ifdef DEBUG_INPUT
238 LogFunction();
239 #endif
240 nsSimpleGestureEvent geckoEvent(true,
241 NS_SIMPLE_GESTURE_EDGE_STARTED,
242 mWidget.Get(),
244 0.0);
245 mModifierKeyState.Update();
246 mModifierKeyState.InitInputEvent(geckoEvent);
247 geckoEvent.time = ::GetMessageTime();
249 geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
251 // Safe
252 DispatchEventIgnoreStatus(&geckoEvent);
253 return S_OK;
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
263 * @returns S_OK
265 HRESULT
266 MetroInput::OnEdgeGestureCanceled(UI::Input::IEdgeGesture* sender,
267 UI::Input::IEdgeGestureEventArgs* aArgs)
269 #ifdef DEBUG_INPUT
270 LogFunction();
271 #endif
272 nsSimpleGestureEvent geckoEvent(true,
273 NS_SIMPLE_GESTURE_EDGE_CANCELED,
274 mWidget.Get(),
276 0.0);
277 mModifierKeyState.Update();
278 mModifierKeyState.InitInputEvent(geckoEvent);
279 geckoEvent.time = ::GetMessageTime();
281 geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
283 // Safe
284 DispatchEventIgnoreStatus(&geckoEvent);
285 return S_OK;
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
294 * @returns S_OK
296 HRESULT
297 MetroInput::OnEdgeGestureCompleted(UI::Input::IEdgeGesture* sender,
298 UI::Input::IEdgeGestureEventArgs* aArgs)
300 #ifdef DEBUG_INPUT
301 LogFunction();
302 #endif
303 nsSimpleGestureEvent geckoEvent(true,
304 NS_SIMPLE_GESTURE_EDGE_COMPLETED,
305 mWidget.Get(),
307 0.0);
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;
317 } else {
318 geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
321 // Safe
322 DispatchEventIgnoreStatus(&geckoEvent);
323 return S_OK;
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
331 * events.
333 * @param aPoint the PointerPoint for the input event
335 void
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,
345 NS_MOUSE_MOVE,
346 mWidget.Get(),
347 nsMouseEvent::eReal,
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;
355 break;
356 case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonPressed:
357 event->button = nsMouseEvent::buttonType::eMiddleButton;
358 event->message = NS_MOUSE_BUTTON_DOWN;
359 break;
360 case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonPressed:
361 event->button = nsMouseEvent::buttonType::eRightButton;
362 event->message = NS_MOUSE_BUTTON_DOWN;
363 break;
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;
368 break;
369 case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonReleased:
370 event->button = nsMouseEvent::buttonType::eMiddleButton;
371 event->message = NS_MOUSE_BUTTON_UP;
372 break;
373 case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonReleased:
374 event->button = nsMouseEvent::buttonType::eRightButton;
375 event->message = NS_MOUSE_BUTTON_UP;
376 break;
378 InitGeckoMouseEventFromPointerPoint(event, aPoint);
379 DispatchAsyncEventIgnoreStatus(event);
382 void
383 MetroInput::InitTouchEventTouchList(nsTouchEvent* aEvent)
385 MOZ_ASSERT(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.
392 HRESULT
393 MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender,
394 UI::Core::IPointerEventArgs* aArgs)
396 #ifdef DEBUG_INPUT
397 LogFunction();
398 #endif
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
409 if (deviceType !=
410 Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
411 OnPointerNonTouch(currentPoint.Get());
412 mGestureRecognizer->ProcessDownEvent(currentPoint.Get());
413 return S_OK;
416 // This is touch input.
417 // Create the new touch point and add it to our event.
418 uint32_t pointerId;
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);
436 } else {
437 InitTouchEventTouchList(touchEvent);
438 DispatchAsyncTouchEventIgnoreStatus(touchEvent);
441 if (!mTouchStartDefaultPrevented) {
442 mGestureRecognizer->ProcessDownEvent(currentPoint.Get());
444 return S_OK;
447 void
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
461 // a touch screen.
462 HRESULT
463 MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender,
464 UI::Core::IPointerEventArgs* aArgs)
466 #ifdef DEBUG_INPUT
467 LogFunction();
468 #endif
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
479 if (deviceType !=
480 Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
481 OnPointerNonTouch(currentPoint.Get());
482 WRL::ComPtr<Foundation::Collections::IVector<UI::Input::PointerPoint*>>
483 pointerPoints;
484 aArgs->GetIntermediatePoints(pointerPoints.GetAddressOf());
485 mGestureRecognizer->ProcessMoveEvents(pointerPoints.Get());
486 return S_OK;
489 // This is touch input.
490 // Get the touch associated with this touch point.
491 uint32_t pointerId;
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.
499 if (!touch) {
500 return S_OK;
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())) {
507 return S_OK;
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;
535 } else {
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*>>
540 pointerPoints;
541 aArgs->GetIntermediatePoints(pointerPoints.GetAddressOf());
542 mGestureRecognizer->ProcessMoveEvents(pointerPoints.Get());
546 return S_OK;
549 void
550 MetroInput::OnFirstPointerMoveCallback()
552 nsTouchEvent* event = static_cast<nsTouchEvent*>(mInputEventQueue.PopFront());
553 MOZ_ASSERT(event);
554 nsEventStatus status;
555 mWidget->DispatchEvent(event, status);
556 mTouchMoveDefaultPrevented = (nsEventStatus_eConsumeNoDefault == status);
557 delete event;
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.
562 HRESULT
563 MetroInput::OnPointerReleased(UI::Core::ICoreWindow* aSender,
564 UI::Core::IPointerEventArgs* aArgs)
566 #ifdef DEBUG_INPUT
567 LogFunction();
568 #endif
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
579 if (deviceType !=
580 Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
581 OnPointerNonTouch(currentPoint.Get());
582 mGestureRecognizer->ProcessUpEvent(currentPoint.Get());
583 return S_OK;
586 // This is touch input.
587 // Get the touch associated with this touch point.
588 uint32_t pointerId;
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
602 // point.
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
612 // recognizer.
613 if (!mTouchStartDefaultPrevented) {
614 mGestureRecognizer->ProcessUpEvent(currentPoint.Get());
617 return S_OK;
620 void
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;
631 uint64_t timestamp;
632 float pressure;
633 boolean canBeDoubleTap;
635 aPointerPoint->get_Position(&position);
636 aPointerPoint->get_Timestamp(&timestamp);
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;
647 } else {
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
657 // event.
658 HRESULT
659 MetroInput::OnPointerEntered(UI::Core::ICoreWindow* aSender,
660 UI::Core::IPointerEventArgs* aArgs)
662 #ifdef DEBUG_INPUT
663 LogFunction();
664 #endif
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.
675 if (deviceType !=
676 Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
677 nsMouseEvent* event = new nsMouseEvent(true,
678 NS_MOUSE_ENTER,
679 mWidget.Get(),
680 nsMouseEvent::eReal,
681 nsMouseEvent::eNormal);
682 InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
683 DispatchAsyncEventIgnoreStatus(event);
685 return S_OK;
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.
691 HRESULT
692 MetroInput::OnPointerExited(UI::Core::ICoreWindow* aSender,
693 UI::Core::IPointerEventArgs* aArgs)
695 #ifdef DEBUG_INPUT
696 LogFunction();
697 #endif
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.
708 if (deviceType !=
709 Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
710 nsMouseEvent* event = new nsMouseEvent(true,
711 NS_MOUSE_EXIT,
712 mWidget.Get(),
713 nsMouseEvent::eReal,
714 nsMouseEvent::eNormal);
715 InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
716 DispatchAsyncEventIgnoreStatus(event);
718 return S_OK;
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
729 * send
730 * @param aRotEventType the event type of the gecko rotation gesture to send
732 void
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)) {
746 return;
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;
767 } else {
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
776 // events.
777 HRESULT
778 MetroInput::OnManipulationStarted(
779 UI::Input::IGestureRecognizer* aSender,
780 UI::Input::IManipulationStartedEventArgs* aArgs)
782 #ifdef DEBUG_INPUT
783 LogFunction();
784 #endif
785 UI::Input::ManipulationDelta delta;
786 Foundation::Point position;
788 aArgs->get_Cumulative(&delta);
789 aArgs->get_Position(&position);
791 ProcessManipulationDelta(delta,
792 position,
793 NS_SIMPLE_GESTURE_MAGNIFY_START,
794 NS_SIMPLE_GESTURE_ROTATE_START);
795 return S_OK;
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.
802 HRESULT
803 MetroInput::OnManipulationUpdated(
804 UI::Input::IGestureRecognizer* aSender,
805 UI::Input::IManipulationUpdatedEventArgs* aArgs)
807 #ifdef DEBUG_INPUT
808 LogFunction();
809 #endif
810 UI::Input::ManipulationDelta delta;
811 Foundation::Point position;
813 aArgs->get_Delta(&delta);
814 aArgs->get_Position(&position);
816 ProcessManipulationDelta(delta,
817 position,
818 NS_SIMPLE_GESTURE_MAGNIFY_UPDATE,
819 NS_SIMPLE_GESTURE_ROTATE_UPDATE);
820 return S_OK;
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
830 // swipe gestures.
831 HRESULT
832 MetroInput::OnManipulationCompleted(
833 UI::Input::IGestureRecognizer* aSender,
834 UI::Input::IManipulationCompletedEventArgs* aArgs)
836 #ifdef DEBUG_INPUT
837 LogFunction();
838 #endif
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,
851 position,
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
863 || deviceType ==
864 Devices::Input::PointerDeviceType::PointerDeviceType_Mouse) {
865 return S_OK;
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) {
886 return S_OK;
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);
915 return S_OK;
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).
921 HRESULT
922 MetroInput::OnTapped(UI::Input::IGestureRecognizer* aSender,
923 UI::Input::ITappedEventArgs* aArgs)
925 #ifdef DEBUG_INPUT
926 LogFunction();
927 #endif
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) {
936 return S_OK;
939 Foundation::Point position;
940 aArgs->get_Position(&position);
941 HandleSingleTap(
942 LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position)));
943 return S_OK;
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.
950 HRESULT
951 MetroInput::OnRightTapped(UI::Input::IGestureRecognizer* aSender,
952 UI::Input::IRightTappedEventArgs* aArgs)
954 #ifdef DEBUG_INPUT
955 LogFunction();
956 #endif
958 Devices::Input::PointerDeviceType deviceType;
959 aArgs->get_PointerDeviceType(&deviceType);
961 Foundation::Point position;
962 aArgs->get_Position(&position);
963 HandleLongTap(
964 LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position)));
966 return S_OK;
969 void
970 MetroInput::HandleSingleTap(const LayoutDeviceIntPoint& aPoint)
972 #ifdef DEBUG_INPUT
973 LogFunction();
974 #endif
976 // send mousemove
977 nsMouseEvent* mouseEvent = new nsMouseEvent(true,
978 NS_MOUSE_MOVE,
979 mWidget.Get(),
980 nsMouseEvent::eReal,
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,
990 mWidget.Get(),
991 nsMouseEvent::eReal,
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,
1000 NS_MOUSE_BUTTON_UP,
1001 mWidget.Get(),
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.
1014 POINT point;
1015 if (GetCursorPos(&point)) {
1016 ScreenToClient((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW), &point);
1017 mouseEvent = new nsMouseEvent(true,
1018 NS_MOUSE_MOVE,
1019 mWidget.Get(),
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);
1030 void
1031 MetroInput::HandleLongTap(const LayoutDeviceIntPoint& aPoint)
1033 #ifdef DEBUG_INPUT
1034 LogFunction();
1035 #endif
1037 nsMouseEvent* contextEvent = new nsMouseEvent(true,
1038 NS_CONTEXTMENU,
1039 mWidget.Get(),
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;
1052 void
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);
1064 void
1065 MetroInput::DeliverNextQueuedEventIgnoreStatus()
1067 nsGUIEvent* event = static_cast<nsGUIEvent*>(mInputEventQueue.PopFront());
1068 MOZ_ASSERT(event);
1069 DispatchEventIgnoreStatus(event);
1070 delete event;
1073 nsEventStatus
1074 MetroInput::DeliverNextQueuedEvent()
1076 nsGUIEvent* event = static_cast<nsGUIEvent*>(mInputEventQueue.PopFront());
1077 MOZ_ASSERT(event);
1078 nsEventStatus status;
1079 mWidget->DispatchEvent(event, status);
1080 delete event;
1081 return status;
1084 void
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);
1096 nsEventStatus
1097 MetroInput::DeliverNextQueuedTouchEvent()
1099 nsTouchEvent* event = static_cast<nsTouchEvent*>(mInputEventQueue.PopFront());
1100 MOZ_ASSERT(event);
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);
1108 delete event;
1109 return status;
1112 void
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);
1124 void
1125 MetroInput::DispatchEventIgnoreStatus(nsGUIEvent *aEvent) {
1126 mWidget->DispatchEvent(aEvent, sThrowawayStatus);
1129 void
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
1146 // to it.
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
1155 // it can't hurt.
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);
1164 void
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)
1175 .Get(),
1176 edgeStatics.GetAddressOf());
1177 WRL::ComPtr<UI::Input::IEdgeGesture> edge;
1178 edgeStatics->GetForCurrentView(edge.GetAddressOf());
1180 edge->add_Starting(
1181 WRL::Callback<EdgeGestureHandler>(
1182 this,
1183 &MetroInput::OnEdgeGestureStarted).Get(),
1184 &mTokenEdgeStarted);
1186 edge->add_Canceled(
1187 WRL::Callback<EdgeGestureHandler>(
1188 this,
1189 &MetroInput::OnEdgeGestureCanceled).Get(),
1190 &mTokenEdgeCanceled);
1192 edge->add_Completed(
1193 WRL::Callback<EdgeGestureHandler>(
1194 this,
1195 &MetroInput::OnEdgeGestureCompleted).Get(),
1196 &mTokenEdgeCompleted);
1198 // Set up our Gesture Recognizer to raise events for the gestures we
1199 // care about
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>(
1213 this,
1214 &MetroInput::OnPointerPressed).Get(),
1215 &mTokenPointerPressed);
1217 mWindow->add_PointerReleased(
1218 WRL::Callback<PointerEventHandler>(
1219 this,
1220 &MetroInput::OnPointerReleased).Get(),
1221 &mTokenPointerReleased);
1223 mWindow->add_PointerMoved(
1224 WRL::Callback<PointerEventHandler>(
1225 this,
1226 &MetroInput::OnPointerMoved).Get(),
1227 &mTokenPointerMoved);
1229 mWindow->add_PointerEntered(
1230 WRL::Callback<PointerEventHandler>(
1231 this,
1232 &MetroInput::OnPointerEntered).Get(),
1233 &mTokenPointerEntered);
1235 mWindow->add_PointerExited(
1236 WRL::Callback<PointerEventHandler>(
1237 this,
1238 &MetroInput::OnPointerExited).Get(),
1239 &mTokenPointerExited);
1241 // Register for the events raised by our Gesture Recognizer
1242 mGestureRecognizer->add_Tapped(
1243 WRL::Callback<TappedEventHandler>(
1244 this,
1245 &MetroInput::OnTapped).Get(),
1246 &mTokenTapped);
1248 mGestureRecognizer->add_RightTapped(
1249 WRL::Callback<RightTappedEventHandler>(
1250 this,
1251 &MetroInput::OnRightTapped).Get(),
1252 &mTokenRightTapped);
1254 mGestureRecognizer->add_ManipulationStarted(
1255 WRL::Callback<ManipulationStartedEventHandler>(
1256 this,
1257 &MetroInput::OnManipulationStarted).Get(),
1258 &mTokenManipulationStarted);
1260 mGestureRecognizer->add_ManipulationUpdated(
1261 WRL::Callback<ManipulationUpdatedEventHandler>(
1262 this,
1263 &MetroInput::OnManipulationUpdated).Get(),
1264 &mTokenManipulationUpdated);
1266 mGestureRecognizer->add_ManipulationCompleted(
1267 WRL::Callback<ManipulationCompletedEventHandler>(
1268 this,
1269 &MetroInput::OnManipulationCompleted).Get(),
1270 &mTokenManipulationCompleted);
1273 } } }