faaxm / spix

UI test automation library for QtQuick/QML Apps
MIT License
184 stars 47 forks source link

[Qt6] Drawer element blocks mouseClick #54

Open prototypicalpro opened 2 years ago

prototypicalpro commented 2 years ago

I have a strange bug that I'm trying to wrap my head around. When using spix (modified to print the mouse events) with a minimal QML application on Qt6 everything works as expected:

ApplicationWindow {
    id: window
    visible: true

    Button {
        id: clickMe
        onClicked: console.log("clicked");
        text: "A Special Button"
    }
}
s = xmlrpc.client.ServerProxy('http://localhost:9000')
s.mouseClick("window/clickMe")
print(s.getErrors())
# Qt
Starting minimalDrawerBug...
QML debugging is enabled. Only use this in a safe environment.
QMouseEvent(MouseButtonPress LeftButton pos=60.1016,12.5 scn=60.1016,12.5 gbl=2470,944 dev=QPointingDevice("core pointer" Mouse id=1))
QMouseEvent(MouseButtonRelease LeftButton pos=60.1016,12.5 scn=60.1016,12.5 gbl=2470,944 dev=QPointingDevice("core pointer" Mouse id=1))
qml: clicked

# python
[]

When I update the QML application to include a Drawer element, however, spix is unable to click on the element:

ApplicationWindow {
    id: window
    visible: true

    Button {
        id: clickMe
        onClicked: console.log("clicked");
        text: "A Special Button"
    }

    // I tested placing drawer both before and after button
    Drawer {
        id: drawer
    }
}
# Qt
Starting minimalDrawerBug...
QML debugging is enabled. Only use this in a safe environment.
QMouseEvent(MouseButtonPress LeftButton pos=60.1016,12.5 scn=60.1016,12.5 gbl=2470,944 dev=QPointingDevice("core pointer" Mouse id=1))
QMouseEvent(MouseButtonRelease LeftButton pos=60.1016,12.5 scn=60.1016,12.5 gbl=2470,944 dev=QPointingDevice("core pointer" Mouse id=1))

# python
[]

I am still able to click the button with normal mouse interaction, but spix seems unable to replicate the same behavior using synthetic events. As far as I can tell spix is generating the same MouseEvent in both cases, so maybe it has something to do with how Drawer interacts with mouse events?

I'm on Ubuntu 20.04, Qt 6.2.3 and the latest spix from master (modified slightly to print mouse events). I'd be happy to post the full project that I test with if that's helpful.

faaxm commented 2 years ago

I have had some issues with the synthetic events in more complex cases, like drag&drop, where Qt seems to work directly with system events and not with the QEvents in its own queue. But that this would be caused by just adding a Drawer seems odd...

What happens if you use pyAutoGUI to create the events on the system level? If you post the code, I can have a look...

prototypicalpro commented 2 years ago

Interaction with pyAutoGui seems to work. Test script:

import xmlrpc.client
import time
import pyautogui

def clickItem(path):
    # from https://github.com/faaxm/spix/blob/master/examples/RemoteCtrl/script/autogui.py
    # Query spix to get the location of the item
    bounds = s.getBoundingBox(path)
    # bounds = [x, y, width, height] as list
    center_x = bounds[0] + bounds[2] / 2
    center_y = bounds[1] + bounds[3] / 2

    # use pyautogui to move the cursor...
    pyautogui.moveTo(center_x, center_y, duration=1)
    # ...and click
    pyautogui.click()

s = xmlrpc.client.ServerProxy('http://localhost:9000')
print('Test synthetic click')
time.sleep(1)
s.mouseClick("window/clickMe")
print(s.getErrors())
time.sleep(1)

print('Test autogui click')
time.sleep(1)
clickItem("window/clickMe")
print(s.getErrors())
print('done')

Log without drawer:

Starting minimalDrawerBug...
QML debugging is enabled. Only use this in a safe environment.
QMouseEvent(MouseButtonPress LeftButton pos=60.1016,12.5 scn=60.1016,12.5 gbl=844,1400 dev=QPointingDevice("core pointer" Mouse id=1))
QMouseEvent(MouseButtonRelease LeftButton pos=60.1016,12.5 scn=60.1016,12.5 gbl=844,1400 dev=QPointingDevice("core pointer" Mouse id=1))
qml: clicked
qml: clicked

Log with drawer:

Starting minimalDrawerBug...
QML debugging is enabled. Only use this in a safe environment.
QMouseEvent(MouseButtonPress LeftButton pos=60.1016,12.5 scn=60.1016,12.5 gbl=1121,1226 dev=QPointingDevice("core pointer" Mouse id=1))
QMouseEvent(MouseButtonRelease LeftButton pos=60.1016,12.5 scn=60.1016,12.5 gbl=1121,1226 dev=QPointingDevice("core pointer" Mouse id=1))
qml: clicked

If you could take a look at the project that would be great, I am thoroughly stumped: minimalDrawerBug.zip. Let me know if you have any questions.

faaxm commented 2 years ago

Sorry for the long wait, I had less time to look into this than I had hoped... For now, I only had a quick look and have tested this with Qt5 as that is still my default version. With that version, I found that it seems to work as expected.

The output I get is:

# Qt
$ ./examples/Basic/SpixBasicExample
qml: clicked
qml: clicked

# python
$ python3 test_click.py 
Test synthetic click
[]
Test autogui click
[]
done

The synthetic click also works when running the app with -platform minimal.

MelodicsPavol commented 1 year ago

Hi there, very similar (or maybe same) problem is happening with our app, using quite complex UI elements. Spix works great with Qt 5.15.10 but all generated QEvents have no effect in Qt 6.4.2.

Note that some of the constructors that Spix is using (e.g. QMouseEvent are deprecated since Qt 6.4) but they should still work. Any idea how to solve this problem? The generated events pass through installed event filter, but maybe are not delivered to the receiver.

Update: The unit tests work with Qt 6.4.2 and if I use same QML contents from the tests in our app, it works as well.

MelodicsPavol commented 1 year ago

I've found through debugging that the issue was caused by an inactive Popup item attached to an Overlay and thus blocking mouse events. Interestingly regular mouse clicks worked, so did the pyautogui solution.

chruetli commented 2 months ago

Hi there, I have the same problem. My UI has a drawer on it which seems to block the mouse events. As soon as i replace the drawer everything works. Disabling, or modifying any property doensn't help to have the mouse clicks come through. I'm using Qt 6.5.0. Any ideas how to work with this?

auxxos commented 2 months ago

I think, it is related to how mouse events are simulated. In the current SPIX version, they are fired on windows level. I have changed this to component level in my SPIX version. You can then adress the target component directly and the events are working even underneath a drawer.

There is a corresponding pull request (#101), but it is still open.

chruetli commented 2 months ago

I think, it is related to how mouse events are simulated. In the current SPIX version, they are fired on windows level. I have changed this to component level in my SPIX version. You can then adress the target component directly and the events are working even underneath a drawer.

There is a corresponding pull request (#101), but it is still open.

Thanks for the hint. But for me it still doesn't work. Maybe I didn't something wrong using your commit. Anyway, did you try your changes it with the example given by @prototypicalpro in the first post?

auxxos commented 2 months ago

Just tried it, and it works with my version.

If I define WINDOW_MODE in QtEvents.cpp the code in the first post is not working. If I use my changes, it works as expected.

Check, if you have the changes in QtEvents.cpp to switch between the old and my new mode.

chruetli commented 2 months ago

Hmm, in my case undefining WINDOW_MODE is even worse. I have the following structure: Window/Item/Rectangle/Item/TabBar/contentItem/TabButton Clicking on a TabButton doesn't work, I don't get any click event. If i define WINDOW_MODE I get the click event as long as the Drawer is not present.

auxxos commented 2 months ago

In a TabBar you have to give unique ids or objectNames to the TabButtons to be able to address them.

Should not work properly in both event modes, I guess.

chruetli commented 2 months ago

Hmm, in my case undefining WINDOW_MODE is even worse. I have the following structure: Window/Item/Rectangle/Item/TabBar/contentItem/TabButton Clicking on a TabButton doesn't work, I don't get any click event. If i define WINDOW_MODE I get the click event as long as the Drawer is not present.

Sorry for the confusion, the path I mentioned was just the object path. The id/objectName path is mainWindow/controlBar/controlBackground/controlBarItem/tabBar/contentItem/controlButtonMenu. The drawer is at Window/Item/Drawer (mainWindow/statusIndicator/statusDrawer)