diff options
author | Johan Klokkhammer Helsing <johan.helsing@qt.io> | 2018-03-27 15:30:26 +0200 |
---|---|---|
committer | Johan Helsing <johan.helsing@qt.io> | 2018-04-27 10:17:10 +0000 |
commit | bd5917025fe7491c9f24e99c20484c7ffce9f172 (patch) | |
tree | 006435d90eb25738b04a2c86aa45c0b3e8babdf1 /tests/auto | |
parent | 531a767040782007181bb13583fe69b4ba4b1ba3 (diff) |
Add QWaylandSeat::sendKeyEvent(int qtKey, bool pressed)
Makes it possible to send keyboard events using the QML API:
Button {
onPressedChanged: seat.sendKeyEvent(Qt.Key_Left, pressed)
}
The wl_keyboard.key event requires a keyboard scan code, so in order to get
this we iterate over all the keys in the current keymap checking which QtKey
they map to, storing the results in a QMap which is reused by later calls to
QWaylandKeymap::toScanCode.
This also fixes a bug when sending QKeyEvents without a native scan code using
QWaylandSeat::sendFullKeyEvent. (generated key events have no nativeScanCode).
Now we try QWaylandKeyboard::toScanCode, and if unsuccessful we return with a
warning instead of letting the assertion in QWaylandKeyboard fail.
This also adds more thorough testing for the keyboard, including keymaps and
checking that the events, including enter and leave, are actually received on
the client side.
Change-Id: I601b0c7d909071863abb146bd65a990215dcaff7
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
Diffstat (limited to 'tests/auto')
-rw-r--r-- | tests/auto/compositor/compositor/compositor.pro | 2 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/mockkeyboard.cpp | 101 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/mockkeyboard.h | 50 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/mockseat.cpp | 5 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/mockseat.h | 4 | ||||
-rw-r--r-- | tests/auto/compositor/compositor/tst_compositor.cpp | 139 |
6 files changed, 293 insertions, 8 deletions
diff --git a/tests/auto/compositor/compositor/compositor.pro b/tests/auto/compositor/compositor/compositor.pro index 2919fa4bb..68b18c974 100644 --- a/tests/auto/compositor/compositor/compositor.pro +++ b/tests/auto/compositor/compositor/compositor.pro @@ -21,6 +21,7 @@ SOURCES += \ mockclient.cpp \ mockseat.cpp \ testseat.cpp \ + mockkeyboard.cpp \ mockpointer.cpp HEADERS += \ @@ -29,4 +30,5 @@ HEADERS += \ mockclient.h \ mockseat.h \ testseat.h \ + mockkeyboard.h \ mockpointer.h diff --git a/tests/auto/compositor/compositor/mockkeyboard.cpp b/tests/auto/compositor/compositor/mockkeyboard.cpp new file mode 100644 index 000000000..e5f5f8d36 --- /dev/null +++ b/tests/auto/compositor/compositor/mockkeyboard.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockkeyboard.h" + +void keyboardKeymap(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) +{ + Q_UNUSED(keyboard); + Q_UNUSED(wl_keyboard); + Q_UNUSED(format); + Q_UNUSED(fd); + Q_UNUSED(size); +} + +void keyboardEnter(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) +{ + Q_UNUSED(wl_keyboard); + Q_UNUSED(serial); + Q_UNUSED(surface); + Q_UNUSED(keys); + + static_cast<MockKeyboard *>(keyboard)->m_enteredSurface = surface; +} + +void keyboardLeave(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) +{ + Q_UNUSED(wl_keyboard); + Q_UNUSED(serial); + Q_UNUSED(surface); + + static_cast<MockKeyboard *>(keyboard)->m_enteredSurface = nullptr; +} + +void keyboardKey(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + Q_UNUSED(keyboard); + Q_UNUSED(wl_keyboard); + Q_UNUSED(serial); + Q_UNUSED(time); + Q_UNUSED(key); + Q_UNUSED(state); + auto kb = static_cast<MockKeyboard *>(keyboard); + kb->m_lastKeyCode = key; + kb->m_lastKeyState = state; +} + +void keyboardModifiers(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) +{ + Q_UNUSED(keyboard); + Q_UNUSED(wl_keyboard); + Q_UNUSED(serial); + Q_UNUSED(mods_depressed); + Q_UNUSED(mods_latched); + Q_UNUSED(mods_locked); + auto kb = static_cast<MockKeyboard *>(keyboard); + kb->m_group = group; +} + +static const struct wl_keyboard_listener keyboardListener = { + keyboardKeymap, + keyboardEnter, + keyboardLeave, + keyboardKey, + keyboardModifiers +}; + +MockKeyboard::MockKeyboard(wl_seat *seat) + : m_keyboard(wl_seat_get_keyboard(seat)) +{ + wl_keyboard_add_listener(m_keyboard, &keyboardListener, this); +} + +MockKeyboard::~MockKeyboard() +{ + wl_keyboard_destroy(m_keyboard); +} diff --git a/tests/auto/compositor/compositor/mockkeyboard.h b/tests/auto/compositor/compositor/mockkeyboard.h new file mode 100644 index 000000000..1090db597 --- /dev/null +++ b/tests/auto/compositor/compositor/mockkeyboard.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MOCKKEYBOARD_H +#define MOCKKEYBOARD_H + +#include <QObject> +#include <wayland-client.h> + +class MockKeyboard : public QObject +{ + Q_OBJECT + +public: + explicit MockKeyboard(wl_seat *seat); + ~MockKeyboard() override; + + wl_keyboard *m_keyboard = nullptr; + wl_surface *m_enteredSurface = nullptr; + uint m_lastKeyCode = 0; + uint m_lastKeyState = 0; + uint m_group = 0; +}; + +#endif // MOCKKEYBOARD_H diff --git a/tests/auto/compositor/compositor/mockseat.cpp b/tests/auto/compositor/compositor/mockseat.cpp index 052c2f90b..ce873c129 100644 --- a/tests/auto/compositor/compositor/mockseat.cpp +++ b/tests/auto/compositor/compositor/mockseat.cpp @@ -31,14 +31,11 @@ MockSeat::MockSeat(wl_seat *seat) : m_seat(seat) , m_pointer(new MockPointer(seat)) + , m_keyboard(new MockKeyboard(seat)) { - // Bind to the keyboard interface so that the compositor has - // the right resource associations - m_keyboard = wl_seat_get_keyboard(seat); } MockSeat::~MockSeat() { - wl_keyboard_destroy(m_keyboard); wl_seat_destroy(m_seat); } diff --git a/tests/auto/compositor/compositor/mockseat.h b/tests/auto/compositor/compositor/mockseat.h index 73d289281..f8c103ed4 100644 --- a/tests/auto/compositor/compositor/mockseat.h +++ b/tests/auto/compositor/compositor/mockseat.h @@ -29,6 +29,7 @@ #define MOCKSEAT #include "mockpointer.h" +#include "mockkeyboard.h" #include <QObject> #include <wayland-client.h> @@ -41,12 +42,13 @@ public: MockSeat(wl_seat *seat); ~MockSeat() override; MockPointer *pointer() const { return m_pointer.data(); } + MockKeyboard *keyboard() const { return m_keyboard.data(); } wl_seat *m_seat = nullptr; - wl_keyboard *m_keyboard = nullptr; private: QScopedPointer<MockPointer> m_pointer; + QScopedPointer<MockKeyboard> m_keyboard; }; #endif diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp index 575ea6466..2f00f2a83 100644 --- a/tests/auto/compositor/compositor/tst_compositor.cpp +++ b/tests/auto/compositor/compositor/tst_compositor.cpp @@ -40,10 +40,12 @@ #include <QtGui/QScreen> #include <QtWaylandCompositor/QWaylandXdgShellV5> #include <QtWaylandCompositor/private/qwaylandxdgshellv6_p.h> +#include <QtWaylandCompositor/private/qwaylandkeyboard_p.h> #include <QtWaylandCompositor/QWaylandIviApplication> #include <QtWaylandCompositor/QWaylandIviSurface> #include <QtWaylandCompositor/QWaylandSurface> #include <QtWaylandCompositor/QWaylandResource> +#include <QtWaylandCompositor/QWaylandKeymap> #include <qwayland-xdg-shell.h> #include <qwayland-ivi-application.h> @@ -56,6 +58,11 @@ class tst_WaylandCompositor : public QObject private slots: void init(); void seatCapabilities(); +#if QT_CONFIG(xkbcommon_evdev) + void simpleKeyboard(); + void keyboardKeymaps(); + void keyboardLayoutSwitching(); +#endif void keyboardGrab(); void seatCreation(); void seatKeyboardFocus(); @@ -160,6 +167,121 @@ void tst_WaylandCompositor::multipleClients() QTRY_COMPARE(compositor.surfaces.size(), 0); } +#if QT_CONFIG(xkbcommon_evdev) + +void tst_WaylandCompositor::simpleKeyboard() +{ + TestCompositor compositor; + compositor.create(); + + QWaylandSeat* seat = compositor.defaultSeat(); + seat->keymap()->setLayout("us"); + + MockClient client; + + QTRY_COMPARE(client.m_seats.size(), 1); + MockKeyboard *mockKeyboard = client.m_seats.at(0)->keyboard(); + + wl_surface *mockSurface = client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 1); + seat->setKeyboardFocus(compositor.surfaces.at(0)); + + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_enteredSurface, mockSurface); + + seat->sendKeyEvent(Qt::Key_A, true); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_lastKeyState, 1u); + QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 30u); // 30 is the scan code for A on us keyboard layouts + + seat->sendKeyEvent(Qt::Key_A, false); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_lastKeyState, 0u); + QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 30u); + + seat->sendKeyEvent(Qt::Key_Super_L, true); + seat->sendKeyEvent(Qt::Key_Super_L, false); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 125u); +} + +void tst_WaylandCompositor::keyboardKeymaps() +{ + TestCompositor compositor; + compositor.create(); + QWaylandSeat* seat = compositor.defaultSeat(); + MockClient client; + QTRY_COMPARE(client.m_seats.size(), 1); + MockKeyboard *mockKeyboard = client.m_seats.at(0)->keyboard(); + client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 1); + seat->setKeyboardFocus(compositor.surfaces.at(0)); + + seat->keymap()->setLayout("us"); + + seat->sendKeyEvent(Qt::Key_Y, true); + seat->sendKeyEvent(Qt::Key_Y, false); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 21u); + + seat->sendKeyEvent(Qt::Key_Z, true); + seat->sendKeyEvent(Qt::Key_Z, false); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 44u); + + seat->keymap()->setLayout("de"); // In the German layout y and z have changed places + + seat->sendKeyEvent(Qt::Key_Y, true); + seat->sendKeyEvent(Qt::Key_Y, false); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 44u); + + seat->sendKeyEvent(Qt::Key_Z, true); + seat->sendKeyEvent(Qt::Key_Z, false); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 21u); +} + +void tst_WaylandCompositor::keyboardLayoutSwitching() +{ + TestCompositor compositor; + compositor.create(); + QWaylandSeat* seat = compositor.defaultSeat(); + MockClient client; + QTRY_COMPARE(client.m_seats.size(), 1); + MockKeyboard *mockKeyboard = client.m_seats.at(0)->keyboard(); + client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 1); + seat->setKeyboardFocus(compositor.surfaces.at(0)); + + seat->keymap()->setLayout("us,de"); + seat->keymap()->setOptions("grp:lalt_toggle"); //toggle keyboard layout with left alt + + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_group, 0u); + + seat->sendKeyEvent(Qt::Key_Y, true); + seat->sendKeyEvent(Qt::Key_Y, false); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 21u); + + // It's not currently possible to switch layouts programmatically with the public APIs + // We will just fake it with the private APIs here. + auto keyboardPrivate = QWaylandKeyboardPrivate::get(seat->keyboard()); + const uint leftAltCode = 64; + keyboardPrivate->updateModifierState(leftAltCode, WL_KEYBOARD_KEY_STATE_PRESSED); + keyboardPrivate->updateModifierState(leftAltCode, WL_KEYBOARD_KEY_STATE_RELEASED); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_group, 1u); + + seat->sendKeyEvent(Qt::Key_Y, true); + seat->sendKeyEvent(Qt::Key_Y, false); + compositor.flushClients(); + QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 44u); +} + +#endif // QT_CONFIG(xkbcommon_evdev) + void tst_WaylandCompositor::keyboardGrab() { TestCompositor compositor; @@ -448,13 +570,24 @@ void tst_WaylandCompositor::seatKeyboardFocus() // Create client after all the input devices have been set up as the mock client // does not dynamically listen to new seats MockClient client; + + QTRY_COMPARE(client.m_seats.size(), 1); + MockKeyboard *mockKeyboard = client.m_seats.first()->keyboard(); + QVERIFY(mockKeyboard); + QCOMPARE(mockKeyboard->m_enteredSurface, nullptr); + wl_surface *surface = client.createSurface(); QTRY_COMPARE(compositor.surfaces.size(), 1); QWaylandSurface *waylandSurface = compositor.surfaces.at(0); - QWaylandSeat* dev = compositor.defaultSeat(); - dev->setKeyboardFocus(waylandSurface); - QTRY_COMPARE(compositor.defaultSeat()->keyboardFocus(), waylandSurface); + QWaylandSeat* seat = compositor.defaultSeat(); + QVERIFY(seat->setKeyboardFocus(waylandSurface)); + QCOMPARE(compositor.defaultSeat()->keyboardFocus(), waylandSurface); + + compositor.flushClients(); + + qDebug() << mockKeyboard->m_enteredSurface; + QTRY_COMPARE(mockKeyboard->m_enteredSurface, surface); wl_surface_destroy(surface); QTRY_VERIFY(compositor.surfaces.size() == 0); |