зеркало из https://github.com/mozilla/gecko-dev.git
201 строка
6.9 KiB
C++
201 строка
6.9 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;
|
|
}
|