diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 18154a80a40..34c2c4c5b12 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -122,6 +122,7 @@ nsIDocument* nsEventStateManager::sMouseOverDocument = nullptr; nsWeakFrame nsEventStateManager::sLastDragOverFrame = nullptr; nsIntPoint nsEventStateManager::sLastRefPoint = nsIntPoint(0,0); nsIntPoint nsEventStateManager::sLastScreenPoint = nsIntPoint(0,0); +nsIntPoint nsEventStateManager::sSynthCenteringPoint = nsIntPoint(-1,-1); nsIntPoint nsEventStateManager::sLastClientPoint = nsIntPoint(0,0); bool nsEventStateManager::sIsPointerLocked = false; // Reference to the pointer locked element. @@ -4132,19 +4133,36 @@ nsEventStateManager::GenerateMouseEnterExit(nsGUIEvent* aEvent) switch(aEvent->message) { case NS_MOUSE_MOVE: { + // Mouse movement is reported on the MouseEvent.movement{X,Y} fields. + // Movement is calculated in nsDOMUIEvent::GetMovementPoint() as: + // previous_mousemove_refPoint - current_mousemove_refPoint. if (sIsPointerLocked && aEvent->widget) { - // Perform mouse lock by recentering the mouse directly, and storing - // the refpoints so movement deltas can be calculated. + // The pointer is locked. If the pointer is not located at the center of + // the window, dispatch a synthetic mousemove to return the pointer there. + // Doing this between "real" pointer moves gives the impression that the + // (locked) pointer can continue moving and won't stop at the screen + // boundary. We cancel the synthetic event so that we don't end up + // dispatching the centering move event to content. nsIntPoint center = GetWindowInnerRectCenter(mDocument->GetWindow(), aEvent->widget, mPresContext); aEvent->lastRefPoint = center; if (aEvent->refPoint != center) { - // This mouse move doesn't finish at the center of the widget, - // dispatch a synthetic mouse move to return the mouse back to - // the center. + // Mouse move doesn't finish at the center of the window. Dispatch a + // synthetic native mouse event to move the pointer back to the center + // of the window, to faciliate more movement. But first, record that + // we've dispatched a synthetic mouse movement, so we can cancel it + // in the other branch here. + sSynthCenteringPoint = center; aEvent->widget->SynthesizeNativeMouseMove( center + aEvent->widget->WidgetToScreenOffset()); + } else if (aEvent->refPoint == sSynthCenteringPoint) { + // This is the "synthetic native" event we dispatched to re-center the + // pointer. Cancel it so we don't expose the centering move to content. + aEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH; + // Clear sSynthCenteringPoint so we don't cancel other events + // targeted at the center. + sSynthCenteringPoint = nsIntPoint(-1,-1); } } else { aEvent->lastRefPoint = sLastRefPoint; diff --git a/content/events/src/nsEventStateManager.h b/content/events/src/nsEventStateManager.h index 5482fb07ce5..e8bc1d8d492 100644 --- a/content/events/src/nsEventStateManager.h +++ b/content/events/src/nsEventStateManager.h @@ -697,6 +697,13 @@ private: // after unlocking. nsIntPoint mPreLockPoint; + // Stores the refPoint of the last synthetic mouse move we dispatched + // to re-center the mouse when we were pointer locked. If this is (-1,-1) it + // means we've not recently dispatched a centering event. We use this to + // detect when we receive the synth event, so we can cancel and not send it + // to content. + static nsIntPoint sSynthCenteringPoint; + nsWeakFrame mCurrentTarget; nsCOMPtr mCurrentTargetContent; nsWeakFrame mLastMouseOverFrame;