Bug 1031362 Part1: Dispatching mouse events by handling pen generated WM_POINTER* messages. r=jimm,smaug

This commit is contained in:
Stone Shih
2016-11-20 10:24:46 +08:00
parent 73244df343
commit c5455f27c3
6 changed files with 440 additions and 31 deletions

View File

@@ -3398,7 +3398,7 @@ nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen)
sCurrentWindow->DispatchMouseEvent(eMouseEnterIntoWidget,
sMouseExitwParam, pos, false,
WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
}
return NS_OK;
@@ -4132,7 +4132,7 @@ bool
nsWindow::DispatchMouseEvent(EventMessage aEventMessage, WPARAM wParam,
LPARAM lParam, bool aIsContextMenuKey,
int16_t aButton, uint16_t aInputSource,
uint16_t aPointerId)
WinPointerInfo* aPointerInfo)
{
bool result = false;
@@ -4169,6 +4169,9 @@ nsWindow::DispatchMouseEvent(EventMessage aEventMessage, WPARAM wParam,
}
}
uint32_t pointerId = aPointerInfo ? aPointerInfo->pointerId :
MOUSE_POINTERID();
// Since it is unclear whether a user will use the digitizer,
// Postpone initialization until first PEN message will be found.
if (nsIDOMMouseEvent::MOZ_SOURCE_PEN == aInputSource
@@ -4177,7 +4180,7 @@ nsWindow::DispatchMouseEvent(EventMessage aEventMessage, WPARAM wParam,
// Currently this scheme is used only when pointer events is enabled.
&& gfxPrefs::PointerEventsEnabled()) {
InkCollector::sInkCollector->SetTarget(mWnd);
InkCollector::sInkCollector->SetPointerId(aPointerId);
InkCollector::sInkCollector->SetPointerId(pointerId);
}
switch (aEventMessage) {
@@ -4214,10 +4217,18 @@ nsWindow::DispatchMouseEvent(EventMessage aEventMessage, WPARAM wParam,
modifierKeyState.InitInputEvent(event);
event.button = aButton;
event.inputSource = aInputSource;
event.pointerId = aPointerId;
// If we get here the mouse events must be from non-touch sources, so
// convert it to pointer events as well
event.convertToPointer = true;
if (aPointerInfo) {
// Mouse events from Windows WM_POINTER*. Fill more information in
// WidgetMouseEvent.
event.AssignPointerHelperData(*aPointerInfo);
event.pressure = aPointerInfo->mPressure;
event.buttons = aPointerInfo->mButtons;
} else {
// If we get here the mouse events must be from non-touch sources, so
// convert it to pointer events as well
event.convertToPointer = true;
event.pointerId = pointerId;
}
bool insideMovementThreshold = (DeprecatedAbs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) &&
(DeprecatedAbs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK));
@@ -4366,7 +4377,7 @@ nsWindow::DispatchMouseEvent(EventMessage aEventMessage, WPARAM wParam,
sCurrentWindow->DispatchMouseEvent(eMouseExitFromWidget,
wParam, pos, false,
WidgetMouseEvent::eLeftButton,
aInputSource, aPointerId);
aInputSource, aPointerInfo);
}
sCurrentWindow = this;
if (!mInDtor) {
@@ -4374,7 +4385,7 @@ nsWindow::DispatchMouseEvent(EventMessage aEventMessage, WPARAM wParam,
sCurrentWindow->DispatchMouseEvent(eMouseEnterIntoWidget,
wParam, pos, false,
WidgetMouseEvent::eLeftButton,
aInputSource, aPointerId);
aInputSource, aPointerInfo);
}
}
}
@@ -5285,7 +5296,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseMove, wParam, lParam,
false, WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
if (userMovedMouse) {
DispatchPendingEvents();
}
@@ -5303,7 +5314,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
{
result = DispatchMouseEvent(eMouseDown, wParam, lParam,
false, WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
}
break;
@@ -5312,7 +5323,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
{
result = DispatchMouseEvent(eMouseUp, wParam, lParam,
false, WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
}
break;
@@ -5333,7 +5344,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
LPARAM pos = lParamToClient(::GetMessagePos());
DispatchMouseEvent(eMouseExitFromWidget, mouseState, pos, false,
WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
}
break;
@@ -5342,9 +5353,11 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
LPARAM pos = lParamToClient(::GetMessagePos());
uint16_t pointerId = InkCollector::sInkCollector->GetPointerId();
if (pointerId != 0) {
WinPointerInfo pointerInfo;
pointerInfo.pointerId = pointerId;
DispatchMouseEvent(eMouseExitFromWidget, wParam, pos, false,
WidgetMouseEvent::eLeftButton,
nsIDOMMouseEvent::MOZ_SOURCE_PEN, pointerId);
nsIDOMMouseEvent::MOZ_SOURCE_PEN, &pointerInfo);
InkCollector::sInkCollector->ClearTarget();
InkCollector::sInkCollector->ClearPointerId();
}
@@ -5380,7 +5393,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
contextMenukey ?
WidgetMouseEvent::eLeftButton :
WidgetMouseEvent::eRightButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
if (lParam != -1 && !result && mCustomNonClient &&
mDraggableRegion.Contains(GET_X_LPARAM(pos), GET_Y_LPARAM(pos))) {
// Blank area hit, throw up the system menu.
@@ -5390,11 +5403,19 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
}
break;
case WM_POINTERLEAVE:
case WM_POINTERDOWN:
case WM_POINTERUP:
case WM_POINTERUPDATE:
result = OnPointerEvents(msg, wParam, lParam);
DispatchPendingEvents();
break;
case WM_LBUTTONDBLCLK:
result = DispatchMouseEvent(eMouseDoubleClick, wParam,
lParam, false,
WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5402,7 +5423,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseDown, wParam,
lParam, false,
WidgetMouseEvent::eMiddleButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5410,7 +5431,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseUp, wParam,
lParam, false,
WidgetMouseEvent::eMiddleButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5418,7 +5439,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseDoubleClick, wParam,
lParam, false,
WidgetMouseEvent::eMiddleButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5426,7 +5447,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseDown, 0,
lParamToClient(lParam), false,
WidgetMouseEvent::eMiddleButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5434,7 +5455,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseUp, 0,
lParamToClient(lParam), false,
WidgetMouseEvent::eMiddleButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5442,7 +5463,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseDoubleClick, 0,
lParamToClient(lParam), false,
WidgetMouseEvent::eMiddleButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5450,7 +5471,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseDown, wParam,
lParam, false,
WidgetMouseEvent::eRightButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5458,7 +5479,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseUp, wParam,
lParam, false,
WidgetMouseEvent::eRightButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5466,7 +5487,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseDoubleClick, wParam,
lParam, false,
WidgetMouseEvent::eRightButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5474,7 +5495,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseDown, 0,
lParamToClient(lParam), false,
WidgetMouseEvent::eRightButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5482,7 +5503,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseUp, 0,
lParamToClient(lParam), false,
WidgetMouseEvent::eRightButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5490,7 +5511,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = DispatchMouseEvent(eMouseDoubleClick, 0,
lParamToClient(lParam), false,
WidgetMouseEvent::eRightButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -5571,11 +5592,11 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
case WM_NCLBUTTONDBLCLK:
DispatchMouseEvent(eMouseDoubleClick, 0, lParamToClient(lParam),
false, WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
result =
DispatchMouseEvent(eMouseUp, 0, lParamToClient(lParam),
false, WidgetMouseEvent::eLeftButton,
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
MOUSE_INPUT_SOURCE());
DispatchPendingEvents();
break;
@@ -8023,6 +8044,107 @@ 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.
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
// sLastClickCount. To prevent that, we keep the last pen down position
// and compare it with the subsequent WM_POINTERUPDATE. If the movement is
// smaller than GetSystemMetrics(SM_CXDRAG), then we suppress firing
// eMouseMove for WM_POINTERUPDATE.
static POINT sLastPointerDownPoint = {0};
// We don't support chorded buttons for pen. Keep the button at
// WM_POINTERDOWN.
static WidgetMouseEvent::buttonType sLastPenDownButton =
WidgetMouseEvent::eLeftButton;
static bool sPointerDown = false;
EventMessage message;
WidgetMouseEvent::buttonType button = WidgetMouseEvent::eLeftButton;
switch (msg) {
case WM_POINTERDOWN:
{
LayoutDeviceIntPoint eventPoint(GET_X_LPARAM(aLParam),
GET_Y_LPARAM(aLParam));
sLastPointerDownPoint.x = eventPoint.x;
sLastPointerDownPoint.y = eventPoint.y;
message = eMouseDown;
button = IS_POINTER_SECONDBUTTON_WPARAM(aWParam) ?
WidgetMouseEvent::eRightButton : WidgetMouseEvent::eLeftButton;
sLastPenDownButton = button;
sPointerDown = true;
}
break;
case WM_POINTERUP:
message = eMouseUp;
MOZ_ASSERT(sPointerDown, "receive WM_POINTERUP w/o WM_POINTERDOWN");
button = sPointerDown ? sLastPenDownButton : WidgetMouseEvent::eLeftButton;
sPointerDown = false;
break;
case WM_POINTERUPDATE:
message = eMouseMove;
if (sPointerDown) {
LayoutDeviceIntPoint eventPoint(GET_X_LPARAM(aLParam),
GET_Y_LPARAM(aLParam));
int32_t movementX = sLastPointerDownPoint.x > eventPoint.x ?
sLastPointerDownPoint.x - eventPoint.x :
eventPoint.x - sLastPointerDownPoint.x;
int32_t movementY = sLastPointerDownPoint.y > eventPoint.y ?
sLastPointerDownPoint.y - eventPoint.y :
eventPoint.y - sLastPointerDownPoint.y;
bool insideMovementThreshold =
movementX < (int32_t)::GetSystemMetrics(SM_CXDRAG) &&
movementY < (int32_t)::GetSystemMetrics(SM_CYDRAG);
if (insideMovementThreshold) {
// Suppress firing eMouseMove for WM_POINTERUPDATE if the movement
// from last WM_POINTERDOWN is smaller than SM_CXDRAG / SM_CYDRAG
return false;
}
button = sLastPenDownButton;
}
break;
case WM_POINTERLEAVE:
message = eMouseExitFromWidget;
break;
default:
return false;
}
uint32_t pointerId = mPointerEvents.GetPointerId(aWParam);
POINTER_PEN_INFO penInfo;
mPointerEvents.GetPointerPenInfo(pointerId, &penInfo);
// Windows defines the pen pressure is normalized to a range between 0 and
// 1024. Convert it to float.
float pressure = penInfo.pressure ? (float)penInfo.pressure / 1024 : 0;
int16_t buttons =
sPointerDown ? button == WidgetMouseEvent::eLeftButton ?
WidgetMouseEvent::eLeftButtonFlag :
WidgetMouseEvent::eRightButtonFlag :
WidgetMouseEvent::eNoButtonFlag;
WinPointerInfo pointerInfo(pointerId, penInfo.tiltX, penInfo.tiltY, pressure,
buttons);
// The aLParam of WM_POINTER* is the screen location. Convert it to client
// location
LPARAM newLParam = lParamToClient(aLParam);
DispatchMouseEvent(message, aWParam, newLParam, false, button,
nsIDOMMouseEvent::MOZ_SOURCE_PEN, &pointerInfo);
// Consume WM_POINTER* to stop Windows fires WM_*BUTTONDOWN / WM_*BUTTONUP
// WM_MOUSEMOVE.
return true;
}
/**************************************************************
**************************************************************
**