1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/winrt/MetroInput.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,304 @@ 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 +#pragma once 1.10 + 1.11 +// Moz headers (alphabetical) 1.12 +#include "keyboardlayout.h" // mModifierKeyState 1.13 +#include "nsBaseHashtable.h" // mTouches 1.14 +#include "nsHashKeys.h" // type of key for mTouches 1.15 +#include "mozwrlbase.h" 1.16 +#include "nsDeque.h" 1.17 +#include "mozilla/EventForwards.h" 1.18 +#include "mozilla/layers/APZCTreeManager.h" 1.19 + 1.20 +// System headers (alphabetical) 1.21 +#include <EventToken.h> // EventRegistrationToken 1.22 +#include <stdint.h> // uint32_t 1.23 +#include <wrl\client.h> // Microsoft::WRL::ComPtr class 1.24 +#include <wrl\implements.h> // Microsoft::WRL::InspectableClass macro 1.25 + 1.26 +// Moz forward declarations 1.27 +class MetroWidget; 1.28 +struct nsIntPoint; 1.29 + 1.30 +namespace mozilla { 1.31 +namespace dom { 1.32 +class Touch; 1.33 +} 1.34 +} 1.35 + 1.36 +// Windows forward declarations 1.37 +namespace ABI { 1.38 + namespace Windows { 1.39 + namespace Devices { 1.40 + namespace Input { 1.41 + enum PointerDeviceType; 1.42 + } 1.43 + }; 1.44 + namespace Foundation { 1.45 + struct Point; 1.46 + }; 1.47 + namespace UI { 1.48 + namespace Core { 1.49 + struct ICoreWindow; 1.50 + struct IAcceleratorKeyEventArgs; 1.51 + struct IKeyEventArgs; 1.52 + struct IPointerEventArgs; 1.53 + }; 1.54 + namespace Input { 1.55 + struct IEdgeGesture; 1.56 + struct IEdgeGestureEventArgs; 1.57 + struct IGestureRecognizer; 1.58 + struct IManipulationCompletedEventArgs; 1.59 + struct IManipulationStartedEventArgs; 1.60 + struct IManipulationUpdatedEventArgs; 1.61 + struct IPointerPoint; 1.62 + struct IRightTappedEventArgs; 1.63 + struct ITappedEventArgs; 1.64 + struct ManipulationDelta; 1.65 + }; 1.66 + }; 1.67 + }; 1.68 +}; 1.69 + 1.70 +namespace mozilla { 1.71 +namespace widget { 1.72 +namespace winrt { 1.73 + 1.74 +class MetroInput : public Microsoft::WRL::RuntimeClass<IInspectable> 1.75 +{ 1.76 + InspectableClass(L"MetroInput", BaseTrust); 1.77 + 1.78 +private: 1.79 + typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior; 1.80 + typedef uint32_t TouchBehaviorFlags; 1.81 + 1.82 + // Devices 1.83 + typedef ABI::Windows::Devices::Input::PointerDeviceType PointerDeviceType; 1.84 + 1.85 + // Foundation 1.86 + typedef ABI::Windows::Foundation::Point Point; 1.87 + 1.88 + // UI::Core 1.89 + typedef ABI::Windows::UI::Core::ICoreWindow ICoreWindow; 1.90 + typedef ABI::Windows::UI::Core::IAcceleratorKeyEventArgs \ 1.91 + IAcceleratorKeyEventArgs; 1.92 + typedef ABI::Windows::UI::Core::IKeyEventArgs IKeyEventArgs; 1.93 + typedef ABI::Windows::UI::Core::IPointerEventArgs IPointerEventArgs; 1.94 + 1.95 + // UI::Input 1.96 + typedef ABI::Windows::UI::Input::IEdgeGesture IEdgeGesture; 1.97 + typedef ABI::Windows::UI::Input::IEdgeGestureEventArgs IEdgeGestureEventArgs; 1.98 + typedef ABI::Windows::UI::Input::IGestureRecognizer IGestureRecognizer; 1.99 + typedef ABI::Windows::UI::Input::IManipulationCompletedEventArgs \ 1.100 + IManipulationCompletedEventArgs; 1.101 + typedef ABI::Windows::UI::Input::IManipulationStartedEventArgs \ 1.102 + IManipulationStartedEventArgs; 1.103 + typedef ABI::Windows::UI::Input::IManipulationUpdatedEventArgs \ 1.104 + IManipulationUpdatedEventArgs; 1.105 + typedef ABI::Windows::UI::Input::IPointerPoint IPointerPoint; 1.106 + typedef ABI::Windows::UI::Input::IRightTappedEventArgs IRightTappedEventArgs; 1.107 + typedef ABI::Windows::UI::Input::ITappedEventArgs ITappedEventArgs; 1.108 + typedef ABI::Windows::UI::Input::ManipulationDelta ManipulationDelta; 1.109 + 1.110 + typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid; 1.111 + 1.112 +public: 1.113 + MetroInput(MetroWidget* aWidget, 1.114 + ICoreWindow* aWindow); 1.115 + virtual ~MetroInput(); 1.116 + 1.117 + // These input events are received from our window. These are basic 1.118 + // pointer and keyboard press events. MetroInput responds to them 1.119 + // by sending gecko events and forwarding these input events to its 1.120 + // GestureRecognizer to be processed into more complex input events 1.121 + // (tap, rightTap, rotate, etc) 1.122 + HRESULT OnPointerPressed(ICoreWindow* aSender, 1.123 + IPointerEventArgs* aArgs); 1.124 + HRESULT OnPointerReleased(ICoreWindow* aSender, 1.125 + IPointerEventArgs* aArgs); 1.126 + HRESULT OnPointerMoved(ICoreWindow* aSender, 1.127 + IPointerEventArgs* aArgs); 1.128 + HRESULT OnPointerEntered(ICoreWindow* aSender, 1.129 + IPointerEventArgs* aArgs); 1.130 + HRESULT OnPointerExited(ICoreWindow* aSender, 1.131 + IPointerEventArgs* aArgs); 1.132 + 1.133 + // The Edge gesture event is special. It does not come from our window 1.134 + // or from our GestureRecognizer. 1.135 + HRESULT OnEdgeGestureStarted(IEdgeGesture* aSender, 1.136 + IEdgeGestureEventArgs* aArgs); 1.137 + HRESULT OnEdgeGestureCanceled(IEdgeGesture* aSender, 1.138 + IEdgeGestureEventArgs* aArgs); 1.139 + HRESULT OnEdgeGestureCompleted(IEdgeGesture* aSender, 1.140 + IEdgeGestureEventArgs* aArgs); 1.141 + 1.142 + // Swipe gesture callback from the GestureRecognizer. 1.143 + HRESULT OnManipulationCompleted(IGestureRecognizer* aSender, 1.144 + IManipulationCompletedEventArgs* aArgs); 1.145 + 1.146 + // Tap gesture callback from the GestureRecognizer. 1.147 + HRESULT OnTapped(IGestureRecognizer* aSender, ITappedEventArgs* aArgs); 1.148 + HRESULT OnRightTapped(IGestureRecognizer* aSender, 1.149 + IRightTappedEventArgs* aArgs); 1.150 + 1.151 + void HandleTap(const Point& aPoint, unsigned int aTapCount); 1.152 + void HandleLongTap(const Point& aPoint); 1.153 + 1.154 + static bool IsInputModeImprecise(); 1.155 + 1.156 +private: 1.157 + Microsoft::WRL::ComPtr<ICoreWindow> mWindow; 1.158 + Microsoft::WRL::ComPtr<MetroWidget> mWidget; 1.159 + Microsoft::WRL::ComPtr<IGestureRecognizer> mGestureRecognizer; 1.160 + 1.161 + ModifierKeyState mModifierKeyState; 1.162 + 1.163 + // Tracking input level 1.164 + enum InputPrecisionLevel { 1.165 + LEVEL_PRECISE, 1.166 + LEVEL_IMPRECISE 1.167 + }; 1.168 + static InputPrecisionLevel sCurrentInputLevel; 1.169 + void UpdateInputLevel(InputPrecisionLevel aInputLevel); 1.170 + 1.171 + // Initialization/Uninitialization helpers 1.172 + void RegisterInputEvents(); 1.173 + void UnregisterInputEvents(); 1.174 + 1.175 + // Hit testing for apz content 1.176 + bool mNonApzTargetForTouch; 1.177 + bool HitTestChrome(const LayoutDeviceIntPoint& pt); 1.178 + 1.179 + // Event processing helpers. See function definitions for more info. 1.180 + bool TransformRefPoint(const Point& aPosition, 1.181 + LayoutDeviceIntPoint& aRefPointOut); 1.182 + void TransformTouchEvent(WidgetTouchEvent* aEvent); 1.183 + void OnPointerNonTouch(IPointerPoint* aPoint); 1.184 + void AddPointerMoveDataToRecognizer(IPointerEventArgs* aArgs); 1.185 + void InitGeckoMouseEventFromPointerPoint(WidgetMouseEvent* aEvent, 1.186 + IPointerPoint* aPoint); 1.187 + void ProcessManipulationDelta(ManipulationDelta const& aDelta, 1.188 + Point const& aPosition, 1.189 + uint32_t aMagEventType, 1.190 + uint32_t aRotEventType); 1.191 + uint16_t ProcessInputTypeForGesture(IEdgeGestureEventArgs* aArgs); 1.192 + bool ShouldDeliverInputToRecognizer(); 1.193 + 1.194 + // Returns array of allowed touch behaviors for touch points of given TouchEvent. 1.195 + // Note: event argument should be transformed via apzc before supplying to this method. 1.196 + void GetAllowedTouchBehavior(WidgetTouchEvent* aTransformedEvent, nsTArray<TouchBehaviorFlags>& aOutBehaviors); 1.197 + 1.198 + // Checks whether any touch behavior is allowed. 1.199 + bool IsTouchBehaviorForbidden(const nsTArray<TouchBehaviorFlags>& aTouchBehaviors); 1.200 + 1.201 + // The W3C spec states that "whether preventDefault has been called" should 1.202 + // be tracked on a per-touchpoint basis, but it also states that touchstart 1.203 + // and touchmove events can contain multiple changed points. At the time of 1.204 + // this writing, W3C touch events are in the process of being abandoned in 1.205 + // favor of W3C pointer events, so it is unlikely that this ambiguity will 1.206 + // be resolved. Additionally, nsPresShell tracks "whether preventDefault 1.207 + // has been called" on a per-touch-session basis. We will follow a similar 1.208 + // approach here. 1.209 + // 1.210 + // Specifically: 1.211 + // If preventDefault is called on the FIRST touchstart event of a touch 1.212 + // session, then no default actions associated with any touchstart, 1.213 + // touchmove, or touchend events will be taken. This means that no 1.214 + // mousedowns, mousemoves, mouseups, clicks, swipes, rotations, 1.215 + // magnifications, etc will be dispatched during this touch session; 1.216 + // only touchstart, touchmove, and touchend. 1.217 + // 1.218 + // If preventDefault is called on the FIRST touchmove event of a touch 1.219 + // session, then no default actions associated with the _touchmove_ events 1.220 + // will be dispatched. However, it is still possible that additional 1.221 + // events will be generated based on the touchstart and touchend events. 1.222 + // For example, a set of mousemove, mousedown, and mouseup events might 1.223 + // be sent if a tap is detected. 1.224 + bool mContentConsumingTouch; 1.225 + bool mApzConsumingTouch; 1.226 + bool mCancelable; 1.227 + bool mRecognizerWantsEvents; 1.228 + 1.229 + nsTArray<uint32_t> mCanceledIds; 1.230 + 1.231 + // In the old Win32 way of doing things, we would receive a WM_TOUCH event 1.232 + // that told us the state of every touchpoint on the touch surface. If 1.233 + // multiple touchpoints had moved since the last update we would learn 1.234 + // about all their movement simultaneously. 1.235 + // 1.236 + // In the new WinRT way of doing things, we receive a separate 1.237 + // PointerPressed/PointerMoved/PointerReleased event for each touchpoint 1.238 + // that has changed. 1.239 + // 1.240 + // When we learn of touch input, we dispatch gecko events in response. 1.241 + // With the new WinRT way of doing things, we would end up sending many 1.242 + // more gecko events than we would using the Win32 mechanism. E.g., 1.243 + // for 5 active touchpoints, we would be sending 5 times as many gecko 1.244 + // events. This caused performance to visibly degrade on modestly-powered 1.245 + // machines. In response, we no longer send touch events immediately 1.246 + // upon receiving PointerPressed or PointerMoved. Instead, we store 1.247 + // the updated touchpoint info and record the fact that the touchpoint 1.248 + // has changed. If ever we try to update a touchpoint has already 1.249 + // changed, we dispatch a touch event containing all the changed touches. 1.250 + void InitTouchEventTouchList(WidgetTouchEvent* aEvent); 1.251 + nsBaseHashtable<nsUint32HashKey, 1.252 + nsRefPtr<mozilla::dom::Touch>, 1.253 + nsRefPtr<mozilla::dom::Touch> > mTouches; 1.254 + 1.255 + // These registration tokens are set when we register ourselves to receive 1.256 + // events from our window. We must hold on to them for the entire duration 1.257 + // that we want to receive these events. When we are done, we must 1.258 + // unregister ourself with the window using these tokens. 1.259 + EventRegistrationToken mTokenPointerPressed; 1.260 + EventRegistrationToken mTokenPointerReleased; 1.261 + EventRegistrationToken mTokenPointerMoved; 1.262 + EventRegistrationToken mTokenPointerEntered; 1.263 + EventRegistrationToken mTokenPointerExited; 1.264 + 1.265 + // When we register ourselves to handle edge gestures, we receive a 1.266 + // token. To we unregister ourselves, we must use the token we received. 1.267 + EventRegistrationToken mTokenEdgeStarted; 1.268 + EventRegistrationToken mTokenEdgeCanceled; 1.269 + EventRegistrationToken mTokenEdgeCompleted; 1.270 + 1.271 + // These registration tokens are set when we register ourselves to receive 1.272 + // events from our GestureRecognizer. It's probably not a huge deal if we 1.273 + // don't unregister ourselves with our GestureRecognizer before destroying 1.274 + // the GestureRecognizer, but it can't hurt. 1.275 + EventRegistrationToken mTokenManipulationCompleted; 1.276 + EventRegistrationToken mTokenTapped; 1.277 + EventRegistrationToken mTokenRightTapped; 1.278 + 1.279 + // Due to a limitation added in 8.1 the ui thread can't re-enter the main 1.280 + // native event dispatcher in MetroAppShell. So all events delivered to us 1.281 + // on the ui thread via a native event dispatch call get bounced through 1.282 + // the gecko thread event queue using runnables. Most events can be sent 1.283 + // async without the need to see the status result. Those that do have 1.284 + // specialty callbacks. Note any event that arrives to us on the ui thread 1.285 + // that originates from another thread is safe to send sync. 1.286 + 1.287 + // Async event dispatching 1.288 + void DispatchAsyncEventIgnoreStatus(WidgetInputEvent* aEvent); 1.289 + void DispatchAsyncTouchEvent(WidgetTouchEvent* aEvent); 1.290 + 1.291 + // Async event callbacks 1.292 + void DeliverNextQueuedEventIgnoreStatus(); 1.293 + void DeliverNextQueuedTouchEvent(); 1.294 + 1.295 + void HandleFirstTouchStartEvent(WidgetTouchEvent* aEvent); 1.296 + void HandleFirstTouchMoveEvent(WidgetTouchEvent* aEvent); 1.297 + 1.298 + // Sync event dispatching 1.299 + void DispatchEventIgnoreStatus(WidgetGUIEvent* aEvent); 1.300 + void DispatchTouchCancel(WidgetTouchEvent* aEvent); 1.301 + 1.302 + nsDeque mInputEventQueue; 1.303 + mozilla::layers::ScrollableLayerGuid mTargetAPZCGuid; 1.304 + static nsEventStatus sThrowawayStatus; 1.305 +}; 1.306 + 1.307 +} } }