summaryrefslogtreecommitdiffstats
path: root/widget/windows/WinPointerEvents.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/windows/WinPointerEvents.cpp')
-rw-r--r--widget/windows/WinPointerEvents.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/widget/windows/WinPointerEvents.cpp b/widget/windows/WinPointerEvents.cpp
new file mode 100644
index 0000000000..62d2aa0515
--- /dev/null
+++ b/widget/windows/WinPointerEvents.cpp
@@ -0,0 +1,190 @@
+/* -*- 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/StaticPrefs_dom.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;
+
+WinPointerEvents::WinPointerEvents() { InitLibrary(); }
+
+/* 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 || !StaticPrefs::dom_w3c_pointer_events_enabled()) {
+ 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 && StaticPrefs::dom_w3c_pointer_events_enabled());
+ return StaticPrefs::dom_w3c_pointer_events_dispatch_by_pointer_messages();
+}
+
+WinPointerInfo* WinPointerEvents::GetCachedPointerInfo(UINT aMsg,
+ WPARAM aWParam) {
+ if (!sLibraryHandle || !StaticPrefs::dom_w3c_pointer_events_enabled() ||
+ 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(
+ !StaticPrefs::dom_w3c_pointer_events_dispatch_by_pointer_messages());
+ // 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(
+ !StaticPrefs::dom_w3c_pointer_events_dispatch_by_pointer_messages());
+ 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;
+}