Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-99106

QMouseEvent always generates Qt::LeftButton events on Android, even on right mouse click

    XMLWordPrintable

Details

    • Android
    • 8d8cbe87e (dev), e259e5b9c (6.7)

    Description

      Mouse events generated on android always specify the Qt::LeftButton as the button generating the event. Qt::RightButton, ... events are never generated.

      The root cause is that QtNative.java does not pass the pressed buttons to mouseUp/Down in androidjniinput.cpp.

      Note that the Android ACTION_UP/DOWN events do not specify the button that generated the event, but do specify the current state of the all the buttons (see MotionEvent.getButtonState(). However, by keeping track of the previous button state ourself, we can generate the correct mouse events for the newly pressed/released events.

      Possible implementation

      androidjniinput.cpp:

      static Qt::MouseButtons m_buttons = Qt::NoButton;
      
      ...
      
      static Qt::MouseButtons mapAndroidButtons(jint buttons)
      {
          Qt::MouseButtons qbuttons;
      
          if (buttons & 0x00000001) // BUTTON_PRIMARY
              qbuttons |= Qt::LeftButton;
      
          if (buttons & 0x00000002) // BUTTON_SECONDARY
              qbuttons |= Qt::RightButton;
      
          if (buttons & 0x00000004) // BUTTON_TERTIARY
              qbuttons |= Qt::MiddleButton;
      
          if (buttons & 0x00000008) // BUTTON_BACK
              qbuttons |= Qt::BackButton;
      
          if (buttons & 0x00000010) // BUTTON_FORWARD
              qbuttons |= Qt::ForwardButton;
      
          if (buttons & 0x00000020) // BUTTON_STYLUS_PRIMARY
              qbuttons |= Qt::LeftButton;
      
          if (buttons & 0x00000040) // BUTTON_STYLUS_SECONDARY
              qbuttons |= Qt::RightButton;
      
          return qbuttons;
      }
      
      static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jint buttonState)
      {
          if (m_ignoreMouseEvents)
              return;
      
          Qt::MouseButtons qbuttons = mapAndroidButtons(buttonState);
          Qt::MouseButtons changedButtons = qbuttons & ~m_buttons; // extract (newly) pressed button
      
          if (changedButtons == Qt::NoButton)
              return;
      
          m_buttons = qbuttons;
      
          QPoint globalPos(x,y);
          QWindow *tlw = topLevelWindowAt(globalPos);
          m_mouseGrabber = tlw;
          QPoint localPos = tlw ? (globalPos - tlw->position()) : globalPos;
      
          static_assert (sizeof(changedButtons) <= sizeof(uint), "Unexpected Qt::MouseButtons size");
          for (uint button = 0x1; (uint) changedButtons >= button; button <<= 1)
          {
              if (changedButtons & button)
                  QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
                                                           qbuttons,
                                                           (Qt::MouseButton) button, QEvent::MouseButtonPress);
          }
      }
      
      static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jint buttonState)
      {
          Qt::MouseButtons qbuttons = mapAndroidButtons(buttonState);
          Qt::MouseButtons changedButtons = m_buttons & ~qbuttons; // extract (newly) released button
      
          if (changedButtons == Qt::NoButton)
            return;
      
          m_buttons = qbuttons;
      
          QPoint globalPos(x,y);
          QWindow *tlw = m_mouseGrabber.data();
          if (!tlw)
              tlw = topLevelWindowAt(globalPos);
          QPoint localPos = tlw ? (globalPos -tlw->position()) : globalPos;
      
          static_assert (sizeof(changedButtons) <= sizeof(uint), "Unexpected Qt::MouseButtons size");
          for (uint button = 0x1; (uint) changedButtons >= button; button <<= 1)
          {
              if (changedButtons & button)
                  QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
                                                           qbuttons,
                                                           (Qt::MouseButton) button, QEvent::MouseButtonRelease);
          }
      
          m_ignoreMouseEvents = false;
          m_mouseGrabber = 0;
      }
      
          static JNINativeMethod methods[] = {
      ...
              {"mouseDown", "(IIII)V", (void *)mouseDown},
              {"mouseUp", "(IIII)V", (void *)mouseUp},
      ...
          };
      

      QtNative.java

      static public boolean sendMouseEvent(MotionEvent event, int id)
      {
          switch (event.getActionMasked()) {
              case MotionEvent.ACTION_UP:
                  mouseUp(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
                  break;
      
              case MotionEvent.ACTION_DOWN:
                  mouseDown(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
                  m_oldx = (int) event.getX();
                  m_oldy = (int) event.getY();
                  break;
      ...
      }
      
      ...
      
      // pointer methods
      public static native void mouseDown(int winId, int x, int y, int buttonState);
      public static native void mouseUp(int winId, int x, int y, int buttonState);
      ...
      
      

      Attachments

        Issue Links

          For Gerrit Dashboard: QTBUG-99106
          # Subject Branch Project Status CR V

          Activity

            People

              axelspoerl Axel Spoerl
              m3197d - -
              Votes:
              2 Vote for this issue
              Watchers:
              7 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There is 1 open Gerrit change