7aeb3bb475
The build-redbear.sh script auto-stashes working tree changes
in nested relibc and base source trees before running the
build. These changes were captured by the failed kernel
build attempt that hit the json-target-spec / kernel rust
toolchain mismatch (fixed in 0.2.5 by creating the local
0.2.5 branch).
Captured changes:
- local/recipes/kde/* : KDE Frameworks 6 source CMakeLists
whitespace changes from the autostash (preserved)
- local/recipes/qt/qtbase/* : qtypes.h whitespace from the
autostash (preserved)
- local/sources/kernel/Cargo.lock : dependency lock from
the kernel relibc rebuild attempt
- local/sources/kernel/src/lib.rs : touched (mtime) by the
build script's touch + make prefix command
This is a bookkeeping commit — the actual code changes
for the threading plan are on the 4 submodule branches
(kernel, relibc, base, libredox) and will be pushed
separately.
0.2.5 branch was created from 0.2.4 (HEAD cd3950072e) to
continue Phase 0 of the multi-threading plan work in a
clean branch.
348 lines
13 KiB
C++
348 lines
13 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
|
SPDX-FileCopyrightText: 2023 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "kwin_wayland_test.h"
|
|
|
|
#include "core/inputdevice.h"
|
|
#include "input.h"
|
|
#include "main.h"
|
|
#include "wayland_server.h"
|
|
|
|
#include <linux/input-event-codes.h>
|
|
#include <xkbcommon/xkbcommon-keysyms.h>
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
static const QString s_socketName = QStringLiteral("wayland_test_kwin_fakeinput-0");
|
|
|
|
class FakeInputTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private Q_SLOTS:
|
|
void initTestCase();
|
|
void init();
|
|
void cleanup();
|
|
void testPointerMotion();
|
|
void testMotionAbsolute();
|
|
void testPointerButton_data();
|
|
void testPointerButton();
|
|
void testPointerVerticalAxis();
|
|
void testPointerHorizontalAxis();
|
|
void testTouch();
|
|
void testKeyboardKey_data();
|
|
void testKeyboardKey();
|
|
void testKeySym();
|
|
|
|
private:
|
|
InputDevice *m_inputDevice = nullptr;
|
|
};
|
|
|
|
void FakeInputTest::initTestCase()
|
|
{
|
|
QVERIFY(waylandServer()->init(s_socketName));
|
|
kwinApp()->start();
|
|
Test::setOutputConfig({
|
|
Rect(0, 0, 1280, 1024),
|
|
Rect(1280, 0, 1280, 1024),
|
|
});
|
|
}
|
|
|
|
void FakeInputTest::init()
|
|
{
|
|
QSignalSpy deviceAddedSpy(input(), &InputRedirection::deviceAdded);
|
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::FakeInput | Test::AdditionalWaylandInterface::Seat));
|
|
|
|
QVERIFY(deviceAddedSpy.wait());
|
|
m_inputDevice = deviceAddedSpy.last().at(0).value<InputDevice *>();
|
|
}
|
|
|
|
void FakeInputTest::cleanup()
|
|
{
|
|
Test::destroyWaylandConnection();
|
|
}
|
|
|
|
void FakeInputTest::testPointerMotion()
|
|
{
|
|
Test::FakeInput *fakeInput = Test::waylandFakeInput();
|
|
|
|
// without an authentication we shouldn't get the signals
|
|
QSignalSpy pointerMotionSpy(m_inputDevice, &InputDevice::pointerMotion);
|
|
fakeInput->pointer_motion(wl_fixed_from_double(1), wl_fixed_from_double(2));
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(pointerMotionSpy.isEmpty());
|
|
|
|
// now let's authenticate the interface
|
|
fakeInput->authenticate(QStringLiteral("org.kde.foobar"), QStringLiteral("foobar"));
|
|
fakeInput->pointer_motion(wl_fixed_from_double(1), wl_fixed_from_double(2));
|
|
QVERIFY(pointerMotionSpy.wait());
|
|
QCOMPARE(pointerMotionSpy.last().first().toPointF(), QPointF(1, 2));
|
|
|
|
// just for the fun: once more
|
|
fakeInput->pointer_motion(wl_fixed_from_double(0), wl_fixed_from_double(0));
|
|
QVERIFY(pointerMotionSpy.wait());
|
|
QCOMPARE(pointerMotionSpy.last().first().toPointF(), QPointF(0, 0));
|
|
}
|
|
|
|
void FakeInputTest::testMotionAbsolute()
|
|
{
|
|
Test::FakeInput *fakeInput = Test::waylandFakeInput();
|
|
|
|
// without an authentication we shouldn't get the signals
|
|
QSignalSpy pointerMotionAbsoluteSpy(m_inputDevice, &InputDevice::pointerMotionAbsolute);
|
|
fakeInput->pointer_motion_absolute(wl_fixed_from_double(1), wl_fixed_from_double(2));
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(pointerMotionAbsoluteSpy.isEmpty());
|
|
|
|
// now let's authenticate the interface
|
|
fakeInput->authenticate(QStringLiteral("org.kde.foobar"), QStringLiteral("foobar"));
|
|
fakeInput->pointer_motion_absolute(wl_fixed_from_double(1), wl_fixed_from_double(2));
|
|
QVERIFY(pointerMotionAbsoluteSpy.wait());
|
|
QCOMPARE(pointerMotionAbsoluteSpy.last().first().toPointF(), QPointF(1, 2));
|
|
}
|
|
|
|
void FakeInputTest::testPointerButton_data()
|
|
{
|
|
QTest::addColumn<quint32>("linuxButton");
|
|
|
|
QTest::newRow("left") << quint32(BTN_LEFT);
|
|
QTest::newRow("right") << quint32(BTN_RIGHT);
|
|
QTest::newRow("middle") << quint32(BTN_MIDDLE);
|
|
QTest::newRow("side") << quint32(BTN_SIDE);
|
|
QTest::newRow("extra") << quint32(BTN_EXTRA);
|
|
QTest::newRow("forward") << quint32(BTN_FORWARD);
|
|
QTest::newRow("back") << quint32(BTN_BACK);
|
|
QTest::newRow("task") << quint32(BTN_TASK);
|
|
}
|
|
|
|
void FakeInputTest::testPointerButton()
|
|
{
|
|
Test::FakeInput *fakeInput = Test::waylandFakeInput();
|
|
|
|
// without an authentication we shouldn't get the signals
|
|
QSignalSpy pointerButtonSpy(m_inputDevice, &InputDevice::pointerButtonChanged);
|
|
QFETCH(quint32, linuxButton);
|
|
fakeInput->button(linuxButton, WL_POINTER_BUTTON_STATE_PRESSED);
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(pointerButtonSpy.isEmpty());
|
|
|
|
// now authenticate
|
|
fakeInput->authenticate(QStringLiteral("org.kde.foobar"), QStringLiteral("foobar"));
|
|
fakeInput->button(linuxButton, WL_POINTER_BUTTON_STATE_PRESSED);
|
|
QVERIFY(pointerButtonSpy.wait());
|
|
QCOMPARE(pointerButtonSpy.last().at(0).value<quint32>(), linuxButton);
|
|
QCOMPARE(pointerButtonSpy.last().at(1).value<PointerButtonState>(), PointerButtonState::Pressed);
|
|
|
|
// and release
|
|
fakeInput->button(linuxButton, WL_POINTER_BUTTON_STATE_RELEASED);
|
|
QVERIFY(pointerButtonSpy.wait());
|
|
QCOMPARE(pointerButtonSpy.last().at(0).value<quint32>(), linuxButton);
|
|
QCOMPARE(pointerButtonSpy.last().at(1).value<PointerButtonState>(), PointerButtonState::Released);
|
|
}
|
|
|
|
void FakeInputTest::testPointerVerticalAxis()
|
|
{
|
|
Test::FakeInput *fakeInput = Test::waylandFakeInput();
|
|
|
|
// without an authentication we shouldn't get the signals
|
|
QSignalSpy pointerAxisSpy(m_inputDevice, &InputDevice::pointerAxisChanged);
|
|
fakeInput->axis(WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_double(15));
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(pointerAxisSpy.isEmpty());
|
|
|
|
// now authenticate
|
|
fakeInput->authenticate(QStringLiteral("org.kde.foobar"), QStringLiteral("foobar"));
|
|
fakeInput->axis(WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_double(15));
|
|
QVERIFY(pointerAxisSpy.wait());
|
|
QCOMPARE(pointerAxisSpy.last().at(0).value<PointerAxis>(), PointerAxis::Vertical);
|
|
QCOMPARE(pointerAxisSpy.last().at(1).value<qreal>(), 15);
|
|
}
|
|
|
|
void FakeInputTest::testPointerHorizontalAxis()
|
|
{
|
|
Test::FakeInput *fakeInput = Test::waylandFakeInput();
|
|
|
|
// without an authentication we shouldn't get the signals
|
|
QSignalSpy pointerAxisSpy(m_inputDevice, &InputDevice::pointerAxisChanged);
|
|
fakeInput->axis(WL_POINTER_AXIS_HORIZONTAL_SCROLL, wl_fixed_from_double(15));
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(pointerAxisSpy.isEmpty());
|
|
|
|
// now authenticate
|
|
fakeInput->authenticate(QStringLiteral("org.kde.foobar"), QStringLiteral("foobar"));
|
|
fakeInput->axis(WL_POINTER_AXIS_HORIZONTAL_SCROLL, wl_fixed_from_double(15));
|
|
QVERIFY(pointerAxisSpy.wait());
|
|
QCOMPARE(pointerAxisSpy.last().at(0).value<PointerAxis>(), PointerAxis::Horizontal);
|
|
QCOMPARE(pointerAxisSpy.last().at(1).value<qreal>(), 15);
|
|
}
|
|
|
|
void FakeInputTest::testTouch()
|
|
{
|
|
Test::FakeInput *fakeInput = Test::waylandFakeInput();
|
|
|
|
// without an authentication we shouldn't get the signals
|
|
QSignalSpy touchDownSpy(m_inputDevice, &InputDevice::touchDown);
|
|
QSignalSpy touchUpSpy(m_inputDevice, &InputDevice::touchUp);
|
|
QSignalSpy touchMotionSpy(m_inputDevice, &InputDevice::touchMotion);
|
|
QSignalSpy touchFrameSpy(m_inputDevice, &InputDevice::touchFrame);
|
|
QSignalSpy touchCanceledSpy(m_inputDevice, &InputDevice::touchCanceled);
|
|
fakeInput->touch_down(0, wl_fixed_from_double(1), wl_fixed_from_double(2));
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(touchDownSpy.isEmpty());
|
|
|
|
fakeInput->touch_motion(0, wl_fixed_from_double(3), wl_fixed_from_double(4));
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(touchMotionSpy.isEmpty());
|
|
|
|
fakeInput->touch_up(0);
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(touchUpSpy.isEmpty());
|
|
|
|
fakeInput->touch_down(1, wl_fixed_from_double(5), wl_fixed_from_double(6));
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(touchDownSpy.isEmpty());
|
|
|
|
fakeInput->touch_frame();
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(touchFrameSpy.isEmpty());
|
|
|
|
fakeInput->touch_cancel();
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(touchCanceledSpy.isEmpty());
|
|
|
|
// now let's authenticate the interface
|
|
fakeInput->authenticate(QStringLiteral("org.kde.foobar"), QStringLiteral("foobar"));
|
|
fakeInput->touch_down(0, wl_fixed_from_double(1), wl_fixed_from_double(2));
|
|
QVERIFY(touchDownSpy.wait());
|
|
QCOMPARE(touchDownSpy.count(), 1);
|
|
QCOMPARE(touchDownSpy.last().at(0).value<quint32>(), quint32(0));
|
|
QCOMPARE(touchDownSpy.last().at(1).toPointF(), QPointF(1, 2));
|
|
|
|
// Same id should not trigger another touchDown.
|
|
fakeInput->touch_down(0, wl_fixed_from_double(5), wl_fixed_from_double(6));
|
|
QVERIFY(Test::waylandSync());
|
|
QCOMPARE(touchDownSpy.count(), 1);
|
|
|
|
fakeInput->touch_motion(0, wl_fixed_from_double(3), wl_fixed_from_double(4));
|
|
QVERIFY(touchMotionSpy.wait());
|
|
QCOMPARE(touchMotionSpy.count(), 1);
|
|
QCOMPARE(touchMotionSpy.last().at(0).value<quint32>(), quint32(0));
|
|
QCOMPARE(touchMotionSpy.last().at(1).toPointF(), QPointF(3, 4));
|
|
|
|
// touchMotion with bogus id should not trigger signal.
|
|
fakeInput->touch_motion(1, wl_fixed_from_double(3), wl_fixed_from_double(4));
|
|
QVERIFY(Test::waylandSync());
|
|
QCOMPARE(touchMotionSpy.count(), 1);
|
|
|
|
fakeInput->touch_up(0);
|
|
QVERIFY(touchUpSpy.wait());
|
|
QCOMPARE(touchUpSpy.count(), 1);
|
|
QCOMPARE(touchUpSpy.last().at(0).value<quint32>(), quint32(0));
|
|
|
|
// touchUp with bogus id should not trigger signal.
|
|
fakeInput->touch_up(1);
|
|
QVERIFY(Test::waylandSync());
|
|
QCOMPARE(touchUpSpy.count(), 1);
|
|
|
|
fakeInput->touch_down(1, wl_fixed_from_double(5), wl_fixed_from_double(6));
|
|
QVERIFY(touchDownSpy.wait());
|
|
QCOMPARE(touchDownSpy.count(), 2);
|
|
QCOMPARE(touchDownSpy.last().at(0).value<quint32>(), quint32(1));
|
|
QCOMPARE(touchDownSpy.last().at(1).toPointF(), QPointF(5, 6));
|
|
|
|
fakeInput->touch_frame();
|
|
QVERIFY(touchFrameSpy.wait());
|
|
QCOMPARE(touchFrameSpy.count(), 1);
|
|
|
|
fakeInput->touch_cancel();
|
|
QVERIFY(touchCanceledSpy.wait());
|
|
QCOMPARE(touchCanceledSpy.count(), 1);
|
|
}
|
|
|
|
void FakeInputTest::testKeyboardKey_data()
|
|
{
|
|
QTest::addColumn<quint32>("linuxKey");
|
|
|
|
QTest::newRow("A") << quint32(KEY_A);
|
|
QTest::newRow("S") << quint32(KEY_S);
|
|
QTest::newRow("D") << quint32(KEY_D);
|
|
QTest::newRow("F") << quint32(KEY_F);
|
|
}
|
|
|
|
void FakeInputTest::testKeyboardKey()
|
|
{
|
|
Test::FakeInput *fakeInput = Test::waylandFakeInput();
|
|
|
|
// without an authentication we shouldn't get the signals
|
|
QSignalSpy keyboardKeySpy(m_inputDevice, &InputDevice::keyChanged);
|
|
QFETCH(quint32, linuxKey);
|
|
fakeInput->keyboard_key(linuxKey, WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
QVERIFY(Test::waylandSync());
|
|
QVERIFY(keyboardKeySpy.isEmpty());
|
|
|
|
// now authenticate
|
|
fakeInput->authenticate(QStringLiteral("org.kde.foobar"), QStringLiteral("foobar"));
|
|
fakeInput->keyboard_key(linuxKey, WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
QVERIFY(keyboardKeySpy.wait());
|
|
QCOMPARE(keyboardKeySpy.last().at(0).value<quint32>(), linuxKey);
|
|
QCOMPARE(keyboardKeySpy.last().at(1).value<KeyboardKeyState>(), KeyboardKeyState::Pressed);
|
|
|
|
// and release
|
|
fakeInput->keyboard_key(linuxKey, WL_KEYBOARD_KEY_STATE_RELEASED);
|
|
QVERIFY(keyboardKeySpy.wait());
|
|
QCOMPARE(keyboardKeySpy.last().at(0).value<quint32>(), linuxKey);
|
|
QCOMPARE(keyboardKeySpy.last().at(1).value<KeyboardKeyState>(), KeyboardKeyState::Released);
|
|
}
|
|
|
|
void FakeInputTest::testKeySym()
|
|
{
|
|
// as keyboard input is complex, test the client gets the right keys as well as kwin
|
|
Test::FakeInput *fakeInput = Test::waylandFakeInput();
|
|
fakeInput->authenticate(QStringLiteral("org.kde.foobar"), QStringLiteral("foobar"));
|
|
|
|
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
|
|
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
|
|
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(1280, 1024), Qt::red);
|
|
QVERIFY(window);
|
|
QVERIFY(window->isActive());
|
|
QCOMPARE(window->frameGeometry().size(), QSize(1280, 1024));
|
|
|
|
auto keyboard = new Test::SimpleKeyboard(window);
|
|
|
|
auto sendKey = [fakeInput](uint32_t keySym) {
|
|
fakeInput->keyboard_keysym(keySym, WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
fakeInput->keyboard_keysym(keySym, WL_KEYBOARD_KEY_STATE_RELEASED);
|
|
};
|
|
|
|
sendKey(XKB_KEY_a);
|
|
sendKey(XKB_KEY_B);
|
|
sendKey(XKB_KEY_space);
|
|
sendKey(XKB_KEY_adiaeresis); // lowercase a with umlauts
|
|
sendKey(XKB_KEY_Adiaeresis); // uppercase a with umlauts
|
|
sendKey(XKB_KEY_space);
|
|
sendKey(0x01000000 | 0xC548); // korean symbol
|
|
sendKey(0x01000000 | 0x1F60A); // smily face
|
|
sendKey(XKB_KEY_f);
|
|
|
|
QSignalSpy receivedTextChangedSpy(keyboard, &Test::SimpleKeyboard::receviedTextChanged);
|
|
bool matched = false;
|
|
for (int i = 0; i < 10; ++i) {
|
|
if (keyboard->receviedText() == "aB äÄ 안😊f") {
|
|
matched = true;
|
|
break;
|
|
}
|
|
receivedTextChangedSpy.wait();
|
|
}
|
|
QVERIFY(matched);
|
|
}
|
|
|
|
} // namespace KWin
|
|
|
|
WAYLANDTEST_MAIN(KWin::FakeInputTest)
|
|
#include "fakeinput_test.moc"
|