Commit ef2253b4 authored by Masayuki Nakano's avatar Masayuki Nakano
Browse files

Bug 1691622 - part 9: Make `nsIWidget::SynthesizeNativeMouseEvent` take an XP...

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
parent e675c834
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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 {
+4 −56
Original line number Diff line number Diff line
@@ -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
+32 −8
Original line number Diff line number Diff line
@@ -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;
}

+18 −6
Original line number Diff line number Diff line
@@ -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);

  /**
+4 −2
Original line number Diff line number Diff line
@@ -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());
  }
Loading