1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/winrt/MetroInput.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1611 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +// Moz headers (alphabetical) 1.10 +#include "MetroInput.h" 1.11 +#include "MetroUtils.h" // Logging, POINT_CEIL_*, ActivateGenericInstance, etc 1.12 +#include "MetroWidget.h" // MetroInput::mWidget 1.13 +#include "mozilla/dom/Touch.h" // Touch 1.14 +#include "nsTArray.h" // Touch lists 1.15 +#include "nsIDOMSimpleGestureEvent.h" // Constants for gesture events 1.16 +#include "InputData.h" 1.17 +#include "UIABridgePrivate.h" 1.18 +#include "MetroAppShell.h" 1.19 +#include "mozilla/EventStateManager.h" 1.20 +#include "mozilla/EventStates.h" 1.21 +#include "mozilla/MouseEvents.h" 1.22 +#include "mozilla/TouchEvents.h" 1.23 +#include "mozilla/Preferences.h" // for Preferences 1.24 +#include "WinUtils.h" 1.25 +#include "nsIPresShell.h" 1.26 + 1.27 +// System headers (alphabetical) 1.28 +#include <windows.ui.core.h> // ABI::Window::UI::Core namespace 1.29 +#include <windows.ui.input.h> // ABI::Window::UI::Input namespace 1.30 + 1.31 +//#define DEBUG_INPUT 1.32 + 1.33 +// Using declarations 1.34 +using namespace ABI::Windows; // UI, System, Foundation namespaces 1.35 +using namespace Microsoft; // WRL namespace (ComPtr, possibly others) 1.36 +using namespace mozilla; 1.37 +using namespace mozilla::widget; 1.38 +using namespace mozilla::widget::winrt; 1.39 +using namespace mozilla::dom; 1.40 + 1.41 +// File-scoped statics (unnamed namespace) 1.42 +namespace { 1.43 + // XXX: Set these min values appropriately 1.44 + const double SWIPE_MIN_DISTANCE = 5.0; 1.45 + const double SWIPE_MIN_VELOCITY = 5.0; 1.46 + 1.47 + // Convenience typedefs for event handler types 1.48 + typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CEdgeGesture_Windows__CUI__CInput__CEdgeGestureEventArgs_t EdgeGestureHandler; 1.49 + typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreDispatcher_Windows__CUI__CCore__CAcceleratorKeyEventArgs_t AcceleratorKeyActivatedHandler; 1.50 + typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs_t PointerEventHandler; 1.51 + typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CTappedEventArgs_t TappedEventHandler; 1.52 + typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CRightTappedEventArgs_t RightTappedEventHandler; 1.53 + typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CManipulationStartedEventArgs_t ManipulationStartedEventHandler; 1.54 + typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CManipulationUpdatedEventArgs_t ManipulationUpdatedEventHandler; 1.55 + typedef Foundation::__FITypedEventHandler_2_Windows__CUI__CInput__CGestureRecognizer_Windows__CUI__CInput__CManipulationCompletedEventArgs_t ManipulationCompletedEventHandler; 1.56 + 1.57 + // Other convenience typedefs 1.58 + typedef ABI::Windows::UI::Core::ICoreAcceleratorKeys ICoreAcceleratorKeys; 1.59 + 1.60 + /** 1.61 + * Specifies whether touch-action property is in force. 1.62 + */ 1.63 + static bool gTouchActionPropertyEnabled = false; 1.64 + 1.65 + /** 1.66 + * Creates and returns a new {@link Touch} from the given 1.67 + * ABI::Windows::UI::Input::IPointerPoint. Note that the caller is 1.68 + * responsible for freeing the memory for the Touch returned from 1.69 + * this function. 1.70 + * 1.71 + * @param aPoint the ABI::Windows::UI::Input::IPointerPoint containing the 1.72 + * metadata from which to create our new {@link Touch} 1.73 + * @return a new {@link Touch} representing the touch point. The caller 1.74 + * is responsible for freeing the memory for this touch point. 1.75 + */ 1.76 + Touch* 1.77 + CreateDOMTouch(UI::Input::IPointerPoint* aPoint) { 1.78 + WRL::ComPtr<UI::Input::IPointerPointProperties> props; 1.79 + Foundation::Point position; 1.80 + uint32_t pointerId; 1.81 + Foundation::Rect contactRect; 1.82 + float pressure; 1.83 + float tiltX; 1.84 + float tiltY; 1.85 + 1.86 + aPoint->get_Properties(props.GetAddressOf()); 1.87 + aPoint->get_Position(&position); 1.88 + aPoint->get_PointerId(&pointerId); 1.89 + props->get_ContactRect(&contactRect); 1.90 + props->get_Pressure(&pressure); 1.91 + props->get_XTilt(&tiltX); 1.92 + props->get_YTilt(&tiltY); 1.93 + 1.94 + nsIntPoint touchPoint = MetroUtils::LogToPhys(position); 1.95 + nsIntPoint touchRadius; 1.96 + touchRadius.x = WinUtils::LogToPhys(contactRect.Width) / 2; 1.97 + touchRadius.y = WinUtils::LogToPhys(contactRect.Height) / 2; 1.98 + Touch* touch = 1.99 + new Touch(pointerId, 1.100 + touchPoint, 1.101 + // Rotation radius and angle. 1.102 + // W3C touch events v1 do not use these. 1.103 + // The draft for W3C touch events v2 explains that 1.104 + // radius and angle should describe the ellipse that 1.105 + // most closely circumscribes the touching area. Since 1.106 + // Windows gives us a bounding rectangle rather than an 1.107 + // ellipse, we provide the ellipse that is most closely 1.108 + // circumscribed by the bounding rectangle that Windows 1.109 + // gave us. 1.110 + touchRadius, 1.111 + 0.0f, 1.112 + // Pressure 1.113 + // W3C touch events v1 do not use this. 1.114 + // The current draft for W3C touch events v2 says that 1.115 + // this should be a value between 0.0 and 1.0, which is 1.116 + // consistent with what Windows provides us here. 1.117 + // XXX: Windows defaults to 0.5, but the current W3C 1.118 + // draft says that the value should be 0.0 if no value 1.119 + // known. 1.120 + pressure); 1.121 + touch->tiltX = tiltX; 1.122 + touch->tiltY = tiltY; 1.123 + return touch; 1.124 + } 1.125 + 1.126 + /** 1.127 + * Test if a touchpoint position has moved. See Touch.Equals for 1.128 + * criteria. 1.129 + * 1.130 + * @param aTouch previous touch point 1.131 + * @param aPoint new winrt touch point 1.132 + * @return true if the point has moved 1.133 + */ 1.134 + bool 1.135 + HasPointMoved(Touch* aTouch, UI::Input::IPointerPoint* aPoint) { 1.136 + WRL::ComPtr<UI::Input::IPointerPointProperties> props; 1.137 + Foundation::Point position; 1.138 + Foundation::Rect contactRect; 1.139 + float pressure; 1.140 + 1.141 + aPoint->get_Properties(props.GetAddressOf()); 1.142 + aPoint->get_Position(&position); 1.143 + props->get_ContactRect(&contactRect); 1.144 + props->get_Pressure(&pressure); 1.145 + nsIntPoint touchPoint = MetroUtils::LogToPhys(position); 1.146 + nsIntPoint touchRadius; 1.147 + touchRadius.x = WinUtils::LogToPhys(contactRect.Width) / 2; 1.148 + touchRadius.y = WinUtils::LogToPhys(contactRect.Height) / 2; 1.149 + 1.150 + // from Touch.Equals 1.151 + return touchPoint != aTouch->mRefPoint || 1.152 + pressure != aTouch->Force() || 1.153 + /* mRotationAngle == aTouch->RotationAngle() || */ 1.154 + touchRadius.x != aTouch->RadiusX() || 1.155 + touchRadius.y != aTouch->RadiusY(); 1.156 + } 1.157 + 1.158 + /** 1.159 + * Converts from the Devices::Input::PointerDeviceType enumeration 1.160 + * to a nsIDOMMouseEvent::MOZ_SOURCE_* value. 1.161 + * 1.162 + * @param aDeviceType the value to convert 1.163 + * @param aMozInputSource the converted value 1.164 + */ 1.165 + void 1.166 + MozInputSourceFromDeviceType( 1.167 + Devices::Input::PointerDeviceType const& aDeviceType, 1.168 + unsigned short& aMozInputSource) { 1.169 + if (Devices::Input::PointerDeviceType::PointerDeviceType_Mouse 1.170 + == aDeviceType) { 1.171 + aMozInputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE; 1.172 + } else if (Devices::Input::PointerDeviceType::PointerDeviceType_Touch 1.173 + == aDeviceType) { 1.174 + aMozInputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.175 + } else if (Devices::Input::PointerDeviceType::PointerDeviceType_Pen 1.176 + == aDeviceType) { 1.177 + aMozInputSource = nsIDOMMouseEvent::MOZ_SOURCE_PEN; 1.178 + } 1.179 + } 1.180 + 1.181 + int16_t 1.182 + ButtonsForPointerPoint(UI::Input::IPointerPoint* aPoint) { 1.183 + WRL::ComPtr<UI::Input::IPointerPointProperties> props; 1.184 + aPoint->get_Properties(props.GetAddressOf()); 1.185 + 1.186 + int16_t buttons = 0; 1.187 + boolean buttonPressed; 1.188 + 1.189 + props->get_IsLeftButtonPressed(&buttonPressed); 1.190 + if (buttonPressed) { 1.191 + buttons |= WidgetMouseEvent::eLeftButtonFlag; 1.192 + } 1.193 + props->get_IsMiddleButtonPressed(&buttonPressed); 1.194 + if (buttonPressed) { 1.195 + buttons |= WidgetMouseEvent::eMiddleButtonFlag; 1.196 + } 1.197 + props->get_IsRightButtonPressed(&buttonPressed); 1.198 + if (buttonPressed) { 1.199 + buttons |= WidgetMouseEvent::eRightButtonFlag; 1.200 + } 1.201 + props->get_IsXButton1Pressed(&buttonPressed); 1.202 + if (buttonPressed) { 1.203 + buttons |= WidgetMouseEvent::e4thButtonFlag; 1.204 + } 1.205 + props->get_IsXButton2Pressed(&buttonPressed); 1.206 + if (buttonPressed) { 1.207 + buttons |= WidgetMouseEvent::e5thButtonFlag; 1.208 + } 1.209 + return buttons; 1.210 + } 1.211 + 1.212 + /** 1.213 + * This function is for use with mTouches.Enumerate. It will 1.214 + * append each element it encounters to the {@link nsTArray} 1.215 + * of {@link mozilla::dom::Touch}es passed in through the third (void*) 1.216 + * parameter. 1.217 + * 1.218 + * NOTE: This function will set the `mChanged` member of each 1.219 + * element it encounters to `false`, since this function is only 1.220 + * used to populate a touchlist that is about to be dispatched 1.221 + * in a gecko touch event. 1.222 + * 1.223 + * @param aKey the key of the current element being enumerated 1.224 + * @param aData the value of the current element being enumerated 1.225 + * @param aTouchList the {@link nsTArray} to append to 1.226 + */ 1.227 + PLDHashOperator 1.228 + AppendToTouchList(const unsigned int& aKey, 1.229 + nsRefPtr<Touch>& aData, 1.230 + void *aTouchList) 1.231 + { 1.232 + nsTArray<nsRefPtr<Touch> > *touches = 1.233 + static_cast<nsTArray<nsRefPtr<Touch> > *>(aTouchList); 1.234 + nsRefPtr<Touch> copy = new Touch(aData->mIdentifier, 1.235 + aData->mRefPoint, 1.236 + aData->mRadius, 1.237 + aData->mRotationAngle, 1.238 + aData->mForce); 1.239 + copy->tiltX = aData->tiltX; 1.240 + copy->tiltY = aData->tiltY; 1.241 + touches->AppendElement(copy); 1.242 + aData->mChanged = false; 1.243 + return PL_DHASH_NEXT; 1.244 + } 1.245 + 1.246 + // Helper for making sure event ptrs get freed. 1.247 + class AutoDeleteEvent 1.248 + { 1.249 + public: 1.250 + AutoDeleteEvent(WidgetGUIEvent* aPtr) : 1.251 + mPtr(aPtr) {} 1.252 + ~AutoDeleteEvent() { 1.253 + if (mPtr) { 1.254 + delete mPtr; 1.255 + } 1.256 + } 1.257 + WidgetGUIEvent* mPtr; 1.258 + }; 1.259 +} 1.260 + 1.261 +namespace mozilla { 1.262 +namespace widget { 1.263 +namespace winrt { 1.264 + 1.265 +MetroInput::InputPrecisionLevel MetroInput::sCurrentInputLevel = 1.266 + MetroInput::InputPrecisionLevel::LEVEL_IMPRECISE; 1.267 + 1.268 +MetroInput::MetroInput(MetroWidget* aWidget, 1.269 + UI::Core::ICoreWindow* aWindow) 1.270 + : mWidget(aWidget), 1.271 + mNonApzTargetForTouch(false), 1.272 + mWindow(aWindow) 1.273 +{ 1.274 + LogFunction(); 1.275 + NS_ASSERTION(aWidget, "Attempted to create MetroInput for null widget!"); 1.276 + NS_ASSERTION(aWindow, "Attempted to create MetroInput for null window!"); 1.277 + 1.278 + Preferences::AddBoolVarCache(&gTouchActionPropertyEnabled, "layout.css.touch_action.enabled", gTouchActionPropertyEnabled); 1.279 + mTokenPointerPressed.value = 0; 1.280 + mTokenPointerReleased.value = 0; 1.281 + mTokenPointerMoved.value = 0; 1.282 + mTokenPointerEntered.value = 0; 1.283 + mTokenPointerExited.value = 0; 1.284 + mTokenEdgeStarted.value = 0; 1.285 + mTokenEdgeCanceled.value = 0; 1.286 + mTokenEdgeCompleted.value = 0; 1.287 + mTokenManipulationCompleted.value = 0; 1.288 + mTokenTapped.value = 0; 1.289 + mTokenRightTapped.value = 0; 1.290 + 1.291 + // Create our Gesture Recognizer 1.292 + ActivateGenericInstance(RuntimeClass_Windows_UI_Input_GestureRecognizer, 1.293 + mGestureRecognizer); 1.294 + NS_ASSERTION(mGestureRecognizer, "Failed to create GestureRecognizer!"); 1.295 + 1.296 + RegisterInputEvents(); 1.297 +} 1.298 + 1.299 +MetroInput::~MetroInput() 1.300 +{ 1.301 + LogFunction(); 1.302 + UnregisterInputEvents(); 1.303 +} 1.304 + 1.305 +/* static */ 1.306 +bool MetroInput::IsInputModeImprecise() 1.307 +{ 1.308 + return sCurrentInputLevel == LEVEL_IMPRECISE; 1.309 +} 1.310 + 1.311 +/** 1.312 + * Tracks the current input level (precise/imprecise) and fires an observer 1.313 + * when the mode changes. 1.314 + */ 1.315 +void 1.316 +MetroInput::UpdateInputLevel(InputPrecisionLevel aInputLevel) 1.317 +{ 1.318 + // ignore mouse input if we have active touch input. 1.319 + if (aInputLevel == LEVEL_PRECISE && mTouches.Count() > 0) { 1.320 + return; 1.321 + } 1.322 + if (sCurrentInputLevel != aInputLevel) { 1.323 + sCurrentInputLevel = aInputLevel; 1.324 + MetroUtils::FireObserver(sCurrentInputLevel == LEVEL_PRECISE ? 1.325 + "metro_precise_input" : "metro_imprecise_input"); 1.326 + } 1.327 +} 1.328 + 1.329 +/** 1.330 + * Processes an IEdgeGestureEventArgs and returns the input source type 1.331 + * for the event. Also updates input level via UpdateInputLevel. 1.332 + */ 1.333 +uint16_t 1.334 +MetroInput::ProcessInputTypeForGesture(UI::Input::IEdgeGestureEventArgs* aArgs) 1.335 +{ 1.336 + MOZ_ASSERT(aArgs); 1.337 + UI::Input::EdgeGestureKind kind; 1.338 + aArgs->get_Kind(&kind); 1.339 + switch(kind) { 1.340 + case UI::Input::EdgeGestureKind::EdgeGestureKind_Touch: 1.341 + UpdateInputLevel(LEVEL_IMPRECISE); 1.342 + return nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.343 + break; 1.344 + case UI::Input::EdgeGestureKind::EdgeGestureKind_Keyboard: 1.345 + return nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; 1.346 + break; 1.347 + case UI::Input::EdgeGestureKind::EdgeGestureKind_Mouse: 1.348 + UpdateInputLevel(LEVEL_PRECISE); 1.349 + return nsIDOMMouseEvent::MOZ_SOURCE_MOUSE; 1.350 + break; 1.351 + } 1.352 + return nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN; 1.353 +} 1.354 + 1.355 +/** 1.356 + * When the user swipes her/his finger in from the top of the screen, 1.357 + * we receive this event. 1.358 + * 1.359 + * @param sender the CoreDispatcher that fired this event 1.360 + * @param aArgs the event-specific args we use when processing this event 1.361 + * @returns S_OK 1.362 + */ 1.363 +HRESULT 1.364 +MetroInput::OnEdgeGestureStarted(UI::Input::IEdgeGesture* sender, 1.365 + UI::Input::IEdgeGestureEventArgs* aArgs) 1.366 +{ 1.367 +#ifdef DEBUG_INPUT 1.368 + LogFunction(); 1.369 +#endif 1.370 + WidgetSimpleGestureEvent geckoEvent(true, 1.371 + NS_SIMPLE_GESTURE_EDGE_STARTED, 1.372 + mWidget.Get()); 1.373 + mModifierKeyState.Update(); 1.374 + mModifierKeyState.InitInputEvent(geckoEvent); 1.375 + geckoEvent.time = ::GetMessageTime(); 1.376 + geckoEvent.inputSource = ProcessInputTypeForGesture(aArgs); 1.377 + 1.378 + // Safe 1.379 + DispatchEventIgnoreStatus(&geckoEvent); 1.380 + return S_OK; 1.381 +} 1.382 + 1.383 +/** 1.384 + * This event can be received if the user swipes her/his finger back to 1.385 + * the top of the screen, or continues moving her/his finger such that 1.386 + * the movement is interpreted as a "grab this window" gesture 1.387 + * 1.388 + * @param sender the CoreDispatcher that fired this event 1.389 + * @param aArgs the event-specific args we use when processing this event 1.390 + * @returns S_OK 1.391 + */ 1.392 +HRESULT 1.393 +MetroInput::OnEdgeGestureCanceled(UI::Input::IEdgeGesture* sender, 1.394 + UI::Input::IEdgeGestureEventArgs* aArgs) 1.395 +{ 1.396 +#ifdef DEBUG_INPUT 1.397 + LogFunction(); 1.398 +#endif 1.399 + WidgetSimpleGestureEvent geckoEvent(true, 1.400 + NS_SIMPLE_GESTURE_EDGE_CANCELED, 1.401 + mWidget.Get()); 1.402 + mModifierKeyState.Update(); 1.403 + mModifierKeyState.InitInputEvent(geckoEvent); 1.404 + geckoEvent.time = ::GetMessageTime(); 1.405 + geckoEvent.inputSource = ProcessInputTypeForGesture(aArgs); 1.406 + 1.407 + // Safe 1.408 + DispatchEventIgnoreStatus(&geckoEvent); 1.409 + return S_OK; 1.410 +} 1.411 + 1.412 +/** 1.413 + * This event is received if the user presses ctrl+Z or lifts her/his 1.414 + * finger after causing an EdgeGestureStarting event to fire. 1.415 + * 1.416 + * @param sender the CoreDispatcher that fired this event 1.417 + * @param aArgs the event-specific args we use when processing this event 1.418 + * @returns S_OK 1.419 + */ 1.420 +HRESULT 1.421 +MetroInput::OnEdgeGestureCompleted(UI::Input::IEdgeGesture* sender, 1.422 + UI::Input::IEdgeGestureEventArgs* aArgs) 1.423 +{ 1.424 +#ifdef DEBUG_INPUT 1.425 + LogFunction(); 1.426 +#endif 1.427 + WidgetSimpleGestureEvent geckoEvent(true, 1.428 + NS_SIMPLE_GESTURE_EDGE_COMPLETED, 1.429 + mWidget.Get()); 1.430 + mModifierKeyState.Update(); 1.431 + mModifierKeyState.InitInputEvent(geckoEvent); 1.432 + geckoEvent.time = ::GetMessageTime(); 1.433 + geckoEvent.inputSource = ProcessInputTypeForGesture(aArgs); 1.434 + 1.435 + // Safe 1.436 + DispatchEventIgnoreStatus(&geckoEvent); 1.437 + return S_OK; 1.438 +} 1.439 + 1.440 +/** 1.441 + * This helper function is used by our processing of PointerPressed, 1.442 + * PointerReleased, and PointerMoved events. 1.443 + * It dispatches a gecko event in response to the input received. This 1.444 + * function should only be called for non-touch (i.e. pen or mouse) input 1.445 + * events. 1.446 + * 1.447 + * @param aPoint the PointerPoint for the input event 1.448 + */ 1.449 +void 1.450 +MetroInput::OnPointerNonTouch(UI::Input::IPointerPoint* aPoint) { 1.451 + WRL::ComPtr<UI::Input::IPointerPointProperties> props; 1.452 + UI::Input::PointerUpdateKind pointerUpdateKind; 1.453 + 1.454 + aPoint->get_Properties(props.GetAddressOf()); 1.455 + props->get_PointerUpdateKind(&pointerUpdateKind); 1.456 + 1.457 + uint32_t message = NS_MOUSE_MOVE; 1.458 + int16_t button = 0; 1.459 + 1.460 + switch (pointerUpdateKind) { 1.461 + case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonPressed: 1.462 + button = WidgetMouseEvent::buttonType::eLeftButton; 1.463 + message = NS_MOUSE_BUTTON_DOWN; 1.464 + break; 1.465 + case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonPressed: 1.466 + button = WidgetMouseEvent::buttonType::eMiddleButton; 1.467 + message = NS_MOUSE_BUTTON_DOWN; 1.468 + break; 1.469 + case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonPressed: 1.470 + button = WidgetMouseEvent::buttonType::eRightButton; 1.471 + message = NS_MOUSE_BUTTON_DOWN; 1.472 + break; 1.473 + case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonReleased: 1.474 + button = WidgetMouseEvent::buttonType::eLeftButton; 1.475 + message = NS_MOUSE_BUTTON_UP; 1.476 + break; 1.477 + case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonReleased: 1.478 + button = WidgetMouseEvent::buttonType::eMiddleButton; 1.479 + message = NS_MOUSE_BUTTON_UP; 1.480 + break; 1.481 + case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonReleased: 1.482 + button = WidgetMouseEvent::buttonType::eRightButton; 1.483 + message = NS_MOUSE_BUTTON_UP; 1.484 + break; 1.485 + } 1.486 + 1.487 + UpdateInputLevel(LEVEL_PRECISE); 1.488 + 1.489 + WidgetMouseEvent* event = 1.490 + new WidgetMouseEvent(true, message, mWidget.Get(), 1.491 + WidgetMouseEvent::eReal, 1.492 + WidgetMouseEvent::eNormal); 1.493 + event->button = button; 1.494 + aPoint->get_PointerId(&event->pointerId); 1.495 + InitGeckoMouseEventFromPointerPoint(event, aPoint); 1.496 + DispatchAsyncEventIgnoreStatus(event); 1.497 +} 1.498 + 1.499 +void 1.500 +MetroInput::InitTouchEventTouchList(WidgetTouchEvent* aEvent) 1.501 +{ 1.502 + MOZ_ASSERT(aEvent); 1.503 + mTouches.Enumerate(&AppendToTouchList, 1.504 + static_cast<void*>(&aEvent->touches)); 1.505 +} 1.506 + 1.507 +bool 1.508 +MetroInput::ShouldDeliverInputToRecognizer() 1.509 +{ 1.510 + return mRecognizerWantsEvents; 1.511 +} 1.512 + 1.513 +void 1.514 +MetroInput::GetAllowedTouchBehavior(WidgetTouchEvent* aTransformedEvent, nsTArray<TouchBehaviorFlags>& aOutBehaviors) 1.515 +{ 1.516 + mWidget->ApzcGetAllowedTouchBehavior(aTransformedEvent, aOutBehaviors); 1.517 + 1.518 + for (uint32_t i = 0; i < aOutBehaviors.Length(); i++) { 1.519 + if (aOutBehaviors[i] & AllowedTouchBehavior::UNKNOWN) { 1.520 + // performing hit testing fallback: asking content to perform hit testing itself 1.521 + // (in spite that this operation has high latency). 1.522 + aOutBehaviors[i] = mWidget->ContentGetAllowedTouchBehavior(aTransformedEvent->touches[i]->mRefPoint); 1.523 + } 1.524 + } 1.525 +} 1.526 + 1.527 +bool 1.528 +MetroInput::IsTouchBehaviorForbidden(const nsTArray<TouchBehaviorFlags>& aTouchBehaviors) 1.529 +{ 1.530 + for (size_t i = 0; i < aTouchBehaviors.Length(); i++) { 1.531 + if (aTouchBehaviors[i] == AllowedTouchBehavior::NONE) 1.532 + return true; 1.533 + } 1.534 + 1.535 + return false; 1.536 +} 1.537 + 1.538 +// This event is raised when the user pushes the left mouse button, presses a 1.539 +// pen to the surface, or presses a touch screen. 1.540 +HRESULT 1.541 +MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender, 1.542 + UI::Core::IPointerEventArgs* aArgs) 1.543 +{ 1.544 +#ifdef DEBUG_INPUT 1.545 + LogFunction(); 1.546 +#endif 1.547 + 1.548 + WRL::ComPtr<UI::Input::IPointerPoint> currentPoint; 1.549 + WRL::ComPtr<Devices::Input::IPointerDevice> device; 1.550 + Devices::Input::PointerDeviceType deviceType; 1.551 + 1.552 + aArgs->get_CurrentPoint(currentPoint.GetAddressOf()); 1.553 + currentPoint->get_PointerDevice(device.GetAddressOf()); 1.554 + device->get_PointerDeviceType(&deviceType); 1.555 + 1.556 + // For mouse and pen input, simply call our helper function 1.557 + if (deviceType != 1.558 + Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { 1.559 + OnPointerNonTouch(currentPoint.Get()); 1.560 + mGestureRecognizer->ProcessDownEvent(currentPoint.Get()); 1.561 + return S_OK; 1.562 + } 1.563 + 1.564 + // This is touch input. 1.565 + UpdateInputLevel(LEVEL_IMPRECISE); 1.566 + 1.567 + // Create the new touch point and add it to our event. 1.568 + uint32_t pointerId; 1.569 + currentPoint->get_PointerId(&pointerId); 1.570 + nsRefPtr<Touch> touch = CreateDOMTouch(currentPoint.Get()); 1.571 + touch->mChanged = true; 1.572 + mTouches.Put(pointerId, touch); 1.573 + 1.574 + WidgetTouchEvent* touchEvent = 1.575 + new WidgetTouchEvent(true, NS_TOUCH_START, mWidget.Get()); 1.576 + 1.577 + if (mTouches.Count() == 1) { 1.578 + // If this is the first touchstart of a touch session reset some 1.579 + // tracking flags. 1.580 + mContentConsumingTouch = false; 1.581 + mApzConsumingTouch = false; 1.582 + mRecognizerWantsEvents = true; 1.583 + mCancelable = true; 1.584 + mCanceledIds.Clear(); 1.585 + } else { 1.586 + mCancelable = false; 1.587 + } 1.588 + 1.589 + InitTouchEventTouchList(touchEvent); 1.590 + DispatchAsyncTouchEvent(touchEvent); 1.591 + 1.592 + if (ShouldDeliverInputToRecognizer()) { 1.593 + mGestureRecognizer->ProcessDownEvent(currentPoint.Get()); 1.594 + } 1.595 + return S_OK; 1.596 +} 1.597 + 1.598 +void 1.599 +MetroInput::AddPointerMoveDataToRecognizer(UI::Core::IPointerEventArgs* aArgs) 1.600 +{ 1.601 + if (ShouldDeliverInputToRecognizer()) { 1.602 + WRL::ComPtr<Foundation::Collections::IVector<UI::Input::PointerPoint*>> 1.603 + pointerPoints; 1.604 + aArgs->GetIntermediatePoints(pointerPoints.GetAddressOf()); 1.605 + mGestureRecognizer->ProcessMoveEvents(pointerPoints.Get()); 1.606 + } 1.607 +} 1.608 + 1.609 +// This event is raised when the user moves the mouse, moves a pen that is 1.610 +// in contact with the surface, or moves a finger that is in contact with 1.611 +// a touch screen. 1.612 +HRESULT 1.613 +MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender, 1.614 + UI::Core::IPointerEventArgs* aArgs) 1.615 +{ 1.616 +#ifdef DEBUG_INPUT 1.617 + LogFunction(); 1.618 +#endif 1.619 + 1.620 + WRL::ComPtr<UI::Input::IPointerPoint> currentPoint; 1.621 + WRL::ComPtr<Devices::Input::IPointerDevice> device; 1.622 + Devices::Input::PointerDeviceType deviceType; 1.623 + 1.624 + aArgs->get_CurrentPoint(currentPoint.GetAddressOf()); 1.625 + currentPoint->get_PointerDevice(device.GetAddressOf()); 1.626 + device->get_PointerDeviceType(&deviceType); 1.627 + 1.628 + // For mouse and pen input, simply call our helper function 1.629 + if (deviceType != 1.630 + Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { 1.631 + OnPointerNonTouch(currentPoint.Get()); 1.632 + AddPointerMoveDataToRecognizer(aArgs); 1.633 + return S_OK; 1.634 + } 1.635 + 1.636 + // This is touch input. 1.637 + UpdateInputLevel(LEVEL_IMPRECISE); 1.638 + 1.639 + // Get the touch associated with this touch point. 1.640 + uint32_t pointerId; 1.641 + currentPoint->get_PointerId(&pointerId); 1.642 + nsRefPtr<Touch> touch = mTouches.Get(pointerId); 1.643 + 1.644 + // Some old drivers cause us to receive a PointerMoved event for a touchId 1.645 + // after we've already received a PointerReleased event for that touchId. 1.646 + // To work around those busted drivers, we simply ignore TouchMoved events 1.647 + // for touchIds that we are not currently tracking. See bug 819223. 1.648 + if (!touch) { 1.649 + return S_OK; 1.650 + } 1.651 + 1.652 + AddPointerMoveDataToRecognizer(aArgs); 1.653 + 1.654 + // If the point hasn't moved, filter it out per the spec. Pres shell does 1.655 + // this as well, but we need to know when our first touchmove is going to 1.656 + // get delivered so we can check the result. 1.657 + if (!HasPointMoved(touch, currentPoint.Get())) { 1.658 + return S_OK; 1.659 + } 1.660 + 1.661 + touch = CreateDOMTouch(currentPoint.Get()); 1.662 + touch->mChanged = true; 1.663 + // replacing old touch point in mTouches map 1.664 + mTouches.Put(pointerId, touch); 1.665 + 1.666 + WidgetTouchEvent* touchEvent = 1.667 + new WidgetTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get()); 1.668 + InitTouchEventTouchList(touchEvent); 1.669 + DispatchAsyncTouchEvent(touchEvent); 1.670 + 1.671 + return S_OK; 1.672 +} 1.673 + 1.674 +// This event is raised when the user lifts the left mouse button, lifts a 1.675 +// pen from the surface, or lifts her/his finger from a touch screen. 1.676 +HRESULT 1.677 +MetroInput::OnPointerReleased(UI::Core::ICoreWindow* aSender, 1.678 + UI::Core::IPointerEventArgs* aArgs) 1.679 +{ 1.680 +#ifdef DEBUG_INPUT 1.681 + LogFunction(); 1.682 +#endif 1.683 + 1.684 + WRL::ComPtr<UI::Input::IPointerPoint> currentPoint; 1.685 + WRL::ComPtr<Devices::Input::IPointerDevice> device; 1.686 + Devices::Input::PointerDeviceType deviceType; 1.687 + 1.688 + aArgs->get_CurrentPoint(currentPoint.GetAddressOf()); 1.689 + currentPoint->get_PointerDevice(device.GetAddressOf()); 1.690 + device->get_PointerDeviceType(&deviceType); 1.691 + 1.692 + // For mouse and pen input, simply call our helper function 1.693 + if (deviceType != 1.694 + Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { 1.695 + OnPointerNonTouch(currentPoint.Get()); 1.696 + mGestureRecognizer->ProcessUpEvent(currentPoint.Get()); 1.697 + return S_OK; 1.698 + } 1.699 + 1.700 + // This is touch input. 1.701 + UpdateInputLevel(LEVEL_IMPRECISE); 1.702 + 1.703 + // Get the touch associated with this touch point. 1.704 + uint32_t pointerId; 1.705 + currentPoint->get_PointerId(&pointerId); 1.706 + nsRefPtr<Touch> touch = mTouches.Get(pointerId); 1.707 + 1.708 + // Purge any pending moves for this pointer 1.709 + if (touch->mChanged) { 1.710 + WidgetTouchEvent* touchEvent = 1.711 + new WidgetTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get()); 1.712 + InitTouchEventTouchList(touchEvent); 1.713 + DispatchAsyncTouchEvent(touchEvent); 1.714 + } 1.715 + 1.716 + // Remove this touch point from our map. Eventually all touch points are 1.717 + // removed for this session since we receive released events for every 1.718 + // point. 1.719 + mTouches.Remove(pointerId); 1.720 + 1.721 + // touchend events only have a single touch; the touch that has been removed 1.722 + WidgetTouchEvent* touchEvent = 1.723 + new WidgetTouchEvent(true, NS_TOUCH_END, mWidget.Get()); 1.724 + touchEvent->touches.AppendElement(CreateDOMTouch(currentPoint.Get())); 1.725 + DispatchAsyncTouchEvent(touchEvent); 1.726 + 1.727 + if (ShouldDeliverInputToRecognizer()) { 1.728 + mGestureRecognizer->ProcessUpEvent(currentPoint.Get()); 1.729 + } 1.730 + 1.731 + return S_OK; 1.732 +} 1.733 + 1.734 +// Tests for chrome vs. content target so we know whether input coordinates need 1.735 +// to be transformed through the apz. Eventually this hit testing should move 1.736 +// into the apz (bug 918288). 1.737 +bool 1.738 +MetroInput::HitTestChrome(const LayoutDeviceIntPoint& pt) 1.739 +{ 1.740 + // Confirm this event targets content. We pick this up in browser's input.js. 1.741 + WidgetMouseEvent hittest(true, NS_MOUSE_MOZHITTEST, mWidget.Get(), 1.742 + WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal); 1.743 + hittest.refPoint = pt; 1.744 + nsEventStatus status; 1.745 + mWidget->DispatchEvent(&hittest, status); 1.746 + return (status == nsEventStatus_eConsumeNoDefault); 1.747 +} 1.748 + 1.749 +/** 1.750 + * Returns true if the position is in chrome, false otherwise. 1.751 + */ 1.752 +bool 1.753 +MetroInput::TransformRefPoint(const Foundation::Point& aPosition, LayoutDeviceIntPoint& aRefPointOut) 1.754 +{ 1.755 + // If this event is destined for content we need to transform our ref point through 1.756 + // the apz so that zoom can be accounted for. 1.757 + aRefPointOut = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition)); 1.758 + ScreenIntPoint spt; 1.759 + spt.x = aRefPointOut.x; 1.760 + spt.y = aRefPointOut.y; 1.761 + // This is currently a general contained rect hit test, it may produce a false positive for 1.762 + // overlay chrome elements. 1.763 + bool apzIntersect = mWidget->ApzHitTest(spt); 1.764 + if (!apzIntersect) { 1.765 + return true; 1.766 + } 1.767 + if (HitTestChrome(aRefPointOut)) { 1.768 + return true; 1.769 + } 1.770 + mWidget->ApzTransformGeckoCoordinate(spt, &aRefPointOut); 1.771 + return false; 1.772 +} 1.773 + 1.774 +void 1.775 +MetroInput::TransformTouchEvent(WidgetTouchEvent* aEvent) 1.776 +{ 1.777 + nsTArray< nsRefPtr<dom::Touch> >& touches = aEvent->touches; 1.778 + for (uint32_t i = 0; i < touches.Length(); ++i) { 1.779 + dom::Touch* touch = touches[i]; 1.780 + if (touch) { 1.781 + LayoutDeviceIntPoint lpt; 1.782 + ScreenIntPoint spt; 1.783 + spt.x = touch->mRefPoint.x; 1.784 + spt.y = touch->mRefPoint.y; 1.785 + mWidget->ApzTransformGeckoCoordinate(spt, &lpt); 1.786 + touch->mRefPoint.x = lpt.x; 1.787 + touch->mRefPoint.y = lpt.y; 1.788 + } 1.789 + } 1.790 +} 1.791 + 1.792 +void 1.793 +MetroInput::InitGeckoMouseEventFromPointerPoint( 1.794 + WidgetMouseEvent* aEvent, 1.795 + UI::Input::IPointerPoint* aPointerPoint) 1.796 +{ 1.797 + NS_ASSERTION(aPointerPoint, "InitGeckoMouseEventFromPointerPoint " 1.798 + "called with null PointerPoint!"); 1.799 + 1.800 + WRL::ComPtr<UI::Input::IPointerPointProperties> props; 1.801 + WRL::ComPtr<Devices::Input::IPointerDevice> device; 1.802 + Devices::Input::PointerDeviceType deviceType; 1.803 + Foundation::Point position; 1.804 + uint64_t timestamp; 1.805 + float pressure; 1.806 + boolean canBeDoubleTap; 1.807 + float tiltX; 1.808 + float tiltY; 1.809 + 1.810 + aPointerPoint->get_Position(&position); 1.811 + aPointerPoint->get_Timestamp(×tamp); 1.812 + aPointerPoint->get_PointerDevice(device.GetAddressOf()); 1.813 + device->get_PointerDeviceType(&deviceType); 1.814 + aPointerPoint->get_Properties(props.GetAddressOf()); 1.815 + aPointerPoint->get_PointerId(&aEvent->pointerId); 1.816 + props->get_Pressure(&pressure); 1.817 + props->get_XTilt(&tiltX); 1.818 + props->get_YTilt(&tiltY); 1.819 + 1.820 + mGestureRecognizer->CanBeDoubleTap(aPointerPoint, &canBeDoubleTap); 1.821 + 1.822 + TransformRefPoint(position, aEvent->refPoint); 1.823 + 1.824 + if (!canBeDoubleTap) { 1.825 + aEvent->clickCount = 1; 1.826 + } else { 1.827 + aEvent->clickCount = 2; 1.828 + } 1.829 + aEvent->pressure = pressure; 1.830 + aEvent->tiltX = tiltX; 1.831 + aEvent->tiltY = tiltY; 1.832 + aEvent->buttons = ButtonsForPointerPoint(aPointerPoint); 1.833 + 1.834 + MozInputSourceFromDeviceType(deviceType, aEvent->inputSource); 1.835 +} 1.836 + 1.837 +// This event is raised when a precise pointer moves into the bounding box of 1.838 +// our window. For touch input, this will be raised before the PointerPressed 1.839 +// event. 1.840 +HRESULT 1.841 +MetroInput::OnPointerEntered(UI::Core::ICoreWindow* aSender, 1.842 + UI::Core::IPointerEventArgs* aArgs) 1.843 +{ 1.844 +#ifdef DEBUG_INPUT 1.845 + LogFunction(); 1.846 +#endif 1.847 + 1.848 + WRL::ComPtr<UI::Input::IPointerPoint> currentPoint; 1.849 + WRL::ComPtr<Devices::Input::IPointerDevice> device; 1.850 + Devices::Input::PointerDeviceType deviceType; 1.851 + 1.852 + aArgs->get_CurrentPoint(currentPoint.GetAddressOf()); 1.853 + currentPoint->get_PointerDevice(device.GetAddressOf()); 1.854 + device->get_PointerDeviceType(&deviceType); 1.855 + 1.856 + // We only dispatch mouseenter and mouseexit events for mouse and pen input. 1.857 + if (deviceType != 1.858 + Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { 1.859 + WidgetMouseEvent* event = 1.860 + new WidgetMouseEvent(true, NS_MOUSE_ENTER, mWidget.Get(), 1.861 + WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal); 1.862 + UpdateInputLevel(LEVEL_PRECISE); 1.863 + InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get()); 1.864 + DispatchAsyncEventIgnoreStatus(event); 1.865 + return S_OK; 1.866 + } 1.867 + UpdateInputLevel(LEVEL_IMPRECISE); 1.868 + return S_OK; 1.869 +} 1.870 + 1.871 +// This event is raised when a precise pointer leaves the bounding box of 1.872 +// our window. For touch input, this will be raised before the 1.873 +// PointerReleased event. 1.874 +HRESULT 1.875 +MetroInput::OnPointerExited(UI::Core::ICoreWindow* aSender, 1.876 + UI::Core::IPointerEventArgs* aArgs) 1.877 +{ 1.878 +#ifdef DEBUG_INPUT 1.879 + LogFunction(); 1.880 +#endif 1.881 + 1.882 + WRL::ComPtr<UI::Input::IPointerPoint> currentPoint; 1.883 + WRL::ComPtr<Devices::Input::IPointerDevice> device; 1.884 + Devices::Input::PointerDeviceType deviceType; 1.885 + 1.886 + aArgs->get_CurrentPoint(currentPoint.GetAddressOf()); 1.887 + currentPoint->get_PointerDevice(device.GetAddressOf()); 1.888 + device->get_PointerDeviceType(&deviceType); 1.889 + 1.890 + // We only dispatch mouseenter and mouseexit events for mouse and pen input. 1.891 + if (deviceType != 1.892 + Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { 1.893 + WidgetMouseEvent* event = 1.894 + new WidgetMouseEvent(true, NS_MOUSE_EXIT, mWidget.Get(), 1.895 + WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal); 1.896 + UpdateInputLevel(LEVEL_PRECISE); 1.897 + InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get()); 1.898 + DispatchAsyncEventIgnoreStatus(event); 1.899 + return S_OK; 1.900 + } 1.901 + UpdateInputLevel(LEVEL_IMPRECISE); 1.902 + return S_OK; 1.903 +} 1.904 + 1.905 +// Gecko expects a "finished" event to be sent that has the cumulative 1.906 +// changes since the gesture began. The idea is that consumers could hook 1.907 +// only this last event and still effectively support magnification and 1.908 +// rotation. We accomplish sending this "finished" event by calling our 1.909 +// helper function with a cumulative "delta" value. 1.910 +// 1.911 +// After sending the "finished" event, this function detects and sends 1.912 +// swipe gestures. 1.913 +HRESULT 1.914 +MetroInput::OnManipulationCompleted( 1.915 + UI::Input::IGestureRecognizer* aSender, 1.916 + UI::Input::IManipulationCompletedEventArgs* aArgs) 1.917 +{ 1.918 +#ifdef DEBUG_INPUT 1.919 + LogFunction(); 1.920 +#endif 1.921 + 1.922 + Devices::Input::PointerDeviceType deviceType; 1.923 + aArgs->get_PointerDeviceType(&deviceType); 1.924 + if (deviceType == 1.925 + Devices::Input::PointerDeviceType::PointerDeviceType_Mouse) { 1.926 + return S_OK; 1.927 + } 1.928 + 1.929 + UI::Input::ManipulationDelta delta; 1.930 + Foundation::Point position; 1.931 + 1.932 + aArgs->get_Position(&position); 1.933 + aArgs->get_Cumulative(&delta); 1.934 + 1.935 + // We check that the distance the user's finger traveled and the 1.936 + // velocity with which it traveled exceed our thresholds for 1.937 + // classifying the movement as a swipe. 1.938 + UI::Input::ManipulationVelocities velocities; 1.939 + aArgs->get_Velocities(&velocities); 1.940 + 1.941 + bool isHorizontalSwipe = 1.942 + abs(velocities.Linear.X) >= SWIPE_MIN_VELOCITY 1.943 + && abs(delta.Translation.X) >= SWIPE_MIN_DISTANCE; 1.944 + bool isVerticalSwipe = 1.945 + abs(velocities.Linear.Y) >= SWIPE_MIN_VELOCITY 1.946 + && abs(delta.Translation.Y) >= SWIPE_MIN_DISTANCE; 1.947 + 1.948 + // If our thresholds were exceeded for both a vertical and a horizontal 1.949 + // swipe, it means the user is flinging her/his finger around and we 1.950 + // should just ignore the input. 1.951 + if (isHorizontalSwipe && isVerticalSwipe) { 1.952 + return S_OK; 1.953 + } 1.954 + 1.955 + if (isHorizontalSwipe) { 1.956 + WidgetSimpleGestureEvent* swipeEvent = 1.957 + new WidgetSimpleGestureEvent(true, NS_SIMPLE_GESTURE_SWIPE, 1.958 + mWidget.Get()); 1.959 + swipeEvent->direction = delta.Translation.X > 0 1.960 + ? nsIDOMSimpleGestureEvent::DIRECTION_RIGHT 1.961 + : nsIDOMSimpleGestureEvent::DIRECTION_LEFT; 1.962 + swipeEvent->delta = delta.Translation.X; 1.963 + swipeEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.964 + swipeEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position)); 1.965 + DispatchAsyncEventIgnoreStatus(swipeEvent); 1.966 + } 1.967 + 1.968 + if (isVerticalSwipe) { 1.969 + WidgetSimpleGestureEvent* swipeEvent = 1.970 + new WidgetSimpleGestureEvent(true, NS_SIMPLE_GESTURE_SWIPE, 1.971 + mWidget.Get()); 1.972 + swipeEvent->direction = delta.Translation.Y > 0 1.973 + ? nsIDOMSimpleGestureEvent::DIRECTION_DOWN 1.974 + : nsIDOMSimpleGestureEvent::DIRECTION_UP; 1.975 + swipeEvent->delta = delta.Translation.Y; 1.976 + swipeEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.977 + swipeEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position)); 1.978 + DispatchAsyncEventIgnoreStatus(swipeEvent); 1.979 + } 1.980 + 1.981 + return S_OK; 1.982 +} 1.983 + 1.984 +// This event is raised when a sequence of pointer events has been 1.985 +// interpreted by the GestureRecognizer as a tap (this could be a mouse 1.986 +// click, a pen tap, or a tap on a touch surface). 1.987 +HRESULT 1.988 +MetroInput::OnTapped(UI::Input::IGestureRecognizer* aSender, 1.989 + UI::Input::ITappedEventArgs* aArgs) 1.990 +{ 1.991 +#ifdef DEBUG_INPUT 1.992 + LogFunction(); 1.993 +#endif 1.994 + 1.995 + Devices::Input::PointerDeviceType deviceType; 1.996 + aArgs->get_PointerDeviceType(&deviceType); 1.997 + 1.998 + unsigned int tapCount; 1.999 + aArgs->get_TapCount(&tapCount); 1.1000 + 1.1001 + // For mouse and pen input, we send mousedown/mouseup/mousemove 1.1002 + // events as soon as we detect the input event. For touch input, a set of 1.1003 + // mousedown/mouseup events will be sent only once a tap has been detected. 1.1004 + if (deviceType != Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { 1.1005 + return S_OK; 1.1006 + } 1.1007 + 1.1008 + Foundation::Point position; 1.1009 + aArgs->get_Position(&position); 1.1010 + HandleTap(position, tapCount); 1.1011 + return S_OK; 1.1012 +} 1.1013 + 1.1014 +// This event is raised when a sequence of pointer events has been 1.1015 +// interpreted by the GestureRecognizer as a right tap. 1.1016 +// This could be a mouse right-click, a right-click on a pen, or 1.1017 +// a tap-and-hold on a touch surface. 1.1018 +HRESULT 1.1019 +MetroInput::OnRightTapped(UI::Input::IGestureRecognizer* aSender, 1.1020 + UI::Input::IRightTappedEventArgs* aArgs) 1.1021 +{ 1.1022 +#ifdef DEBUG_INPUT 1.1023 + LogFunction(); 1.1024 +#endif 1.1025 + 1.1026 + Devices::Input::PointerDeviceType deviceType; 1.1027 + aArgs->get_PointerDeviceType(&deviceType); 1.1028 + 1.1029 + Foundation::Point position; 1.1030 + aArgs->get_Position(&position); 1.1031 + HandleLongTap(position); 1.1032 + 1.1033 + return S_OK; 1.1034 +} 1.1035 + 1.1036 +void 1.1037 +MetroInput::HandleTap(const Foundation::Point& aPoint, unsigned int aTapCount) 1.1038 +{ 1.1039 +#ifdef DEBUG_INPUT 1.1040 + LogFunction(); 1.1041 +#endif 1.1042 + 1.1043 + LayoutDeviceIntPoint refPoint; 1.1044 + TransformRefPoint(aPoint, refPoint); 1.1045 + 1.1046 + WidgetMouseEvent* mouseEvent = 1.1047 + new WidgetMouseEvent(true, NS_MOUSE_MOVE, mWidget.Get(), 1.1048 + WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal); 1.1049 + mouseEvent->refPoint = refPoint; 1.1050 + mouseEvent->clickCount = aTapCount; 1.1051 + mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.1052 + DispatchAsyncEventIgnoreStatus(mouseEvent); 1.1053 + 1.1054 + mouseEvent = 1.1055 + new WidgetMouseEvent(true, NS_MOUSE_BUTTON_DOWN, mWidget.Get(), 1.1056 + WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal); 1.1057 + mouseEvent->refPoint = refPoint; 1.1058 + mouseEvent->clickCount = aTapCount; 1.1059 + mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.1060 + mouseEvent->button = WidgetMouseEvent::buttonType::eLeftButton; 1.1061 + DispatchAsyncEventIgnoreStatus(mouseEvent); 1.1062 + 1.1063 + mouseEvent = 1.1064 + new WidgetMouseEvent(true, NS_MOUSE_BUTTON_UP, mWidget.Get(), 1.1065 + WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal); 1.1066 + mouseEvent->refPoint = refPoint; 1.1067 + mouseEvent->clickCount = aTapCount; 1.1068 + mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.1069 + mouseEvent->button = WidgetMouseEvent::buttonType::eLeftButton; 1.1070 + DispatchAsyncEventIgnoreStatus(mouseEvent); 1.1071 + 1.1072 + // Make sure all gecko events are dispatched and the dom is up to date 1.1073 + // so that when ui automation comes in looking for focus info it gets 1.1074 + // the right information. 1.1075 + MetroAppShell::MarkEventQueueForPurge(); 1.1076 +} 1.1077 + 1.1078 +void 1.1079 +MetroInput::HandleLongTap(const Foundation::Point& aPoint) 1.1080 +{ 1.1081 +#ifdef DEBUG_INPUT 1.1082 + LogFunction(); 1.1083 +#endif 1.1084 + LayoutDeviceIntPoint refPoint; 1.1085 + TransformRefPoint(aPoint, refPoint); 1.1086 + 1.1087 + WidgetMouseEvent* contextEvent = 1.1088 + new WidgetMouseEvent(true, NS_CONTEXTMENU, mWidget.Get(), 1.1089 + WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal); 1.1090 + contextEvent->refPoint = refPoint; 1.1091 + contextEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.1092 + DispatchAsyncEventIgnoreStatus(contextEvent); 1.1093 +} 1.1094 + 1.1095 +/** 1.1096 + * Implementation Details 1.1097 + */ 1.1098 +nsEventStatus MetroInput::sThrowawayStatus; 1.1099 + 1.1100 +void 1.1101 +MetroInput::DispatchAsyncEventIgnoreStatus(WidgetInputEvent* aEvent) 1.1102 +{ 1.1103 + aEvent->time = ::GetMessageTime(); 1.1104 + mModifierKeyState.Update(); 1.1105 + mModifierKeyState.InitInputEvent(*aEvent); 1.1106 + mInputEventQueue.Push(aEvent); 1.1107 + nsCOMPtr<nsIRunnable> runnable = 1.1108 + NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedEventIgnoreStatus); 1.1109 + NS_DispatchToCurrentThread(runnable); 1.1110 +} 1.1111 + 1.1112 +void 1.1113 +MetroInput::DeliverNextQueuedEventIgnoreStatus() 1.1114 +{ 1.1115 + nsAutoPtr<WidgetGUIEvent> event = 1.1116 + static_cast<WidgetGUIEvent*>(mInputEventQueue.PopFront()); 1.1117 + MOZ_ASSERT(event.get()); 1.1118 + DispatchEventIgnoreStatus(event.get()); 1.1119 + 1.1120 + // Let app shell know we've delivered that last input we wanted purged 1.1121 + // via a call to MarkEventQueueForPurge(). 1.1122 + if (event->message == NS_MOUSE_BUTTON_UP) { 1.1123 + MetroAppShell::InputEventsDispatched(); 1.1124 + } 1.1125 + 1.1126 + // Clear :hover/:active states for mouse events generated by HandleTap 1.1127 + WidgetMouseEvent* mouseEvent = event.get()->AsMouseEvent(); 1.1128 + if (!mouseEvent) { 1.1129 + return; 1.1130 + } 1.1131 + if (mouseEvent->message != NS_MOUSE_BUTTON_UP || 1.1132 + mouseEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { 1.1133 + return; 1.1134 + } 1.1135 + nsCOMPtr<nsIPresShell> presShell = mWidget->GetPresShell(); 1.1136 + if (presShell) { 1.1137 + EventStateManager* esm = presShell->GetPresContext()->EventStateManager(); 1.1138 + if (esm) { 1.1139 + esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER); 1.1140 + } 1.1141 + } 1.1142 +} 1.1143 + 1.1144 +void 1.1145 +MetroInput::DispatchAsyncTouchEvent(WidgetTouchEvent* aEvent) 1.1146 +{ 1.1147 + aEvent->time = ::GetMessageTime(); 1.1148 + mModifierKeyState.Update(); 1.1149 + mModifierKeyState.InitInputEvent(*aEvent); 1.1150 + mInputEventQueue.Push(aEvent); 1.1151 + nsCOMPtr<nsIRunnable> runnable = 1.1152 + NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedTouchEvent); 1.1153 + NS_DispatchToCurrentThread(runnable); 1.1154 +} 1.1155 + 1.1156 +static void DumpTouchIds(const char* aTarget, WidgetTouchEvent* aEvent) 1.1157 +{ 1.1158 + // comment out for touch moves 1.1159 + if (aEvent->message == NS_TOUCH_MOVE) { 1.1160 + return; 1.1161 + } 1.1162 + switch(aEvent->message) { 1.1163 + case NS_TOUCH_START: 1.1164 + WinUtils::Log("DumpTouchIds: NS_TOUCH_START block"); 1.1165 + break; 1.1166 + case NS_TOUCH_MOVE: 1.1167 + WinUtils::Log("DumpTouchIds: NS_TOUCH_MOVE block"); 1.1168 + break; 1.1169 + case NS_TOUCH_END: 1.1170 + WinUtils::Log("DumpTouchIds: NS_TOUCH_END block"); 1.1171 + break; 1.1172 + case NS_TOUCH_CANCEL: 1.1173 + WinUtils::Log("DumpTouchIds: NS_TOUCH_CANCEL block"); 1.1174 + break; 1.1175 + } 1.1176 + nsTArray< nsRefPtr<dom::Touch> >& touches = aEvent->touches; 1.1177 + for (uint32_t i = 0; i < touches.Length(); ++i) { 1.1178 + dom::Touch* touch = touches[i]; 1.1179 + if (!touch) { 1.1180 + continue; 1.1181 + } 1.1182 + int32_t id = touch->Identifier(); 1.1183 + WinUtils::Log(" id=%d target=%s", id, aTarget); 1.1184 + } 1.1185 +} 1.1186 + 1.1187 +static void DumpTouchBehavior(nsTArray<uint32_t>& aBehavior) 1.1188 +{ 1.1189 + WinUtils::Log("DumpTouchBehavior: Touch behavior flags set for current touch session:"); 1.1190 + for (uint32_t i = 0; i < aBehavior.Length(); i++) { 1.1191 + if (mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN & aBehavior[i]) { 1.1192 + WinUtils::Log("VERTICAL_PAN"); 1.1193 + } 1.1194 + 1.1195 + if (mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN & aBehavior[i]) { 1.1196 + WinUtils::Log("HORIZONTAL_PAN"); 1.1197 + } 1.1198 + 1.1199 + if (mozilla::layers::AllowedTouchBehavior::UNKNOWN & aBehavior[i]) { 1.1200 + WinUtils::Log("UNKNOWN"); 1.1201 + } 1.1202 + 1.1203 + if ((mozilla::layers::AllowedTouchBehavior::NONE & aBehavior[i]) == 0) { 1.1204 + WinUtils::Log("NONE"); 1.1205 + } 1.1206 + } 1.1207 +} 1.1208 + 1.1209 +/* 1.1210 + * nsPreShell's processing of WidgetTouchEvent events: 1.1211 + * 1.1212 + * NS_TOUCH_START: 1.1213 + * Interprets a single touch point as the first touch point of a block and will reset its 1.1214 + * queue when it receives this. For multiple touch points it sets all points in its queue 1.1215 + * and marks new points as changed. 1.1216 + * NS_TOUCH_MOVE: 1.1217 + * Uses the equality tests in dom::Touch to test if a touch point has changed (moved). 1.1218 + * If a point has moved, keeps this touch point in the event, otherwise it removes 1.1219 + * the touch point. Note if no points have changed, it exits without sending a dom event. 1.1220 + * NS_TOUCH_CANCEL/NS_TOUCH_END 1.1221 + * Assumes any point in touchEvent->touches has been removed or canceled. 1.1222 +*/ 1.1223 + 1.1224 +//#define DUMP_TOUCH_IDS(aTarget, aEvent) DumpTouchIds(aTarget, aEvent) 1.1225 +#define DUMP_TOUCH_IDS(...) 1.1226 + 1.1227 +//#define DUMP_ALLOWED_TOUCH_BEHAVIOR(aBehavior) DumpTouchBehavior(aBehavior) 1.1228 +#define DUMP_ALLOWED_TOUCH_BEHAVIOR(...) 1.1229 + 1.1230 +void 1.1231 +MetroInput::HandleFirstTouchStartEvent(WidgetTouchEvent* aEvent) 1.1232 +{ 1.1233 + nsEventStatus contentStatus = nsEventStatus_eIgnore; 1.1234 + 1.1235 + WidgetTouchEvent transformedEvent(*aEvent); 1.1236 + DUMP_TOUCH_IDS("APZC(1)", aEvent); 1.1237 + mWidget->ApzReceiveInputEvent(&transformedEvent, &mTargetAPZCGuid); 1.1238 + 1.1239 + if (gTouchActionPropertyEnabled) { 1.1240 + nsTArray<TouchBehaviorFlags> touchBehaviors; 1.1241 + // Retrieving touch behaviors from apzctm and from the content (if needed) 1.1242 + // then setting it back to the apzc. The apzc we retrieved touch behaviors 1.1243 + // from and we're setting to may changes if there are multiple touches (in that 1.1244 + // case apzctm needs to take common ancestor of them). 1.1245 + GetAllowedTouchBehavior(&transformedEvent, touchBehaviors); 1.1246 + // Setting the touch behaviors to the apzc that will be responsible 1.1247 + // for interpreting it. It may be not the same apzc we retrieved touch 1.1248 + // action values from. E.g. for zooming we're taking parent apzc of a few ones 1.1249 + // that were touched but touch behaviors would be taken from childs. 1.1250 + DUMP_ALLOWED_TOUCH_BEHAVIOR(touchBehaviors); 1.1251 + mWidget->ApzcSetAllowedTouchBehavior(mTargetAPZCGuid, touchBehaviors); 1.1252 + if (IsTouchBehaviorForbidden(touchBehaviors)) { 1.1253 + mContentConsumingTouch = true; 1.1254 + } 1.1255 + } 1.1256 + 1.1257 + DUMP_TOUCH_IDS("DOM(2)", aEvent); 1.1258 + mWidget->DispatchEvent(&transformedEvent, contentStatus); 1.1259 + if (nsEventStatus_eConsumeNoDefault == contentStatus) { 1.1260 + mContentConsumingTouch = true; 1.1261 + } 1.1262 + 1.1263 + if (mContentConsumingTouch) { 1.1264 + mCancelable = false; 1.1265 + mWidget->ApzContentConsumingTouch(mTargetAPZCGuid); 1.1266 + DispatchTouchCancel(aEvent); 1.1267 + } 1.1268 + 1.1269 + // Disable gesture based events (taps, swipes, rotation) if 1.1270 + // preventDefault is called on touchstart. 1.1271 + mRecognizerWantsEvents = !(nsEventStatus_eConsumeNoDefault == contentStatus); 1.1272 + 1.1273 + // If content is consuming touch don't generate any gesture based 1.1274 + // input - clear the recognizer state without sending any events. 1.1275 + if (!ShouldDeliverInputToRecognizer()) { 1.1276 + mGestureRecognizer->CompleteGesture(); 1.1277 + } 1.1278 +} 1.1279 + 1.1280 +void 1.1281 +MetroInput::HandleFirstTouchMoveEvent(WidgetTouchEvent* aEvent) 1.1282 +{ 1.1283 + mCancelable = false; 1.1284 + 1.1285 + nsEventStatus contentStatus = nsEventStatus_eIgnore; 1.1286 + nsEventStatus apzcStatus = nsEventStatus_eIgnore; 1.1287 + 1.1288 + WidgetTouchEvent transformedEvent(*aEvent); 1.1289 + DUMP_TOUCH_IDS("APZC(2)", aEvent); 1.1290 + apzcStatus = mWidget->ApzReceiveInputEvent(&transformedEvent, &mTargetAPZCGuid); 1.1291 + 1.1292 + // We need to dispatch here only touch event, not pointer one. 1.1293 + // That's because according to the spec pointer events doesn't imply pointermove event 1.1294 + // between pointerdown and pointercancel (If default touch behavior is triggered). 1.1295 + // But at the same time we need to dispatch at least touchmove event to let content to 1.1296 + // consume it (or not consume). 1.1297 + // TODO: determine how to dispatch only one kind of events: currently there are two options: 1.1298 + // 1) Create two separate instances of the WidgetTouchEvent and WidgetPointerEvent and 1.1299 + // dispatch them separately. 1.1300 + // 2) Add a boolean flag to the WidgetTouchEvent that states whether this event should produce 1.1301 + // both touch and pointer event or only touch one. 1.1302 + // Anyway it's worth to add this stuff only after patches from bug 822898 (Pointer events) are 1.1303 + // fully commited. 1.1304 + DUMP_TOUCH_IDS("DOM(3)", aEvent); 1.1305 + mWidget->DispatchEvent(&transformedEvent, contentStatus); 1.1306 + 1.1307 + // Checking content result first since content can override apzc wish and disallow apzc touch 1.1308 + // behavior (via preventDefault). 1.1309 + if (nsEventStatus_eConsumeNoDefault == contentStatus) { 1.1310 + // Touchmove handler consumed touch. 1.1311 + mContentConsumingTouch = true; 1.1312 + } else if (nsEventStatus_eConsumeNoDefault == apzcStatus) { 1.1313 + // Apzc triggered default behavior. 1.1314 + mApzConsumingTouch = true; 1.1315 + } 1.1316 + 1.1317 + // Let the apz know if content wants to consume touch events, or cancel 1.1318 + // the touch block for content. 1.1319 + if (mContentConsumingTouch) { 1.1320 + mWidget->ApzContentConsumingTouch(mTargetAPZCGuid); 1.1321 + DispatchTouchCancel(aEvent); 1.1322 + } else { 1.1323 + mWidget->ApzContentIgnoringTouch(mTargetAPZCGuid); 1.1324 + } 1.1325 + 1.1326 + if (mApzConsumingTouch) { 1.1327 + // Dispatching cancel to the content. 1.1328 + DispatchTouchCancel(&transformedEvent); 1.1329 + } 1.1330 +} 1.1331 + 1.1332 +void 1.1333 +MetroInput::DeliverNextQueuedTouchEvent() 1.1334 +{ 1.1335 + /* 1.1336 + * We go through states here and make different decisions in each: 1.1337 + * 1.1338 + * 1) Hit test for apz on first touchstart 1.1339 + * If non-apzc content/chrome is the target simplify event delivery from 1.1340 + * that point on by directing all input to chrome, bypassing the apz. 1.1341 + * 2) Process first touchstart and touchmove events 1.1342 + * If touch behavior value associated with the TouchStart's touches doesn't 1.1343 + * allow zooming or panning we explicitly set mContentConsumingTouch to true. 1.1344 + * Otherwise check the result and set mContentConsumingTouch appropriately. 1.1345 + * Deliver touch events to the apz (ignoring return result) and to content. 1.1346 + * 3) If mContentConsumingTouch is true: deliver touch to content after 1.1347 + * transforming through the apz. Also let the apz know content is 1.1348 + * consuming touch and deliver cancel event to apz. 1.1349 + * 4) If mContentConsumingTouch is false: check the result from the apz and 1.1350 + * set mApzConsumingTouch appropriately. 1.1351 + * 5) If mApzConsumingTouch is true: send a touchcancel to content 1.1352 + * and deliver all events to the apz. If the apz is doing something with 1.1353 + * the events we can save ourselves the overhead of delivering dom events. 1.1354 + * 1.1355 + * Notes: 1.1356 + * - never rely on the contents of mTouches here, since this is a delayed 1.1357 + * callback. mTouches will likely have been modified. 1.1358 + */ 1.1359 + nsEventStatus status = nsEventStatus_eIgnore; 1.1360 + 1.1361 + WidgetTouchEvent* event = 1.1362 + static_cast<WidgetTouchEvent*>(mInputEventQueue.PopFront()); 1.1363 + MOZ_ASSERT(event); 1.1364 + 1.1365 + AutoDeleteEvent wrap(event); 1.1366 + 1.1367 + // Test for non-apz vs. apz target. To do this we only use the first touch 1.1368 + // point since that will be the input batch target. Cache this for touch events 1.1369 + // since HitTestChrome has to send a dom event. 1.1370 + if (mCancelable && event->message == NS_TOUCH_START) { 1.1371 + nsRefPtr<Touch> touch = event->touches[0]; 1.1372 + LayoutDeviceIntPoint pt = LayoutDeviceIntPoint::FromUntyped(touch->mRefPoint); 1.1373 + // This is currently a general contained rect hit test, it may produce a false 1.1374 + // positive for overlay chrome elements. Also, some content pages won't support 1.1375 + // apzc, so this may be false for content as well. 1.1376 + bool apzIntersect = mWidget->ApzHitTest(mozilla::ScreenIntPoint(pt.x, pt.y)); 1.1377 + mNonApzTargetForTouch = (!apzIntersect || HitTestChrome(pt)); 1.1378 + } 1.1379 + 1.1380 + // If this event is destined for dom, deliver it directly there bypassing 1.1381 + // the apz. 1.1382 + if (mNonApzTargetForTouch) { 1.1383 + DUMP_TOUCH_IDS("DOM(1)", event); 1.1384 + mWidget->DispatchEvent(event, status); 1.1385 + if (mCancelable) { 1.1386 + // Disable gesture based events (taps, swipes, rotation) if 1.1387 + // preventDefault is called on touchstart. 1.1388 + if (nsEventStatus_eConsumeNoDefault == status) { 1.1389 + mRecognizerWantsEvents = false; 1.1390 + mGestureRecognizer->CompleteGesture(); 1.1391 + } 1.1392 + if (event->message == NS_TOUCH_MOVE) { 1.1393 + mCancelable = false; 1.1394 + } 1.1395 + } 1.1396 + return; 1.1397 + } 1.1398 + 1.1399 + if (mCancelable && event->message == NS_TOUCH_START) { 1.1400 + HandleFirstTouchStartEvent(event); 1.1401 + return; 1.1402 + } else if (mCancelable && event->message == NS_TOUCH_MOVE) { 1.1403 + HandleFirstTouchMoveEvent(event); 1.1404 + return; 1.1405 + } 1.1406 + // Let TouchEnd events go through even if mCancelable is true since we 1.1407 + // don't need to check whether it is prevented by content or consumed 1.1408 + // by apzc. 1.1409 + 1.1410 + // If content is consuming touch, we may need to transform event coords 1.1411 + // through the apzc before sending to the dom. Otherwise send the event 1.1412 + // to apzc. 1.1413 + if (mContentConsumingTouch) { 1.1414 + // Only translate if we're dealing with web content that's transformed 1.1415 + // by the apzc. 1.1416 + TransformTouchEvent(event); 1.1417 + DUMP_TOUCH_IDS("DOM(4)", event); 1.1418 + mWidget->DispatchEvent(event, status); 1.1419 + return; 1.1420 + } 1.1421 + 1.1422 + DUMP_TOUCH_IDS("APZC(3)", event); 1.1423 + status = mWidget->ApzReceiveInputEvent(event, nullptr); 1.1424 + 1.1425 + // If we're getting a new touch (touch start) after some touch start/move 1.1426 + // events we need to reset touch behavior for touches. 1.1427 + if (gTouchActionPropertyEnabled && event->message == NS_TOUCH_START) { 1.1428 + nsTArray<TouchBehaviorFlags> touchBehaviors; 1.1429 + GetAllowedTouchBehavior(event, touchBehaviors); 1.1430 + DUMP_ALLOWED_TOUCH_BEHAVIOR(touchBehaviors); 1.1431 + mWidget->ApzcSetAllowedTouchBehavior(mTargetAPZCGuid, touchBehaviors); 1.1432 + } 1.1433 + 1.1434 + // Send the event to content unless APZC is consuming it. 1.1435 + if (!mApzConsumingTouch) { 1.1436 + if (status == nsEventStatus_eConsumeNoDefault) { 1.1437 + mApzConsumingTouch = true; 1.1438 + DispatchTouchCancel(event); 1.1439 + return; 1.1440 + } 1.1441 + TransformTouchEvent(event); 1.1442 + DUMP_TOUCH_IDS("DOM(5)", event); 1.1443 + mWidget->DispatchEvent(event, status); 1.1444 + } 1.1445 +} 1.1446 + 1.1447 +void 1.1448 +MetroInput::DispatchTouchCancel(WidgetTouchEvent* aEvent) 1.1449 +{ 1.1450 + MOZ_ASSERT(aEvent); 1.1451 + // Send a touchcancel for each pointer id we have a corresponding start 1.1452 + // for. Note we can't rely on mTouches here since touchends remove points 1.1453 + // from it. 1.1454 + WidgetTouchEvent touchEvent(true, NS_TOUCH_CANCEL, mWidget.Get()); 1.1455 + nsTArray< nsRefPtr<dom::Touch> >& touches = aEvent->touches; 1.1456 + for (uint32_t i = 0; i < touches.Length(); ++i) { 1.1457 + dom::Touch* touch = touches[i]; 1.1458 + if (!touch) { 1.1459 + continue; 1.1460 + } 1.1461 + int32_t id = touch->Identifier(); 1.1462 + if (mCanceledIds.Contains(id)) { 1.1463 + continue; 1.1464 + } 1.1465 + mCanceledIds.AppendElement(id); 1.1466 + touchEvent.touches.AppendElement(touch); 1.1467 + } 1.1468 + if (!touchEvent.touches.Length()) { 1.1469 + return; 1.1470 + } 1.1471 + if (mContentConsumingTouch) { 1.1472 + DUMP_TOUCH_IDS("APZC(4)", &touchEvent); 1.1473 + mWidget->ApzReceiveInputEvent(&touchEvent, nullptr); 1.1474 + } else { 1.1475 + DUMP_TOUCH_IDS("DOM(6)", &touchEvent); 1.1476 + mWidget->DispatchEvent(&touchEvent, sThrowawayStatus); 1.1477 + } 1.1478 +} 1.1479 + 1.1480 +void 1.1481 +MetroInput::DispatchEventIgnoreStatus(WidgetGUIEvent *aEvent) 1.1482 +{ 1.1483 + mWidget->DispatchEvent(aEvent, sThrowawayStatus); 1.1484 +} 1.1485 + 1.1486 +void 1.1487 +MetroInput::UnregisterInputEvents() { 1.1488 + // Unregister ourselves for the edge swipe event 1.1489 + WRL::ComPtr<UI::Input::IEdgeGestureStatics> edgeStatics; 1.1490 + if (SUCCEEDED(Foundation::GetActivationFactory( 1.1491 + WRL::Wrappers::HStringReference( 1.1492 + RuntimeClass_Windows_UI_Input_EdgeGesture).Get(), 1.1493 + edgeStatics.GetAddressOf()))) { 1.1494 + WRL::ComPtr<UI::Input::IEdgeGesture> edge; 1.1495 + if (SUCCEEDED(edgeStatics->GetForCurrentView(edge.GetAddressOf()))) { 1.1496 + edge->remove_Starting(mTokenEdgeStarted); 1.1497 + edge->remove_Canceled(mTokenEdgeCanceled); 1.1498 + edge->remove_Completed(mTokenEdgeCompleted); 1.1499 + } 1.1500 + } 1.1501 + // Unregister ourselves from the window events. This is extremely important; 1.1502 + // once this object is destroyed we don't want Windows to try to send events 1.1503 + // to it. 1.1504 + mWindow->remove_PointerPressed(mTokenPointerPressed); 1.1505 + mWindow->remove_PointerReleased(mTokenPointerReleased); 1.1506 + mWindow->remove_PointerMoved(mTokenPointerMoved); 1.1507 + mWindow->remove_PointerEntered(mTokenPointerEntered); 1.1508 + mWindow->remove_PointerExited(mTokenPointerExited); 1.1509 + 1.1510 + // Unregistering from the gesture recognizer events probably isn't as 1.1511 + // necessary since we're about to destroy the gesture recognizer, but 1.1512 + // it can't hurt. 1.1513 + mGestureRecognizer->remove_ManipulationCompleted( 1.1514 + mTokenManipulationCompleted); 1.1515 + mGestureRecognizer->remove_Tapped(mTokenTapped); 1.1516 + mGestureRecognizer->remove_RightTapped(mTokenRightTapped); 1.1517 +} 1.1518 + 1.1519 +void 1.1520 +MetroInput::RegisterInputEvents() 1.1521 +{ 1.1522 + NS_ASSERTION(mWindow, "Must have a window to register for input events!"); 1.1523 + NS_ASSERTION(mGestureRecognizer, 1.1524 + "Must have a GestureRecognizer for input events!"); 1.1525 + // Register for edge swipe 1.1526 + WRL::ComPtr<UI::Input::IEdgeGestureStatics> edgeStatics; 1.1527 + Foundation::GetActivationFactory( 1.1528 + WRL::Wrappers::HStringReference( 1.1529 + RuntimeClass_Windows_UI_Input_EdgeGesture) 1.1530 + .Get(), 1.1531 + edgeStatics.GetAddressOf()); 1.1532 + WRL::ComPtr<UI::Input::IEdgeGesture> edge; 1.1533 + edgeStatics->GetForCurrentView(edge.GetAddressOf()); 1.1534 + 1.1535 + edge->add_Starting( 1.1536 + WRL::Callback<EdgeGestureHandler>( 1.1537 + this, 1.1538 + &MetroInput::OnEdgeGestureStarted).Get(), 1.1539 + &mTokenEdgeStarted); 1.1540 + 1.1541 + edge->add_Canceled( 1.1542 + WRL::Callback<EdgeGestureHandler>( 1.1543 + this, 1.1544 + &MetroInput::OnEdgeGestureCanceled).Get(), 1.1545 + &mTokenEdgeCanceled); 1.1546 + 1.1547 + edge->add_Completed( 1.1548 + WRL::Callback<EdgeGestureHandler>( 1.1549 + this, 1.1550 + &MetroInput::OnEdgeGestureCompleted).Get(), 1.1551 + &mTokenEdgeCompleted); 1.1552 + 1.1553 + // Set up our Gesture Recognizer to raise events for the gestures we 1.1554 + // care about 1.1555 + mGestureRecognizer->put_GestureSettings( 1.1556 + UI::Input::GestureSettings::GestureSettings_Tap 1.1557 + | UI::Input::GestureSettings::GestureSettings_DoubleTap 1.1558 + | UI::Input::GestureSettings::GestureSettings_RightTap 1.1559 + | UI::Input::GestureSettings::GestureSettings_Hold 1.1560 + | UI::Input::GestureSettings::GestureSettings_ManipulationTranslateX 1.1561 + | UI::Input::GestureSettings::GestureSettings_ManipulationTranslateY); 1.1562 + 1.1563 + // Register for the pointer events on our Window 1.1564 + mWindow->add_PointerPressed( 1.1565 + WRL::Callback<PointerEventHandler>( 1.1566 + this, 1.1567 + &MetroInput::OnPointerPressed).Get(), 1.1568 + &mTokenPointerPressed); 1.1569 + 1.1570 + mWindow->add_PointerReleased( 1.1571 + WRL::Callback<PointerEventHandler>( 1.1572 + this, 1.1573 + &MetroInput::OnPointerReleased).Get(), 1.1574 + &mTokenPointerReleased); 1.1575 + 1.1576 + mWindow->add_PointerMoved( 1.1577 + WRL::Callback<PointerEventHandler>( 1.1578 + this, 1.1579 + &MetroInput::OnPointerMoved).Get(), 1.1580 + &mTokenPointerMoved); 1.1581 + 1.1582 + mWindow->add_PointerEntered( 1.1583 + WRL::Callback<PointerEventHandler>( 1.1584 + this, 1.1585 + &MetroInput::OnPointerEntered).Get(), 1.1586 + &mTokenPointerEntered); 1.1587 + 1.1588 + mWindow->add_PointerExited( 1.1589 + WRL::Callback<PointerEventHandler>( 1.1590 + this, 1.1591 + &MetroInput::OnPointerExited).Get(), 1.1592 + &mTokenPointerExited); 1.1593 + 1.1594 + // Register for the events raised by our Gesture Recognizer 1.1595 + mGestureRecognizer->add_Tapped( 1.1596 + WRL::Callback<TappedEventHandler>( 1.1597 + this, 1.1598 + &MetroInput::OnTapped).Get(), 1.1599 + &mTokenTapped); 1.1600 + 1.1601 + mGestureRecognizer->add_RightTapped( 1.1602 + WRL::Callback<RightTappedEventHandler>( 1.1603 + this, 1.1604 + &MetroInput::OnRightTapped).Get(), 1.1605 + &mTokenRightTapped); 1.1606 + 1.1607 + mGestureRecognizer->add_ManipulationCompleted( 1.1608 + WRL::Callback<ManipulationCompletedEventHandler>( 1.1609 + this, 1.1610 + &MetroInput::OnManipulationCompleted).Get(), 1.1611 + &mTokenManipulationCompleted); 1.1612 +} 1.1613 + 1.1614 +} } }