Improve keyboard handling for internal windows

So far the key handler in the InternalWindowEventFilter used the
PointerInputRedirection's internal window. This had the result that
key events were only delivered to an internal window if the window
was under the cursor.

This change tries sending the event to the latest created and visible
window. Thus e.g. with nested context menus it goes to the current
sub menu as expected. The return value of sendEvent is used to filter
out the event.
This commit is contained in:
Martin Gräßlin 2016-02-17 13:34:24 +01:00
parent 36facda110
commit 521470b04a
2 changed files with 29 additions and 5 deletions

View file

@ -44,6 +44,7 @@ private Q_SLOTS:
void testEnterLeave();
void testPointerPressRelease();
void testPointerAxis();
void testKeyboard_data();
void testKeyboard();
};
@ -237,6 +238,14 @@ void InternalWindowTest::testPointerAxis()
QTRY_COMPARE(wheelSpy.count(), 2);
}
void InternalWindowTest::testKeyboard_data()
{
QTest::addColumn<QPoint>("cursorPos");
QTest::newRow("on Window") << QPoint(50, 50);
QTest::newRow("outside Window") << QPoint(250, 250);
}
void InternalWindowTest::testKeyboard()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
@ -252,7 +261,8 @@ void InternalWindowTest::testKeyboard()
QCOMPARE(clientAddedSpy.count(), 1);
quint32 timestamp = 1;
waylandServer()->backend()->pointerMotion(QPoint(50, 50), timestamp++);
QFETCH(QPoint, cursorPos);
waylandServer()->backend()->pointerMotion(cursorPos, timestamp++);
waylandServer()->backend()->keyboardKeyPressed(KEY_A, timestamp++);
QTRY_COMPARE(pressSpy.count(), 1);

View file

@ -385,13 +385,27 @@ class InternalWindowEventFilter : public InputEventFilter {
return e.isAccepted();
}
bool keyEvent(QKeyEvent *event) override {
auto internal = input()->pointer()->internalWindow();
if (!internal) {
const auto &internalClients = waylandServer()->internalClients();
if (internalClients.isEmpty()) {
return false;
}
QWindow *found = nullptr;
auto it = internalClients.end();
do {
it--;
if (QWindow *w = (*it)->internalWindow()) {
if (!w->isVisible()) {
continue;
}
found = w;
break;
}
} while (it != internalClients.begin());
if (!found) {
return false;
}
event->setAccepted(false);
QCoreApplication::sendEvent(internal.data(), event);
return true;
return QCoreApplication::sendEvent(found, event);
}
};