Bug 1691622 - part 9: Make nsIWidget::SynthesizeNativeMouseEvent take an XP button ID and abstract message value r=smaug,geckoview-reviewers,agi,m_kato

Currently, it takes a raw native message value, but it makes JS content too
complicated.  And on Linux, it cannot synthesize non-primary button events
because GDK has only button press and release messages which dont' include
mouse button information.

For solving these problems, this patch creates a new abstract native message
as `nsIWidget::NativeMouseMessage` and makes each widget converts it to
a platform native message.

Additionally, this patch adds an argument to make it possible its callers
to specify pressing or releasing mouse button with a DOM mouse button value.

Note that the following patch adds new argument to
`synthesizeNativeEventMouse*` for mochitests and which will be tested by
new tests.

Differential Revision: https://phabricator.services.mozilla.com/D105763
This commit is contained in:
Masayuki Nakano 2021-02-24 01:27:10 +00:00
parent e675c8343f
commit ef2253b4a1
31 changed files with 405 additions and 344 deletions

View File

@ -935,9 +935,9 @@ struct RoleDescrComparator {
LayoutDeviceIntPoint(geckoRect.X() + (geckoRect.Width() / 2),
geckoRect.Y() + (geckoRect.Height() / 2));
nsIWidget* widget = [objOrView widget];
widget->SynthesizeNativeMouseEvent(p, NSEventTypeRightMouseDown,
nsIWidget::Modifiers::NO_MODIFIERS,
nullptr);
widget->SynthesizeNativeMouseEvent(
p, nsIWidget::NativeMouseMessage::ButtonDown, MouseButton::eSecondary,
nsIWidget::Modifiers::NO_MODIFIERS, nullptr);
}
- (void)moxPerformPress {

View File

@ -152,60 +152,6 @@ for (const mvcontent of META_VIEWPORT_CONTENTS) {
}
}
// Lift a set of functions out of apz_test_native_event_utils.js
// to use for sending native mouse events. Bug 1126772 would instead
// allow us to use a method in EventUtils.
function getPlatform() {
if (content.navigator.platform.indexOf("Win") == 0) {
return "windows";
}
if (content.navigator.platform.indexOf("Mac") == 0) {
return "mac";
}
// Check for Android before Linux
if (content.navigator.appVersion.includes("Android")) {
return "android";
}
if (content.navigator.platform.indexOf("Linux") == 0) {
return "linux";
}
return "unknown";
}
function nativeMouseDownEventMsg() {
switch (getPlatform()) {
case "windows":
return 2; // MOUSEEVENTF_LEFTDOWN
case "mac":
return 1; // NSEventTypeLeftMouseDown
case "linux":
return 4; // GDK_BUTTON_PRESS
case "android":
return 5; // ACTION_POINTER_DOWN
}
throw new Error(
"Native mouse-down events not supported on platform " +
getPlatform()
);
}
function nativeMouseUpEventMsg() {
switch (getPlatform()) {
case "windows":
return 4; // MOUSEEVENTF_LEFTUP
case "mac":
return 2; // NSEventTypeLeftMouseUp
case "linux":
return 7; // GDK_BUTTON_RELEASE
case "android":
return 6; // ACTION_POINTER_UP
}
throw new Error(
"Native mouse-up events not supported on platform " +
getPlatform()
);
}
// This function takes screen coordinates in css pixels.
function synthesizeNativeMouseClick(win, screenX, screenY) {
const utils = win.windowUtils;
@ -215,14 +161,16 @@ for (const mvcontent of META_VIEWPORT_CONTENTS) {
utils.sendNativeMouseEvent(
screenX * scale,
screenY * scale,
nativeMouseDownEventMsg(),
utils.NATIVE_MOUSE_MESSAGE_BUTTON_DOWN,
0,
0,
win.document.documentElement,
() => {
utils.sendNativeMouseEvent(
screenX * scale,
screenY * scale,
nativeMouseUpEventMsg(),
utils.NATIVE_MOUSE_MESSAGE_BUTTON_UP,
0,
0,
win.document.documentElement,
resolve

View File

@ -1029,21 +1029,45 @@ nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout,
NS_IMETHODIMP
nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX, int32_t aScreenY,
int32_t aNativeMessage,
uint32_t aNativeMessage, int16_t aButton,
uint32_t aModifierFlags,
Element* aElement,
Element* aElementOnWidget,
nsIObserver* aObserver) {
// get the widget to send the event to
nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement);
if (!widget) return NS_ERROR_FAILURE;
nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElementOnWidget);
if (!widget) {
return NS_ERROR_FAILURE;
}
nsIWidget::NativeMouseMessage message;
switch (aNativeMessage) {
case NATIVE_MOUSE_MESSAGE_BUTTON_DOWN:
message = nsIWidget::NativeMouseMessage::ButtonDown;
break;
case NATIVE_MOUSE_MESSAGE_BUTTON_UP:
message = nsIWidget::NativeMouseMessage::ButtonUp;
break;
case NATIVE_MOUSE_MESSAGE_MOVE:
message = nsIWidget::NativeMouseMessage::Move;
break;
case NATIVE_MOUSE_MESSAGE_ENTER_WINDOW:
message = nsIWidget::NativeMouseMessage::EnterWindow;
break;
case NATIVE_MOUSE_MESSAGE_LEAVE_WINDOW:
message = nsIWidget::NativeMouseMessage::LeaveWindow;
break;
default:
return NS_ERROR_INVALID_ARG;
}
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<LayoutDeviceIntPoint, int32_t, nsIWidget::Modifiers,
nsIObserver*>(
NewRunnableMethod<LayoutDeviceIntPoint, nsIWidget::NativeMouseMessage,
MouseButton, nsIWidget::Modifiers, nsIObserver*>(
"nsIWidget::SynthesizeNativeMouseEvent", widget,
&nsIWidget::SynthesizeNativeMouseEvent,
LayoutDeviceIntPoint(aScreenX, aScreenY), aNativeMessage,
GetWidgetModifiers(aModifierFlags), aObserver)));
LayoutDeviceIntPoint(aScreenX, aScreenY), message,
static_cast<MouseButton>(aButton), GetWidgetModifiers(aModifierFlags),
aObserver)));
return NS_OK;
}

View File

@ -525,15 +525,27 @@ interface nsIDOMWindowUtils : nsISupports {
* Cannot be accessed from unprivileged context (not content-accessible)
* Will throw a DOM security error if called without chrome privileges.
*
* NOTE: The synthesized native event will be fired asynchronously, and upon
* completion the observer, if provided, will be notified with a "mouseevent"
* topic.
* @param aScreenX X offset in the screen in device pixels.
* @param aScreenY Y offset in the screen in derive pixels.
* @param aNativeMessage One of NATIVE_MOUSE_MESSAGE_*
* @param aButton Same as `MouseEvent.button` value.
* @param aModifierFlags See nsIWidget's native modifier flags.
* @param aElementOnWidget An element which is on a widget.
* @param aObserver The synthesized native event will be fired
* asynchronously, and upon completion the observer, if
* provided, will be notified with a "mouseevent" topic.
*/
const unsigned long NATIVE_MOUSE_MESSAGE_BUTTON_DOWN = 0x00000001;
const unsigned long NATIVE_MOUSE_MESSAGE_BUTTON_UP = 0x00000002;
const unsigned long NATIVE_MOUSE_MESSAGE_MOVE = 0x00000003;
const unsigned long NATIVE_MOUSE_MESSAGE_ENTER_WINDOW = 0x00000004;
const unsigned long NATIVE_MOUSE_MESSAGE_LEAVE_WINDOW = 0x00000005;
void sendNativeMouseEvent(in long aScreenX,
in long aScreenY,
in long aNativeMessage,
in unsigned long aNativeMessage,
in short aButton,
in unsigned long aModifierFlags,
in Element aElement,
in Element aElementOnWidget,
[optional] in nsIObserver aObserver);
/**

View File

@ -1780,12 +1780,14 @@ mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeKeyEvent(
mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseEvent(
const LayoutDeviceIntPoint& aPoint, const uint32_t& aNativeMessage,
const uint32_t& aModifierFlags, const uint64_t& aObserverId) {
const int16_t& aButton, const uint32_t& aModifierFlags,
const uint64_t& aObserverId) {
AutoSynthesizedEventResponder responder(this, aObserverId, "mouseevent");
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SynthesizeNativeMouseEvent(
aPoint, aNativeMessage,
aPoint, static_cast<nsIWidget::NativeMouseMessage>(aNativeMessage),
static_cast<mozilla::MouseButton>(aButton),
static_cast<nsIWidget::Modifiers>(aModifierFlags),
responder.GetObserver());
}

View File

@ -516,7 +516,8 @@ class BrowserParent final : public PBrowserParent,
mozilla::ipc::IPCResult RecvSynthesizeNativeMouseEvent(
const LayoutDeviceIntPoint& aPoint, const uint32_t& aNativeMessage,
const uint32_t& aModifierFlags, const uint64_t& aObserverId);
const int16_t& aButton, const uint32_t& aModifierFlags,
const uint64_t& aObserverId);
mozilla::ipc::IPCResult RecvSynthesizeNativeMouseMove(
const LayoutDeviceIntPoint& aPoint, const uint64_t& aObserverId);

View File

@ -507,6 +507,7 @@ parent:
uint64_t aObserverId);
async SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
int16_t aButton,
uint32_t aModifierFlags,
uint64_t aObserverId);
async SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,

View File

@ -100,54 +100,6 @@ function nativeScrollUnits(aTarget, aDimen) {
return aDimen;
}
function nativeMouseDownEventMsg() {
switch (getPlatform()) {
case "windows":
return 2; // MOUSEEVENTF_LEFTDOWN
case "mac":
return 1; // NSEventTypeLeftMouseDown
case "linux":
return 4; // GDK_BUTTON_PRESS
case "android":
return 5; // ACTION_POINTER_DOWN
}
throw new Error(
"Native mouse-down events not supported on platform " + getPlatform()
);
}
function nativeMouseMoveEventMsg() {
switch (getPlatform()) {
case "windows":
return 1; // MOUSEEVENTF_MOVE
case "mac":
return 5; // NSEventTypeMouseMoved
case "linux":
return 3; // GDK_MOTION_NOTIFY
case "android":
return 7; // ACTION_HOVER_MOVE
}
throw new Error(
"Native mouse-move events not supported on platform " + getPlatform()
);
}
function nativeMouseUpEventMsg() {
switch (getPlatform()) {
case "windows":
return 4; // MOUSEEVENTF_LEFTUP
case "mac":
return 2; // NSEventTypeLeftMouseUp
case "linux":
return 7; // GDK_BUTTON_RELEASE
case "android":
return 6; // ACTION_POINTER_UP
}
throw new Error(
"Native mouse-up events not supported on platform " + getPlatform()
);
}
function parseNativeModifiers(aModifiers, aWindow = window) {
let modifiers = 0;
if (aModifiers.capsLockKey) {
@ -794,14 +746,16 @@ function synthesizeNativeMouseEventWithAPZ(aParams, aObserver = null) {
utils.sendNativeMouseEvent(
pt.x,
pt.y,
nativeMouseDownEventMsg(),
utils.NATIVE_MOUSE_MESSAGE_BUTTON_DOWN,
0,
modifierFlags,
element,
function() {
utils.sendNativeMouseEvent(
pt.x,
pt.y,
nativeMouseUpEventMsg(),
utils.NATIVE_MOUSE_MESSAGE_BUTTON_UP,
0,
modifierFlags,
element,
aObserver
@ -817,15 +771,16 @@ function synthesizeNativeMouseEventWithAPZ(aParams, aObserver = null) {
(() => {
switch (type) {
case "mousedown":
return nativeMouseDownEventMsg();
return utils.NATIVE_MOUSE_MESSAGE_BUTTON_DOWN;
case "mouseup":
return nativeMouseUpEventMsg();
return utils.NATIVE_MOUSE_MESSAGE_BUTTON_UP;
case "mousemove":
return nativeMouseMoveEventMsg();
return utils.NATIVE_MOUSE_MESSAGE_MOVE;
default:
throw Error(`Invalid type is specified: ${type}`);
}
})(),
0,
modifierFlags,
element,
aObserver

View File

@ -23,14 +23,16 @@ function synthesizeNativeMouseClick(aWin, aScreenX, aScreenY) {
utils.sendNativeMouseEvent(
aScreenX * scale,
aScreenY * scale,
nativeMouseDownEventMsg(),
utils.NATIVE_MOUSE_MESSAGE_BUTTON_DOWN,
0,
0,
aWin.document.documentElement,
() => {
utils.sendNativeMouseEvent(
aScreenX * scale,
aScreenY * scale,
nativeMouseUpEventMsg(),
utils.NATIVE_MOUSE_MESSAGE_BUTTON_UP,
0,
0,
aWin.document.documentElement
);

View File

@ -51,10 +51,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=987230
SimpleTest.requestCompleteLog();
let platform = navigator.platform.toLowerCase();
let isWindows = platform.startsWith("win");
let mouseMove = isWindows ? 1 : 5;
function onMyPopupHidden(e) {
ok(true, "Popup hidden");
if (outerAnchor.id == "toolbarbutton-anchor") {
@ -73,7 +69,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=987230
info("Mousemove: " + outsideOfFrameX + ", " + outsideOfFrameY +
" (from innerscreen " + window.mozInnerScreenX + ", " + window.mozInnerScreenY +
" and rect width " + frameRect.width + " and scale " + scale + ")");
utils.sendNativeMouseEvent(outsideOfFrameX, outsideOfFrameY, mouseMove, 0, null);
utils.sendNativeMouseEvent(
outsideOfFrameX,
outsideOfFrameY,
utils.NATIVE_MOUSE_MESSAGE_MOVE,
0,
0,
null
);
SimpleTest.finish();
}
}

View File

@ -214,15 +214,15 @@ public class PanZoomController {
throw new IllegalArgumentException("Pointer ID reserved for mouse");
}
synthesizeNativePointer(InputDevice.SOURCE_TOUCHSCREEN, pointerId,
eventType, clientX, clientY, pressure, orientation);
eventType, clientX, clientY, pressure, orientation, 0);
}
@WrapForJNI(calledFrom = "ui")
private void synthesizeNativeMouseEvent(final int eventType, final int clientX,
final int clientY) {
final int clientY, final int button) {
synthesizeNativePointer(InputDevice.SOURCE_MOUSE,
PointerInfo.RESERVED_MOUSE_POINTER_ID,
eventType, clientX, clientY, 0, 0);
eventType, clientX, clientY, 0, 0, button);
}
@WrapForJNI(calledFrom = "ui")
@ -527,6 +527,7 @@ public class PanZoomController {
public int surfaceY;
public double pressure;
public int orientation;
public int buttonState;
public MotionEvent.PointerCoords getCoords() {
MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
@ -573,6 +574,15 @@ public class PanZoomController {
return count;
}
int getPointerButtonState(final int source) {
for (int i = 0; i < pointers.size(); i++) {
if (pointers.get(i).source == source) {
return pointers.get(i).buttonState;
}
}
return 0;
}
MotionEvent.PointerProperties[] getPointerProperties(final int source) {
MotionEvent.PointerProperties[] props =
new MotionEvent.PointerProperties[getPointerCount(source)];
@ -611,7 +621,8 @@ public class PanZoomController {
private void synthesizeNativePointer(final int source, final int pointerId,
final int originalEventType,
final int clientX, final int clientY,
final double pressure, final int orientation) {
final double pressure, final int orientation,
final int button) {
if (mPointerState == null) {
mPointerState = new SynthesizedEventState();
}
@ -677,6 +688,14 @@ public class PanZoomController {
info.surfaceY = surfaceY;
info.pressure = pressure;
info.orientation = orientation;
if (source == InputDevice.SOURCE_MOUSE) {
if (eventType == MotionEvent.ACTION_DOWN ||
eventType == MotionEvent.ACTION_MOVE) {
info.buttonState |= button;
} else if (eventType == MotionEvent.ACTION_UP) {
info.buttonState &= button;
}
}
// Dispatch the event
int action = 0;
@ -688,9 +707,6 @@ public class PanZoomController {
action &= MotionEvent.ACTION_POINTER_INDEX_MASK;
}
action |= (eventType & MotionEvent.ACTION_MASK);
boolean isButtonDown = (source == InputDevice.SOURCE_MOUSE) &&
(eventType == MotionEvent.ACTION_DOWN ||
eventType == MotionEvent.ACTION_MOVE);
final MotionEvent event = MotionEvent.obtain(
/*downTime*/ mPointerState.downTime,
/*eventTime*/ SystemClock.uptimeMillis(),
@ -699,7 +715,7 @@ public class PanZoomController {
/*pointerProperties*/ mPointerState.getPointerProperties(source),
/*pointerCoords*/ mPointerState.getPointerCoords(source),
/*metaState*/ 0,
/*buttonState*/ (isButtonDown ? MotionEvent.BUTTON_PRIMARY : 0),
/*buttonState*/ mPointerState.getPointerButtonState(source),
/*xPrecision*/ 0,
/*yPrecision*/ 0,
/*deviceId*/ 0,

View File

@ -155,54 +155,6 @@ function _EU_getPlatform() {
return "unknown";
}
function _EU_nativeMouseDownEventMsg() {
switch (_EU_getPlatform()) {
case "windows":
return 2; // MOUSEEVENTF_LEFTDOWN
case "mac":
return 1; // NSEventTypeLeftMouseDown
case "linux":
return 4; // GDK_BUTTON_PRESS
case "android":
return 5; // ACTION_POINTER_DOWN
}
throw new Error(
"Native mouse-down events not supported on platform " + _EU_getPlatform()
);
}
function _EU_nativeMouseMoveEventMsg() {
switch (_EU_getPlatform()) {
case "windows":
return 1; // MOUSEEVENTF_MOVE
case "mac":
return 5; // NSEventTypeMouseMoved
case "linux":
return 3; // GDK_MOTION_NOTIFY
case "android":
return 7; // ACTION_HOVER_MOVE
}
throw new Error(
"Native mouse-move events not supported on platform " + _EU_getPlatform()
);
}
function _EU_nativeMouseUpEventMsg() {
switch (_EU_getPlatform()) {
case "windows":
return 4; // MOUSEEVENTF_LEFTUP
case "mac":
return 2; // NSEventTypeLeftMouseUp
case "linux":
return 7; // GDK_BUTTON_RELEASE
case "android":
return 6; // ACTION_POINTER_UP
}
throw new Error(
"Native mouse-up events not supported on platform " + _EU_getPlatform()
);
}
/**
* Send a mouse event to the node aTarget (aTarget can be an id, or an
* actual node) . The "event" passed in to aEvent is just a JavaScript
@ -1120,14 +1072,16 @@ function synthesizeNativeMouseEvent(aParams, aCallback = null) {
utils.sendNativeMouseEvent(
x,
y,
_EU_nativeMouseDownEventMsg(),
utils.NATIVE_MOUSE_MESSAGE_BUTTON_DOWN,
0,
modifierFlags,
null,
function() {
utils.sendNativeMouseEvent(
x,
y,
_EU_nativeMouseUpEventMsg(),
utils.NATIVE_MOUSE_MESSAGE_BUTTON_UP,
0,
modifierFlags,
null,
observer
@ -1142,15 +1096,16 @@ function synthesizeNativeMouseEvent(aParams, aCallback = null) {
(() => {
switch (type) {
case "mousedown":
return _EU_nativeMouseDownEventMsg();
return utils.NATIVE_MOUSE_MESSAGE_BUTTON_DOWN;
case "mouseup":
return _EU_nativeMouseUpEventMsg();
return utils.NATIVE_MOUSE_MESSAGE_BUTTON_UP;
case "mousemove":
return _EU_nativeMouseMoveEventMsg();
return utils.NATIVE_MOUSE_MESSAGE_MOVE;
default:
throw Error(`Invalid type is specified: ${type}`);
}
})(),
0,
modifierFlags,
null,
observer

View File

@ -438,11 +438,13 @@ typedef nsTArray<OwningNonNull<dom::StaticRange>> OwningNonNullStaticRangeArray;
// FontRange.h
struct FontRange;
enum MouseButton {
enum MouseButton : int16_t {
eNotPressed = -1,
ePrimary = 0,
eMiddle = 1,
eSecondary = 2
eSecondary = 2,
eX1 = 3, // Typically, "back" button
eX2 = 4, // Typically, "forward" button
};
enum MouseButtonsFlag {

View File

@ -427,14 +427,16 @@ nsresult PuppetWidget::SynthesizeNativeKeyEvent(
}
nsresult PuppetWidget::SynthesizeNativeMouseEvent(
mozilla::LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) {
mozilla::LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) {
AutoObserverNotifier notifier(aObserver, "mouseevent");
if (!mBrowserChild) {
return NS_ERROR_FAILURE;
}
mBrowserChild->SendSynthesizeNativeMouseEvent(
aPoint, aNativeMessage, static_cast<uint32_t>(aModifierFlags),
aPoint, static_cast<uint32_t>(aNativeMessage),
static_cast<int16_t>(aButton), static_cast<uint32_t>(aModifierFlags),
notifier.SaveObserver());
return NS_OK;
}

View File

@ -252,8 +252,9 @@ class PuppetWidget : public nsBaseWidget,
uint32_t aModifierFlags, const nsAString& aCharacters,
const nsAString& aUnmodifiedCharacters, nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) override;
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseScrollEvent(

View File

@ -2439,30 +2439,8 @@ nsresult nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
}
nsresult nsWindow::SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) {
mozilla::widget::AutoObserverNotifier notifier(aObserver, "mouseevent");
MOZ_ASSERT(mNPZCSupport.IsAttached());
auto npzcSup(mNPZCSupport.Access());
MOZ_ASSERT(!!npzcSup);
const auto& npzc = npzcSup->GetJavaNPZC();
const auto& bounds = FindTopLevel()->mBounds;
aPoint.x -= bounds.x;
aPoint.y -= bounds.y;
// TODO (bug 1693237): Handle aModifierFlags.
DispatchToUiThread(
"nsWindow::SynthesizeNativeMouseEvent",
[npzc = java::PanZoomController::NativeProvider::GlobalRef(npzc),
aNativeMessage, aPoint] {
npzc->SynthesizeNativeMouseEvent(aNativeMessage, aPoint.x, aPoint.y);
});
return NS_OK;
}
nsresult nsWindow::SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) {
mozilla::widget::AutoObserverNotifier notifier(aObserver, "mouseevent");
@ -2475,16 +2453,65 @@ nsresult nsWindow::SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
aPoint.x -= bounds.x;
aPoint.y -= bounds.y;
int32_t nativeMessage;
switch (aNativeMessage) {
case NativeMouseMessage::ButtonDown:
nativeMessage = java::sdk::MotionEvent::ACTION_POINTER_DOWN;
break;
case NativeMouseMessage::ButtonUp:
nativeMessage = java::sdk::MotionEvent::ACTION_POINTER_UP;
break;
case NativeMouseMessage::Move:
nativeMessage = java::sdk::MotionEvent::ACTION_HOVER_MOVE;
break;
default:
MOZ_ASSERT_UNREACHABLE("Non supported mouse event on Android");
return NS_ERROR_INVALID_ARG;
}
int32_t button;
switch (aButton) {
case MouseButton::ePrimary:
button = java::sdk::MotionEvent::BUTTON_PRIMARY;
break;
case MouseButton::eMiddle:
button = java::sdk::MotionEvent::BUTTON_TERTIARY;
break;
case MouseButton::eSecondary:
button = java::sdk::MotionEvent::BUTTON_SECONDARY;
break;
case MouseButton::eX1:
button = java::sdk::MotionEvent::BUTTON_BACK;
break;
case MouseButton::eX2:
button = java::sdk::MotionEvent::BUTTON_FORWARD;
break;
default:
if (aNativeMessage != NativeMouseMessage::ButtonDown &&
aNativeMessage != NativeMouseMessage::ButtonUp) {
button = 0;
break;
}
return NS_ERROR_INVALID_ARG;
}
// TODO (bug 1693237): Handle aModifierFlags.
DispatchToUiThread(
"nsWindow::SynthesizeNativeMouseMove",
"nsWindow::SynthesizeNativeMouseEvent",
[npzc = java::PanZoomController::NativeProvider::GlobalRef(npzc),
aPoint] {
npzc->SynthesizeNativeMouseEvent(
java::sdk::MotionEvent::ACTION_HOVER_MOVE, aPoint.x, aPoint.y);
nativeMessage, aPoint, button] {
npzc->SynthesizeNativeMouseEvent(nativeMessage, aPoint.x, aPoint.y,
button);
});
return NS_OK;
}
nsresult nsWindow::SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver) {
return SynthesizeNativeMouseEvent(
aPoint, NativeMouseMessage::Move, MouseButton::eNotPressed,
nsIWidget::Modifiers::NO_MODIFIERS, aObserver);
}
bool nsWindow::WidgetPaintsBackground() {
return StaticPrefs::android_widget_paints_background();
}

View File

@ -201,7 +201,8 @@ class nsWindow final : public nsBaseWidget {
uint32_t aPointerOrientation,
nsIObserver* aObserver) override;
nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
NativeMouseMessage aNativeMessage,
mozilla::MouseButton aButton,
nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) override;
nsresult SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,

View File

@ -386,13 +386,16 @@ class nsChildView final : public nsBaseWidget {
const nsAString& aUnmodifiedCharacters,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
NativeMouseMessage aNativeMessage,
mozilla::MouseButton aButton,
nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver) override {
return SynthesizeNativeMouseEvent(aPoint, NSEventTypeMouseMoved,
return SynthesizeNativeMouseEvent(aPoint, NativeMouseMessage::Move,
mozilla::MouseButton::eNotPressed,
nsIWidget::Modifiers::NO_MODIFIERS, aObserver);
}
virtual nsresult SynthesizeNativeMouseScrollEvent(LayoutDeviceIntPoint aPoint,

View File

@ -868,7 +868,8 @@ nsresult nsChildView::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
}
nsresult nsChildView::SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
NativeMouseMessage aNativeMessage,
MouseButton aButton,
nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
@ -888,7 +889,49 @@ nsresult nsChildView::SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
NSEventModifierFlags modifierFlags =
nsCocoaUtils::ConvertWidgetModifiersToMacModifierFlags(aModifierFlags);
NSEvent* event = [NSEvent mouseEventWithType:(NSEventType)aNativeMessage
if (aButton == MouseButton::eX1 || aButton == MouseButton::eX2) {
// NSEvent has `buttonNumber` for `NSEventTypeOther*`. However, it seems that
// there is no way to specify it. Therefore, we should return error for now.
return NS_ERROR_INVALID_ARG;
}
NSEventType nativeEventType;
switch (aNativeMessage) {
case NativeMouseMessage::ButtonDown:
case NativeMouseMessage::ButtonUp: {
switch (aButton) {
case MouseButton::ePrimary:
nativeEventType = aNativeMessage == NativeMouseMessage::ButtonDown
? NSEventTypeLeftMouseDown
: NSEventTypeLeftMouseUp;
break;
case MouseButton::eMiddle:
nativeEventType = aNativeMessage == NativeMouseMessage::ButtonDown
? NSEventTypeOtherMouseDown
: NSEventTypeOtherMouseUp;
break;
case MouseButton::eSecondary:
nativeEventType = aNativeMessage == NativeMouseMessage::ButtonDown
? NSEventTypeRightMouseDown
: NSEventTypeRightMouseUp;
break;
default:
return NS_ERROR_INVALID_ARG;
}
break;
}
case NativeMouseMessage::Move:
nativeEventType = NSEventTypeMouseMoved;
break;
case NativeMouseMessage::EnterWindow:
nativeEventType = NSEventTypeMouseEntered;
break;
case NativeMouseMessage::LeaveWindow:
nativeEventType = NSEventTypeMouseExited;
break;
}
NSEvent* event = [NSEvent mouseEventWithType:nativeEventType
location:windowPoint
modifierFlags:modifierFlags
timestamp:[[NSProcessInfo processInfo] systemUptime]
@ -904,15 +947,15 @@ nsresult nsChildView::SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
// Tracking area events don't end up in their tracking areas when sent
// through [NSApp sendEvent:], so pass them directly to the right methods.
BaseWindow* window = (BaseWindow*)[mView window];
if (aNativeMessage == NSEventTypeMouseEntered) {
if (nativeEventType == NSEventTypeMouseEntered) {
[window mouseEntered:event];
return NS_OK;
}
if (aNativeMessage == NSEventTypeMouseExited) {
if (nativeEventType == NSEventTypeMouseExited) {
[window mouseExited:event];
return NS_OK;
}
if (aNativeMessage == NSEventTypeMouseMoved) {
if (nativeEventType == NSEventTypeMouseMoved) {
[window mouseMoved:event];
return NS_OK;
}

View File

@ -304,7 +304,9 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa {
virtual nsresult SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override;
virtual void SetDrawsInTitlebar(bool aState) override;
virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override;
virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
NativeMouseMessage aNativeMessage,
mozilla::MouseButton aButton,
nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseScrollEvent(LayoutDeviceIntPoint aPoint,

View File

@ -2442,16 +2442,18 @@ void nsCocoaWindow::SetDrawsInTitlebar(bool aState) {
}
NS_IMETHODIMP nsCocoaWindow::SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
NativeMouseMessage aNativeMessage,
MouseButton aButton,
nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
AutoObserverNotifier notifier(aObserver, "mouseevent");
if (mPopupContentView) {
return mPopupContentView->SynthesizeNativeMouseEvent(aPoint, aNativeMessage, aModifierFlags,
nullptr);
return mPopupContentView->SynthesizeNativeMouseEvent(aPoint, aNativeMessage, aButton,
aModifierFlags, nullptr);
}
return NS_OK;
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);

View File

@ -7869,8 +7869,9 @@ LayoutDeviceIntRect nsWindow::GdkRectToDevicePixels(GdkRectangle rect) {
}
nsresult nsWindow::SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) {
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) {
AutoObserverNotifier notifier(aObserver, "mouseevent");
if (!mGdkWindow) {
@ -7884,20 +7885,35 @@ nsresult nsWindow::SynthesizeNativeMouseEvent(
// done explicitly *before* requesting a button-press/release. You will also
// need to wait for the motion event to be dispatched before requesting a
// button-press/release event to maintain the desired event order.
if (aNativeMessage == GDK_BUTTON_PRESS ||
aNativeMessage == GDK_BUTTON_RELEASE) {
switch (aNativeMessage) {
case NativeMouseMessage::ButtonDown:
case NativeMouseMessage::ButtonUp: {
GdkEvent event;
memset(&event, 0, sizeof(GdkEvent));
event.type = (GdkEventType)aNativeMessage;
event.button.button = 1;
event.type = aNativeMessage == NativeMouseMessage::ButtonDown
? GDK_BUTTON_PRESS
: GDK_BUTTON_RELEASE;
switch (aButton) {
case MouseButton::ePrimary:
case MouseButton::eMiddle:
case MouseButton::eSecondary:
case MouseButton::eX1:
case MouseButton::eX2:
event.button.button = aButton + 1;
break;
default:
return NS_ERROR_INVALID_ARG;
}
event.button.state =
KeymapWrapper::ConvertWidgetModifierToGdkState(aModifierFlags);
event.button.window = mGdkWindow;
event.button.time = GDK_CURRENT_TIME;
// Get device for event source
GdkDeviceManager* device_manager = gdk_display_get_device_manager(display);
event.button.device = gdk_device_manager_get_client_pointer(device_manager);
GdkDeviceManager* device_manager =
gdk_display_get_device_manager(display);
event.button.device =
gdk_device_manager_get_client_pointer(device_manager);
event.button.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
event.button.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
@ -7907,17 +7923,24 @@ nsresult nsWindow::SynthesizeNativeMouseEvent(
event.button.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
gdk_event_put(&event);
} else {
// We don't support specific events other than button-press/release. In all
// other cases we'll synthesize a motion event that will be emitted by
return NS_OK;
}
case NativeMouseMessage::Move: {
// We don't support specific events other than button-press/release. In
// all other cases we'll synthesize a motion event that will be emitted by
// gdk_display_warp_pointer().
// XXX How to activate native modifier for the other events?
GdkScreen* screen = gdk_window_get_screen(mGdkWindow);
GdkPoint point = DevicePixelsToGdkPointRoundDown(aPoint);
gdk_display_warp_pointer(display, screen, point.x, point.y);
}
return NS_OK;
}
case NativeMouseMessage::EnterWindow:
case NativeMouseMessage::LeaveWindow:
MOZ_ASSERT_UNREACHABLE("Non supported mouse event on Linux");
return NS_ERROR_INVALID_ARG;
}
return NS_ERROR_UNEXPECTED;
}
nsresult nsWindow::SynthesizeNativeMouseScrollEvent(

View File

@ -342,14 +342,15 @@ class nsWindow final : public nsBaseWidget {
virtual void ReparentNativeWidget(nsIWidget* aNewParent) override;
virtual nsresult SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) override;
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
mozilla::MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver) override {
return SynthesizeNativeMouseEvent(aPoint, GDK_MOTION_NOTIFY,
nsIWidget::Modifiers::NO_MODIFIERS,
aObserver);
return SynthesizeNativeMouseEvent(
aPoint, NativeMouseMessage::Move, mozilla::MouseButton::eNotPressed,
nsIWidget::Modifiers::NO_MODIFIERS, aObserver);
}
virtual nsresult SynthesizeNativeMouseScrollEvent(

View File

@ -433,28 +433,30 @@ nsresult HeadlessWidget::DispatchEvent(WidgetGUIEvent* aEvent,
}
nsresult HeadlessWidget::SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) {
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) {
AutoObserverNotifier notifier(aObserver, "mouseevent");
EventMessage msg;
switch (aNativeMessage) {
case MOZ_HEADLESS_MOUSE_MOVE:
case NativeMouseMessage::Move:
msg = eMouseMove;
break;
case MOZ_HEADLESS_MOUSE_DOWN:
case NativeMouseMessage::ButtonDown:
msg = eMouseDown;
break;
case MOZ_HEADLESS_MOUSE_UP:
case NativeMouseMessage::ButtonUp:
msg = eMouseUp;
break;
default:
case NativeMouseMessage::EnterWindow:
case NativeMouseMessage::LeaveWindow:
MOZ_ASSERT_UNREACHABLE("Unsupported synthesized mouse event");
return NS_ERROR_UNEXPECTED;
}
WidgetMouseEvent event(true, msg, this, WidgetMouseEvent::eReal);
event.mRefPoint = aPoint - WidgetToScreenOffset();
if (msg == eMouseDown || msg == eMouseUp) {
event.mButton = MouseButton::ePrimary;
event.mButton = aButton;
}
if (msg == eMouseDown) {
event.mClickCount = 1;

View File

@ -14,38 +14,23 @@
// The various synthesized event values are hardcoded to avoid pulling
// in the platform specific widget code.
#if defined(MOZ_WIDGET_GTK)
# define MOZ_HEADLESS_MOUSE_MOVE 3 // GDK_MOTION_NOTIFY
# define MOZ_HEADLESS_MOUSE_DOWN 4 // GDK_BUTTON_PRESS
# define MOZ_HEADLESS_MOUSE_UP 7 // GDK_BUTTON_RELEASE
# define MOZ_HEADLESS_SCROLL_MULTIPLIER 3
# define MOZ_HEADLESS_SCROLL_DELTA_MODE \
mozilla::dom::WheelEvent_Binding::DOM_DELTA_LINE
#elif defined(XP_WIN)
# define MOZ_HEADLESS_MOUSE_MOVE 1 // MOUSEEVENTF_MOVE
# define MOZ_HEADLESS_MOUSE_DOWN 2 // MOUSEEVENTF_LEFTDOWN
# define MOZ_HEADLESS_MOUSE_UP 4 // MOUSEEVENTF_LEFTUP
# define MOZ_HEADLESS_SCROLL_MULTIPLIER \
.025 // default scroll lines (3) / WHEEL_DELTA (120)
# define MOZ_HEADLESS_SCROLL_DELTA_MODE \
mozilla::dom::WheelEvent_Binding::DOM_DELTA_LINE
#elif defined(XP_MACOSX)
# define MOZ_HEADLESS_MOUSE_MOVE 5 // NSEventTypeMouseMoved
# define MOZ_HEADLESS_MOUSE_DOWN 1 // NSEventTypeLeftMouseDown
# define MOZ_HEADLESS_MOUSE_UP 2 // NSEventTypeLeftMouseUp
# define MOZ_HEADLESS_SCROLL_MULTIPLIER 1
# define MOZ_HEADLESS_SCROLL_DELTA_MODE \
mozilla::dom::WheelEvent_Binding::DOM_DELTA_PIXEL
#elif defined(ANDROID)
# define MOZ_HEADLESS_MOUSE_MOVE 7 // ACTION_HOVER_MOVE
# define MOZ_HEADLESS_MOUSE_DOWN 5 // ACTION_POINTER_DOWN
# define MOZ_HEADLESS_MOUSE_UP 6 // ACTION_POINTER_UP
# define MOZ_HEADLESS_SCROLL_MULTIPLIER 1
# define MOZ_HEADLESS_SCROLL_DELTA_MODE \
mozilla::dom::WheelEvent_Binding::DOM_DELTA_LINE
#else
# define MOZ_HEADLESS_MOUSE_MOVE -1
# define MOZ_HEADLESS_MOUSE_DOWN -1
# define MOZ_HEADLESS_MOUSE_UP -1
# define MOZ_HEADLESS_SCROLL_MULTIPLIER -1
# define MOZ_HEADLESS_SCROLL_DELTA_MODE -1
#endif
@ -132,13 +117,14 @@ class HeadlessWidget : public nsBaseWidget {
nsEventStatus& aStatus) override;
virtual nsresult SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) override;
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
mozilla::MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver) override {
return SynthesizeNativeMouseEvent(aPoint, MOZ_HEADLESS_MOUSE_MOVE,
nsIWidget::Modifiers::NO_MODIFIERS,
aObserver);
return SynthesizeNativeMouseEvent(
aPoint, NativeMouseMessage::Move, mozilla::MouseButton::eNotPressed,
nsIWidget::Modifiers::NO_MODIFIERS, aObserver);
};
virtual nsresult SynthesizeNativeMouseScrollEvent(

View File

@ -488,8 +488,9 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
}
virtual nsresult SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) override {
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
mozilla::MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) override {
mozilla::widget::AutoObserverNotifier notifier(aObserver, "mouseevent");
return NS_ERROR_UNEXPECTED;
}

View File

@ -1576,18 +1576,25 @@ class nsIWidget : public nsISupports {
* z-order.
* @param aPoint screen location of the mouse, in device
* pixels, with origin at the top left
* @param aNativeMessage *platform-specific* event type (e.g. on Mac,
* NSEventTypeMouseMoved; on Windows, MOUSEEVENTF_MOVE, MOUSEEVENTF_LEFTDOWN
* etc)
* @param aNativeMessage abstract native message.
* @param aButton Mouse button defined by DOM UI Events.
* @param aModifierFlags Some values of nsIWidget::Modifiers.
* FYI: On Windows, Android and Headless widget on all
* platroms, this hasn't been handled yet.
* @param aObserver the observer that will get notified once the events
* have been dispatched.
*/
enum class NativeMouseMessage : uint32_t {
ButtonDown, // button down
ButtonUp, // button up
Move, // mouse cursor move
EnterWindow, // mouse cursor comes into a window
LeaveWindow, // mouse cursor leaves from a window
};
virtual nsresult SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) = 0;
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
mozilla::MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) = 0;
/**
* A shortcut to SynthesizeNativeMouseEvent, abstracting away the native

View File

@ -20,14 +20,20 @@
<![CDATA[
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const NSEventTypeMouseMoved = 5;
var gLeftWindow, gRightWindow, gBrowserElement;
var gExpectedEvents = [];
function moveMouseTo(x, y, andThen) {
var utils = gLeftWindow.windowUtils;
utils.sendNativeMouseEvent(x, y, NSEventTypeMouseMoved, 0, gLeftWindow.documentElement);
utils.sendNativeMouseEvent(
x,
y,
utils.NATIVE_MOUSE_MESSAGE_MOVE,
0,
0,
gLeftWindow.documentElement
);
SimpleTest.executeSoon(andThen);
}

View File

@ -29,29 +29,21 @@ SimpleTest.waitForExplicitFinish();
let utils = window.windowUtils;
let panel = document.getElementById('thepanel');
let nativeMouseMove;
let rect;
function startTest() {
let widgetToolkit = SpecialPowers.Services.appinfo.widgetToolkit;
if (widgetToolkit == "cocoa") {
nativeMouseMove = 5; // NSEventTypeMouseMoved
} else if (widgetToolkit == "windows") {
nativeMouseMove = 1; // MOUSEEVENTF_MOVE
} else if (/^gtk/.test(widgetToolkit)) {
nativeMouseMove = 3; // GDK_MOTION_NOTIFY
} else {
todo_is("widgetToolkit", widgetToolkit, "Platform not supported");
done();
}
// This first event is to ensure that the next event will have different
// coordinates to the previous mouse position, and so actually generates
// mouse events. The mouse is not moved off the window, as that might
// move focus to another application.
utils.sendNativeMouseEvent(window.mozInnerScreenX, window.mozInnerScreenY,
nativeMouseMove, 0, window.documentElement);
utils.sendNativeMouseEvent(
window.mozInnerScreenX,
window.mozInnerScreenY,
utils.NATIVE_MOUSE_MESSAGE_MOVE,
0,
0,
window.documentElement
);
panel.openPopup(document.getElementById("anchor"), "after_start");
}
@ -60,7 +52,12 @@ function sendMouseEvent() {
rect = panel.getBoundingClientRect();
let x = window.mozInnerScreenX + rect.left + 1;
let y = window.mozInnerScreenY + rect.top + 2;
utils.sendNativeMouseEvent(x, y, nativeMouseMove, 0,
utils.sendNativeMouseEvent(
x,
y,
utils.NATIVE_MOUSE_MESSAGE_MOVE,
0,
0,
window.documentElement);
}

View File

@ -6605,18 +6605,11 @@ nsresult nsWindow::SynthesizeNativeKeyEvent(
}
nsresult nsWindow::SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) {
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) {
AutoObserverNotifier notifier(aObserver, "mouseevent");
if (aNativeMessage == MOUSEEVENTF_MOVE) {
// Reset sLastMouseMovePoint so that even if we're moving the mouse
// to the position it's already at, we still dispatch a mousemove
// event, because the callers of this function expect that.
sLastMouseMovePoint = {0};
}
::SetCursorPos(aPoint.x, aPoint.y);
INPUT input;
memset(&input, 0, sizeof(input));
@ -6627,8 +6620,50 @@ nsresult nsWindow::SynthesizeNativeMouseEvent(
// being handled, and MOUSEEVENTF_MOVE may be coalesced by Windows. So, we
// need a trick for handling it.
switch (aNativeMessage) {
case NativeMouseMessage::Move:
input.mi.dwFlags = MOUSEEVENTF_MOVE;
// Reset sLastMouseMovePoint so that even if we're moving the mouse
// to the position it's already at, we still dispatch a mousemove
// event, because the callers of this function expect that.
sLastMouseMovePoint = {0};
break;
case NativeMouseMessage::ButtonDown:
case NativeMouseMessage::ButtonUp: {
const bool isDown = aNativeMessage == NativeMouseMessage::ButtonDown;
switch (aButton) {
case MouseButton::ePrimary:
input.mi.dwFlags = isDown ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
break;
case MouseButton::eMiddle:
input.mi.dwFlags =
isDown ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
break;
case MouseButton::eSecondary:
input.mi.dwFlags =
isDown ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
break;
case MouseButton::eX1:
input.mi.dwFlags = isDown ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP;
input.mi.mouseData = XBUTTON1;
break;
case MouseButton::eX2:
input.mi.dwFlags = isDown ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP;
input.mi.mouseData = XBUTTON2;
break;
default:
return NS_ERROR_INVALID_ARG;
}
break;
}
case NativeMouseMessage::EnterWindow:
case NativeMouseMessage::LeaveWindow:
MOZ_ASSERT_UNREACHABLE("Non supported mouse event on Windows");
return NS_ERROR_INVALID_ARG;
}
input.type = INPUT_MOUSE;
input.mi.dwFlags = aNativeMessage;
::SetCursorPos(aPoint.x, aPoint.y);
::SendInput(1, &input, sizeof(INPUT));
return NS_OK;

View File

@ -223,14 +223,15 @@ class nsWindow final : public nsWindowBase {
uint32_t aModifierFlags, const nsAString& aCharacters,
const nsAString& aUnmodifiedCharacters, nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
nsIWidget::Modifiers aModifierFlags, nsIObserver* aObserver) override;
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
mozilla::MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver) override {
return SynthesizeNativeMouseEvent(aPoint, MOUSEEVENTF_MOVE,
nsIWidget::Modifiers::NO_MODIFIERS,
aObserver);
return SynthesizeNativeMouseEvent(
aPoint, NativeMouseMessage::Move, mozilla::MouseButton::eNotPressed,
nsIWidget::Modifiers::NO_MODIFIERS, aObserver);
}
virtual nsresult SynthesizeNativeMouseScrollEvent(