Bug 1345398 - Fire WidgetMouseEvent by handling pen generated mouse messages to get Windows native dnd supports. r=jimm

Due to Windows doesn't support dnd in the pen message handler, we can't handle and consume WM_POINTER* to fire WidgetMouseEvent. On the other hand, we can't get some pen related attributes from Windows mouse messages. This patch gets and caches the attributes by handling WM_POINTER* but not fire WidgetMouseEvent to support dnd and pen related attributes. When handling the subsequent Windows mouse messages, we use the cached attributes to fire WidgetMouseEvent. Considering we might need to use WM_POINTER* someday, use a preference to control the behavior.

MozReview-Commit-ID: 5E60KO1zo0W
This commit is contained in:
Stone Shih 2017-03-13 15:40:52 +08:00
Родитель 9672dfeb91
Коммит c2ff93f196
4 изменённых файлов: 135 добавлений и 19 удалений

Просмотреть файл

@ -4913,6 +4913,12 @@ pref("dom.w3c_pointer_events.enabled", true);
pref("dom.w3c_pointer_events.enabled", false);
#endif
// Control firing WidgetMouseEvent by handling Windows pointer messages or mouse
// messages.
#if defined(XP_WIN)
pref("dom.w3c_pointer_events.dispatch_by_pointer_messages", false);
#endif
// W3C pointer events draft
pref("dom.w3c_pointer_events.implicit_capture", false);

Просмотреть файл

@ -21,6 +21,7 @@ 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()
{
@ -29,6 +30,9 @@ WinPointerEvents::WinPointerEvents()
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;
}
}
@ -67,14 +71,17 @@ WinPointerEvents::InitLibrary()
}
bool
WinPointerEvents::ShouldFireCompatibilityMouseEventsForPen(WPARAM aWParam)
WinPointerEvents::ShouldHandleWinPointerMessages(UINT aMsg, WPARAM aWParam)
{
MOZ_ASSERT(aMsg == WM_POINTERDOWN || aMsg == WM_POINTERUP ||
aMsg == WM_POINTERUPDATE || aMsg == WM_POINTERLEAVE);
if (!sLibraryHandle || !sPointerEventEnabled) {
// Firing mouse events by handling Windows WM_POINTER* when preference is on
// and the Windows platform supports PointerEvent related interfaces.
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)) {
@ -94,6 +101,14 @@ WinPointerEvents::GetPointerType(uint32_t aPointerId,
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)
@ -123,9 +138,83 @@ WinPointerEvents::ShouldEnableInkCollector()
}
bool
WinPointerEvents::ShouldRollupOnPointerEvent(WPARAM aWParam)
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 ShouldFireCompatibilityMouseEventsForPen(aWParam);
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() != nsIDOMMouseEvent::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;
}

Просмотреть файл

@ -104,6 +104,8 @@ class WinPointerInfo final : public mozilla::WidgetPointerHelper
public:
WinPointerInfo()
: WidgetPointerHelper()
, mPressure(0)
, mButtons(0)
{
}
@ -125,17 +127,23 @@ public:
explicit WinPointerEvents();
public:
bool ShouldFireCompatibilityMouseEventsForPen(WPARAM aWParam);
bool ShouldHandleWinPointerMessages(UINT aMsg, WPARAM aWParam);
uint32_t GetPointerId(WPARAM aWParam)
{
return GET_POINTERID_WPARAM(aWParam);
}
bool GetPointerType(uint32_t aPointerId, POINTER_INPUT_TYPE *aPointerType);
POINTER_INPUT_TYPE GetPointerType(uint32_t aPointerId);
bool GetPointerInfo(uint32_t aPointerId, POINTER_INFO *aPointerInfo);
bool GetPointerPenInfo(uint32_t aPointerId, POINTER_PEN_INFO *aPenInfo);
bool ShouldEnableInkCollector();
bool ShouldRollupOnPointerEvent(WPARAM aWParam);
bool ShouldRollupOnPointerEvent(UINT aMsg, WPARAM aWParam);
bool ShouldFirePointerEventByWinPointerMessages();
WinPointerInfo* GetCachedPointerInfo(UINT aMsg, WPARAM aWParam);
void ConvertAndCachePointerInfo(UINT aMsg, WPARAM aWParam);
void ConvertAndCachePointerInfo(WPARAM aWParam, WinPointerInfo* aInfo);
private:
// Function prototypes
typedef BOOL (WINAPI* GetPointerTypePtr)(uint32_t aPointerId,
@ -150,10 +158,14 @@ private:
static HMODULE sLibraryHandle;
static const wchar_t kPointerLibraryName[];
static bool sPointerEventEnabled;
static bool WinPointerEvents::sFirePointerEventsByWinPointerMessages;
// Static function pointers
static GetPointerTypePtr getPointerType;
static GetPointerInfoPtr getPointerInfo;
static GetPointerPenInfoPtr getPointerPenInfo;
WinPointerInfo mPenPointerDownInfo;
WinPointerInfo mPenPointerUpInfo;
WinPointerInfo mPenPointerUpdateInfo;
};
#endif // #ifndef WinPointerEvents_h__

Просмотреть файл

@ -5439,7 +5439,8 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseMove, wParam, lParam,
false, WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE());
MOUSE_INPUT_SOURCE(),
mPointerEvents.GetCachedPointerInfo(msg, wParam));
if (userMovedMouse) {
DispatchPendingEvents();
}
@ -5457,7 +5458,8 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
{
result = DispatchMouseEvent(eMouseDown, wParam, lParam,
false, WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE());
MOUSE_INPUT_SOURCE(),
mPointerEvents.GetCachedPointerInfo(msg, wParam));
DispatchPendingEvents();
}
break;
@ -5466,7 +5468,8 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
{
result = DispatchMouseEvent(eMouseUp, wParam, lParam,
false, WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE());
MOUSE_INPUT_SOURCE(),
mPointerEvents.GetCachedPointerInfo(msg, wParam));
DispatchPendingEvents();
}
break;
@ -5617,7 +5620,8 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseDown, wParam,
lParam, false,
WidgetMouseEvent::eRightButton,
MOUSE_INPUT_SOURCE());
MOUSE_INPUT_SOURCE(),
mPointerEvents.GetCachedPointerInfo(msg, wParam));
DispatchPendingEvents();
break;
@ -5625,7 +5629,8 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseUp, wParam,
lParam, false,
WidgetMouseEvent::eRightButton,
MOUSE_INPUT_SOURCE());
MOUSE_INPUT_SOURCE(),
mPointerEvents.GetCachedPointerInfo(msg, wParam));
DispatchPendingEvents();
break;
@ -7781,7 +7786,7 @@ nsWindow::DealWithPopups(HWND aWnd, UINT aMessage,
case WM_POINTERDOWN:
{
WinPointerEvents pointerEvents;
if (!pointerEvents.ShouldRollupOnPointerEvent(aWParam)) {
if (!pointerEvents.ShouldRollupOnPointerEvent(nativeMessage, aWParam)) {
return false;
}
if (!GetPopupsToRollup(rollupListener, &popupsToRollup)) {
@ -8197,14 +8202,18 @@ nsWindow::OnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
bool nsWindow::OnPointerEvents(UINT msg, WPARAM aWParam, LPARAM aLParam)
{
if (!mPointerEvents.ShouldFireCompatibilityMouseEventsForPen(aWParam)) {
// 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. So we fire Gecko WidgetMouseEvent when handling
// WM_POINTER* and consume WM_POINTER* to stop Windows fire WM_*BUTTONDOWN.
if (!mPointerEvents.ShouldHandleWinPointerMessages(msg, aWParam)) {
return false;
}
if (!mPointerEvents.ShouldFirePointerEventByWinPointerMessages()) {
// We have to handle WM_POINTER* to fetch and cache pen related information
// and fire WidgetMouseEvent with the cached information the WM_*BUTTONDOWN
// handler. This is because Windows doesn't support ::DoDragDrop in the touch
// or pen message handlers.
mPointerEvents.ConvertAndCachePointerInfo(msg, aWParam);
// Don't consume the Windows WM_POINTER* messages
return false;
}
// When dispatching mouse events with pen, there may be some
// WM_POINTERUPDATE messages between WM_POINTERDOWN and WM_POINTERUP with
// small movements. Those events will reset sLastMousePoint and reset