forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			221 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 2; 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/. */
 | |
| 
 | |
| /*
 | |
|  * WinPointerEvents - Helper functions to retrieve PointerEvent's attributes
 | |
|  */
 | |
| 
 | |
| #include "nscore.h"
 | |
| #include "WinPointerEvents.h"
 | |
| #include "mozilla/MouseEvents.h"
 | |
| #include "mozilla/WindowsVersion.h"
 | |
| #include "mozilla/dom/MouseEventBinding.h"
 | |
| 
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::widget;
 | |
| 
 | |
| const wchar_t WinPointerEvents::kPointerLibraryName[] =  L"user32.dll";
 | |
| HMODULE WinPointerEvents::sLibraryHandle = nullptr;
 | |
| WinPointerEvents::GetPointerTypePtr WinPointerEvents::getPointerType = nullptr;
 | |
| WinPointerEvents::GetPointerInfoPtr WinPointerEvents::getPointerInfo = nullptr;
 | |
| WinPointerEvents::GetPointerPenInfoPtr WinPointerEvents::getPointerPenInfo = nullptr;
 | |
| bool WinPointerEvents::sPointerEventEnabled = true;
 | |
| bool WinPointerEvents::sFirePointerEventsByWinPointerMessages = false;
 | |
| 
 | |
| WinPointerEvents::WinPointerEvents()
 | |
| {
 | |
|   InitLibrary();
 | |
|   static bool addedPointerEventEnabled = false;
 | |
|   if (!addedPointerEventEnabled) {
 | |
|     Preferences::AddBoolVarCache(&sPointerEventEnabled,
 | |
|                                  "dom.w3c_pointer_events.enabled", true);
 | |
|     Preferences::AddBoolVarCache(
 | |
|       &sFirePointerEventsByWinPointerMessages,
 | |
|       "dom.w3c_pointer_events.dispatch_by_pointer_messages", false);
 | |
|     addedPointerEventEnabled = true;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* Load and shutdown */
 | |
| void
 | |
| WinPointerEvents::InitLibrary()
 | |
| {
 | |
|   MOZ_ASSERT(XRE_IsParentProcess());
 | |
|   if (!IsWin8OrLater()) {
 | |
|     // Only Win8 or later supports WM_POINTER*
 | |
|     return;
 | |
|   }
 | |
|   if (getPointerType) {
 | |
|     // Return if we already initialized the PointerEvent related interfaces
 | |
|     return;
 | |
|   }
 | |
|   sLibraryHandle = ::LoadLibraryW(kPointerLibraryName);
 | |
|   MOZ_ASSERT(sLibraryHandle, "cannot load pointer library");
 | |
|   if (sLibraryHandle) {
 | |
|     getPointerType =
 | |
|       (GetPointerTypePtr)GetProcAddress(sLibraryHandle, "GetPointerType");
 | |
|     getPointerInfo =
 | |
|       (GetPointerInfoPtr)GetProcAddress(sLibraryHandle, "GetPointerInfo");
 | |
|     getPointerPenInfo =
 | |
|       (GetPointerPenInfoPtr)GetProcAddress(sLibraryHandle, "GetPointerPenInfo");
 | |
|   }
 | |
| 
 | |
|   if (!getPointerType || !getPointerInfo || !getPointerPenInfo) {
 | |
|     MOZ_ASSERT(false, "get PointerEvent interfaces failed");
 | |
|     getPointerType = nullptr;
 | |
|     getPointerInfo = nullptr;
 | |
|     getPointerPenInfo = nullptr;
 | |
|     return;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool
 | |
| WinPointerEvents::ShouldHandleWinPointerMessages(UINT aMsg, WPARAM aWParam)
 | |
| {
 | |
|   MOZ_ASSERT(aMsg == WM_POINTERDOWN || aMsg == WM_POINTERUP ||
 | |
|              aMsg == WM_POINTERUPDATE || aMsg == WM_POINTERLEAVE);
 | |
|   if (!sLibraryHandle || !sPointerEventEnabled) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // We only handle WM_POINTER* when the input source is pen. This is because
 | |
|   // we need some information (e.g. tiltX, tiltY) which can't be retrieved by
 | |
|   // WM_*BUTTONDOWN.
 | |
|   uint32_t pointerId = GetPointerId(aWParam);
 | |
|   POINTER_INPUT_TYPE pointerType = PT_POINTER;
 | |
|   if (!GetPointerType(pointerId, &pointerType)) {
 | |
|     MOZ_ASSERT(false, "cannot find PointerType");
 | |
|     return false;
 | |
|   }
 | |
|   return (pointerType == PT_PEN);
 | |
| }
 | |
| 
 | |
| bool
 | |
| WinPointerEvents::GetPointerType(uint32_t aPointerId,
 | |
|                                  POINTER_INPUT_TYPE *aPointerType)
 | |
| {
 | |
|   if (!getPointerType) {
 | |
|     return false;
 | |
|   }
 | |
|   return getPointerType(aPointerId, aPointerType);
 | |
| }
 | |
| 
 | |
| POINTER_INPUT_TYPE
 | |
| WinPointerEvents::GetPointerType(uint32_t aPointerId)
 | |
| {
 | |
|   POINTER_INPUT_TYPE pointerType = PT_POINTER;
 | |
|   Unused << GetPointerType(aPointerId, &pointerType);
 | |
|   return pointerType;
 | |
| }
 | |
| 
 | |
| bool
 | |
| WinPointerEvents::GetPointerInfo(uint32_t aPointerId,
 | |
|                                  POINTER_INFO *aPointerInfo)
 | |
| {
 | |
|   if (!getPointerInfo) {
 | |
|     return false;
 | |
|   }
 | |
|   return getPointerInfo(aPointerId, aPointerInfo);
 | |
| }
 | |
| 
 | |
| bool
 | |
| WinPointerEvents::GetPointerPenInfo(uint32_t aPointerId,
 | |
|                                     POINTER_PEN_INFO *aPenInfo)
 | |
| {
 | |
|   if (!getPointerPenInfo) {
 | |
|     return false;
 | |
|   }
 | |
|   return getPointerPenInfo(aPointerId, aPenInfo);
 | |
| }
 | |
| 
 | |
| bool
 | |
| WinPointerEvents::ShouldEnableInkCollector()
 | |
| {
 | |
|   // We need InkCollector on Win7. For Win8 or later, we handle WM_POINTER* for
 | |
|   // pen.
 | |
|   return !IsWin8OrLater();
 | |
| }
 | |
| 
 | |
| bool
 | |
| WinPointerEvents::ShouldRollupOnPointerEvent(UINT aMsg, WPARAM aWParam)
 | |
| {
 | |
|   MOZ_ASSERT(aMsg == WM_POINTERDOWN);
 | |
|   // Only roll up popups when we handling WM_POINTER* to fire Gecko
 | |
|   // WidgetMouseEvent and suppress Windows WM_*BUTTONDOWN.
 | |
|   return ShouldHandleWinPointerMessages(aMsg, aWParam) &&
 | |
|          ShouldFirePointerEventByWinPointerMessages();
 | |
| }
 | |
| 
 | |
| bool
 | |
| WinPointerEvents::ShouldFirePointerEventByWinPointerMessages()
 | |
| {
 | |
|   MOZ_ASSERT(sLibraryHandle && sPointerEventEnabled);
 | |
|   return sFirePointerEventsByWinPointerMessages;
 | |
| }
 | |
| 
 | |
| WinPointerInfo*
 | |
| WinPointerEvents::GetCachedPointerInfo(UINT aMsg, WPARAM aWParam)
 | |
| {
 | |
|   if (!sLibraryHandle || !sPointerEventEnabled ||
 | |
|       MOUSE_INPUT_SOURCE() != dom::MouseEvent_Binding::MOZ_SOURCE_PEN ||
 | |
|       ShouldFirePointerEventByWinPointerMessages()) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   switch (aMsg) {
 | |
|   case WM_LBUTTONDOWN:
 | |
|   case WM_MBUTTONDOWN:
 | |
|   case WM_RBUTTONDOWN:
 | |
|     return &mPenPointerDownInfo;
 | |
|   case WM_LBUTTONUP:
 | |
|   case WM_MBUTTONUP:
 | |
|   case WM_RBUTTONUP:
 | |
|     return &mPenPointerDownInfo;
 | |
|   case WM_MOUSEMOVE:
 | |
|     return &mPenPointerUpdateInfo;
 | |
|   default:
 | |
|     MOZ_ASSERT(false);
 | |
|   }
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| void
 | |
| WinPointerEvents::ConvertAndCachePointerInfo(UINT aMsg, WPARAM aWParam)
 | |
| {
 | |
|   MOZ_ASSERT(!sFirePointerEventsByWinPointerMessages);
 | |
|   // Windows doesn't support chorded buttons for pen, so we can simply keep the
 | |
|   // latest information from pen generated pointer messages and use them when
 | |
|   // handling mouse messages. Used different pointer info for pointerdown,
 | |
|   // pointerupdate, and pointerup because Windows doesn't always interleave
 | |
|   // pointer messages and mouse messages.
 | |
|   switch (aMsg) {
 | |
|   case WM_POINTERDOWN:
 | |
|     ConvertAndCachePointerInfo(aWParam, &mPenPointerDownInfo);
 | |
|     break;
 | |
|   case WM_POINTERUP:
 | |
|     ConvertAndCachePointerInfo(aWParam, &mPenPointerUpInfo);
 | |
|     break;
 | |
|   case WM_POINTERUPDATE:
 | |
|     ConvertAndCachePointerInfo(aWParam, &mPenPointerUpdateInfo);
 | |
|     break;
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| WinPointerEvents::ConvertAndCachePointerInfo(WPARAM aWParam,
 | |
|                                              WinPointerInfo* aInfo)
 | |
| {
 | |
|   MOZ_ASSERT(!sFirePointerEventsByWinPointerMessages);
 | |
|   aInfo->pointerId = GetPointerId(aWParam);
 | |
|   MOZ_ASSERT(GetPointerType(aInfo->pointerId) == PT_PEN);
 | |
|   POINTER_PEN_INFO penInfo;
 | |
|   GetPointerPenInfo(aInfo->pointerId, &penInfo);
 | |
|   aInfo->tiltX = penInfo.tiltX;
 | |
|   aInfo->tiltY = penInfo.tiltY;
 | |
|   // Windows defines the pen pressure is normalized to a range between 0 and
 | |
|   // 1024. Convert it to float.
 | |
|   aInfo->mPressure = penInfo.pressure ? (float)penInfo.pressure / 1024 : 0;
 | |
| }
 | 
