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