diff -r 000000000000 -r 6474c204b198 widget/windows/winrt/MetroInput.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widget/windows/winrt/MetroInput.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,304 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +// Moz headers (alphabetical) +#include "keyboardlayout.h" // mModifierKeyState +#include "nsBaseHashtable.h" // mTouches +#include "nsHashKeys.h" // type of key for mTouches +#include "mozwrlbase.h" +#include "nsDeque.h" +#include "mozilla/EventForwards.h" +#include "mozilla/layers/APZCTreeManager.h" + +// System headers (alphabetical) +#include // EventRegistrationToken +#include // uint32_t +#include // Microsoft::WRL::ComPtr class +#include // Microsoft::WRL::InspectableClass macro + +// Moz forward declarations +class MetroWidget; +struct nsIntPoint; + +namespace mozilla { +namespace dom { +class Touch; +} +} + +// Windows forward declarations +namespace ABI { + namespace Windows { + namespace Devices { + namespace Input { + enum PointerDeviceType; + } + }; + namespace Foundation { + struct Point; + }; + namespace UI { + namespace Core { + struct ICoreWindow; + struct IAcceleratorKeyEventArgs; + struct IKeyEventArgs; + struct IPointerEventArgs; + }; + namespace Input { + struct IEdgeGesture; + struct IEdgeGestureEventArgs; + struct IGestureRecognizer; + struct IManipulationCompletedEventArgs; + struct IManipulationStartedEventArgs; + struct IManipulationUpdatedEventArgs; + struct IPointerPoint; + struct IRightTappedEventArgs; + struct ITappedEventArgs; + struct ManipulationDelta; + }; + }; + }; +}; + +namespace mozilla { +namespace widget { +namespace winrt { + +class MetroInput : public Microsoft::WRL::RuntimeClass +{ + InspectableClass(L"MetroInput", BaseTrust); + +private: + typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior; + typedef uint32_t TouchBehaviorFlags; + + // Devices + typedef ABI::Windows::Devices::Input::PointerDeviceType PointerDeviceType; + + // Foundation + typedef ABI::Windows::Foundation::Point Point; + + // UI::Core + typedef ABI::Windows::UI::Core::ICoreWindow ICoreWindow; + typedef ABI::Windows::UI::Core::IAcceleratorKeyEventArgs \ + IAcceleratorKeyEventArgs; + typedef ABI::Windows::UI::Core::IKeyEventArgs IKeyEventArgs; + typedef ABI::Windows::UI::Core::IPointerEventArgs IPointerEventArgs; + + // UI::Input + typedef ABI::Windows::UI::Input::IEdgeGesture IEdgeGesture; + typedef ABI::Windows::UI::Input::IEdgeGestureEventArgs IEdgeGestureEventArgs; + typedef ABI::Windows::UI::Input::IGestureRecognizer IGestureRecognizer; + typedef ABI::Windows::UI::Input::IManipulationCompletedEventArgs \ + IManipulationCompletedEventArgs; + typedef ABI::Windows::UI::Input::IManipulationStartedEventArgs \ + IManipulationStartedEventArgs; + typedef ABI::Windows::UI::Input::IManipulationUpdatedEventArgs \ + IManipulationUpdatedEventArgs; + typedef ABI::Windows::UI::Input::IPointerPoint IPointerPoint; + typedef ABI::Windows::UI::Input::IRightTappedEventArgs IRightTappedEventArgs; + typedef ABI::Windows::UI::Input::ITappedEventArgs ITappedEventArgs; + typedef ABI::Windows::UI::Input::ManipulationDelta ManipulationDelta; + + typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid; + +public: + MetroInput(MetroWidget* aWidget, + ICoreWindow* aWindow); + virtual ~MetroInput(); + + // These input events are received from our window. These are basic + // pointer and keyboard press events. MetroInput responds to them + // by sending gecko events and forwarding these input events to its + // GestureRecognizer to be processed into more complex input events + // (tap, rightTap, rotate, etc) + HRESULT OnPointerPressed(ICoreWindow* aSender, + IPointerEventArgs* aArgs); + HRESULT OnPointerReleased(ICoreWindow* aSender, + IPointerEventArgs* aArgs); + HRESULT OnPointerMoved(ICoreWindow* aSender, + IPointerEventArgs* aArgs); + HRESULT OnPointerEntered(ICoreWindow* aSender, + IPointerEventArgs* aArgs); + HRESULT OnPointerExited(ICoreWindow* aSender, + IPointerEventArgs* aArgs); + + // The Edge gesture event is special. It does not come from our window + // or from our GestureRecognizer. + HRESULT OnEdgeGestureStarted(IEdgeGesture* aSender, + IEdgeGestureEventArgs* aArgs); + HRESULT OnEdgeGestureCanceled(IEdgeGesture* aSender, + IEdgeGestureEventArgs* aArgs); + HRESULT OnEdgeGestureCompleted(IEdgeGesture* aSender, + IEdgeGestureEventArgs* aArgs); + + // Swipe gesture callback from the GestureRecognizer. + HRESULT OnManipulationCompleted(IGestureRecognizer* aSender, + IManipulationCompletedEventArgs* aArgs); + + // Tap gesture callback from the GestureRecognizer. + HRESULT OnTapped(IGestureRecognizer* aSender, ITappedEventArgs* aArgs); + HRESULT OnRightTapped(IGestureRecognizer* aSender, + IRightTappedEventArgs* aArgs); + + void HandleTap(const Point& aPoint, unsigned int aTapCount); + void HandleLongTap(const Point& aPoint); + + static bool IsInputModeImprecise(); + +private: + Microsoft::WRL::ComPtr mWindow; + Microsoft::WRL::ComPtr mWidget; + Microsoft::WRL::ComPtr mGestureRecognizer; + + ModifierKeyState mModifierKeyState; + + // Tracking input level + enum InputPrecisionLevel { + LEVEL_PRECISE, + LEVEL_IMPRECISE + }; + static InputPrecisionLevel sCurrentInputLevel; + void UpdateInputLevel(InputPrecisionLevel aInputLevel); + + // Initialization/Uninitialization helpers + void RegisterInputEvents(); + void UnregisterInputEvents(); + + // Hit testing for apz content + bool mNonApzTargetForTouch; + bool HitTestChrome(const LayoutDeviceIntPoint& pt); + + // Event processing helpers. See function definitions for more info. + bool TransformRefPoint(const Point& aPosition, + LayoutDeviceIntPoint& aRefPointOut); + void TransformTouchEvent(WidgetTouchEvent* aEvent); + void OnPointerNonTouch(IPointerPoint* aPoint); + void AddPointerMoveDataToRecognizer(IPointerEventArgs* aArgs); + void InitGeckoMouseEventFromPointerPoint(WidgetMouseEvent* aEvent, + IPointerPoint* aPoint); + void ProcessManipulationDelta(ManipulationDelta const& aDelta, + Point const& aPosition, + uint32_t aMagEventType, + uint32_t aRotEventType); + uint16_t ProcessInputTypeForGesture(IEdgeGestureEventArgs* aArgs); + bool ShouldDeliverInputToRecognizer(); + + // Returns array of allowed touch behaviors for touch points of given TouchEvent. + // Note: event argument should be transformed via apzc before supplying to this method. + void GetAllowedTouchBehavior(WidgetTouchEvent* aTransformedEvent, nsTArray& aOutBehaviors); + + // Checks whether any touch behavior is allowed. + bool IsTouchBehaviorForbidden(const nsTArray& aTouchBehaviors); + + // The W3C spec states that "whether preventDefault has been called" should + // be tracked on a per-touchpoint basis, but it also states that touchstart + // and touchmove events can contain multiple changed points. At the time of + // this writing, W3C touch events are in the process of being abandoned in + // favor of W3C pointer events, so it is unlikely that this ambiguity will + // be resolved. Additionally, nsPresShell tracks "whether preventDefault + // has been called" on a per-touch-session basis. We will follow a similar + // approach here. + // + // Specifically: + // If preventDefault is called on the FIRST touchstart event of a touch + // session, then no default actions associated with any touchstart, + // touchmove, or touchend events will be taken. This means that no + // mousedowns, mousemoves, mouseups, clicks, swipes, rotations, + // magnifications, etc will be dispatched during this touch session; + // only touchstart, touchmove, and touchend. + // + // If preventDefault is called on the FIRST touchmove event of a touch + // session, then no default actions associated with the _touchmove_ events + // will be dispatched. However, it is still possible that additional + // events will be generated based on the touchstart and touchend events. + // For example, a set of mousemove, mousedown, and mouseup events might + // be sent if a tap is detected. + bool mContentConsumingTouch; + bool mApzConsumingTouch; + bool mCancelable; + bool mRecognizerWantsEvents; + + nsTArray mCanceledIds; + + // In the old Win32 way of doing things, we would receive a WM_TOUCH event + // that told us the state of every touchpoint on the touch surface. If + // multiple touchpoints had moved since the last update we would learn + // about all their movement simultaneously. + // + // In the new WinRT way of doing things, we receive a separate + // PointerPressed/PointerMoved/PointerReleased event for each touchpoint + // that has changed. + // + // When we learn of touch input, we dispatch gecko events in response. + // With the new WinRT way of doing things, we would end up sending many + // more gecko events than we would using the Win32 mechanism. E.g., + // for 5 active touchpoints, we would be sending 5 times as many gecko + // events. This caused performance to visibly degrade on modestly-powered + // machines. In response, we no longer send touch events immediately + // upon receiving PointerPressed or PointerMoved. Instead, we store + // the updated touchpoint info and record the fact that the touchpoint + // has changed. If ever we try to update a touchpoint has already + // changed, we dispatch a touch event containing all the changed touches. + void InitTouchEventTouchList(WidgetTouchEvent* aEvent); + nsBaseHashtable, + nsRefPtr > mTouches; + + // These registration tokens are set when we register ourselves to receive + // events from our window. We must hold on to them for the entire duration + // that we want to receive these events. When we are done, we must + // unregister ourself with the window using these tokens. + EventRegistrationToken mTokenPointerPressed; + EventRegistrationToken mTokenPointerReleased; + EventRegistrationToken mTokenPointerMoved; + EventRegistrationToken mTokenPointerEntered; + EventRegistrationToken mTokenPointerExited; + + // When we register ourselves to handle edge gestures, we receive a + // token. To we unregister ourselves, we must use the token we received. + EventRegistrationToken mTokenEdgeStarted; + EventRegistrationToken mTokenEdgeCanceled; + EventRegistrationToken mTokenEdgeCompleted; + + // These registration tokens are set when we register ourselves to receive + // events from our GestureRecognizer. It's probably not a huge deal if we + // don't unregister ourselves with our GestureRecognizer before destroying + // the GestureRecognizer, but it can't hurt. + EventRegistrationToken mTokenManipulationCompleted; + EventRegistrationToken mTokenTapped; + EventRegistrationToken mTokenRightTapped; + + // Due to a limitation added in 8.1 the ui thread can't re-enter the main + // native event dispatcher in MetroAppShell. So all events delivered to us + // on the ui thread via a native event dispatch call get bounced through + // the gecko thread event queue using runnables. Most events can be sent + // async without the need to see the status result. Those that do have + // specialty callbacks. Note any event that arrives to us on the ui thread + // that originates from another thread is safe to send sync. + + // Async event dispatching + void DispatchAsyncEventIgnoreStatus(WidgetInputEvent* aEvent); + void DispatchAsyncTouchEvent(WidgetTouchEvent* aEvent); + + // Async event callbacks + void DeliverNextQueuedEventIgnoreStatus(); + void DeliverNextQueuedTouchEvent(); + + void HandleFirstTouchStartEvent(WidgetTouchEvent* aEvent); + void HandleFirstTouchMoveEvent(WidgetTouchEvent* aEvent); + + // Sync event dispatching + void DispatchEventIgnoreStatus(WidgetGUIEvent* aEvent); + void DispatchTouchCancel(WidgetTouchEvent* aEvent); + + nsDeque mInputEventQueue; + mozilla::layers::ScrollableLayerGuid mTargetAPZCGuid; + static nsEventStatus sThrowawayStatus; +}; + +} } }