backends/fakeinput: Implement fake input protocol in backend
The interface is redundant now since there's an abstract input backend abstraction.
This commit is contained in:
parent
0d2a66f054
commit
d6e94163f5
14 changed files with 587 additions and 978 deletions
|
@ -20,6 +20,7 @@ qt6_generate_wayland_protocol_client_sources(KWinIntegrationTestFramework
|
|||
${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-output-management-v2.xml
|
||||
${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-screen-edge-v1.xml
|
||||
${PLASMA_WAYLAND_PROTOCOLS_DIR}/zkde-screencast-unstable-v1.xml
|
||||
${PLASMA_WAYLAND_PROTOCOLS_DIR}/fake-input.xml
|
||||
)
|
||||
|
||||
target_sources(KWinIntegrationTestFramework PRIVATE
|
||||
|
@ -123,6 +124,7 @@ integrationTest(NAME testStackingOrder SRCS stacking_order_test.cpp LIBS XCB::IC
|
|||
integrationTest(NAME testDbusInterface SRCS dbus_interface_test.cpp LIBS XCB::ICCCM)
|
||||
integrationTest(NAME testXwaylandServerCrash SRCS xwaylandserver_crash_test.cpp LIBS XCB::ICCCM)
|
||||
integrationTest(NAME testXwaylandServerRestart SRCS xwaylandserver_restart_test.cpp LIBS XCB::ICCCM)
|
||||
integrationTest(NAME testFakeInput SRCS fakeinput_test.cpp)
|
||||
|
||||
qt_add_dbus_interfaces(DBUS_SRCS ${CMAKE_BINARY_DIR}/src/org.kde.kwin.VirtualKeyboard.xml)
|
||||
integrationTest(NAME testVirtualKeyboardDBus SRCS test_virtualkeyboard_dbus.cpp ${DBUS_SRCS})
|
||||
|
|
306
autotests/integration/fakeinput_test.cpp
Normal file
306
autotests/integration/fakeinput_test.cpp
Normal file
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
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>
|
||||
|
||||
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();
|
||||
|
||||
private:
|
||||
InputDevice *m_inputDevice = nullptr;
|
||||
};
|
||||
|
||||
void FakeInputTest::initTestCase()
|
||||
{
|
||||
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
|
||||
QVERIFY(waylandServer()->init(s_socketName));
|
||||
Test::setOutputConfig({
|
||||
QRect(0, 0, 1280, 1024),
|
||||
QRect(1280, 0, 1280, 1024),
|
||||
});
|
||||
|
||||
kwinApp()->start();
|
||||
QVERIFY(applicationStartedSpy.wait());
|
||||
}
|
||||
|
||||
void FakeInputTest::init()
|
||||
{
|
||||
QSignalSpy deviceAddedSpy(input(), &InputRedirection::deviceAdded);
|
||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::FakeInput));
|
||||
|
||||
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<InputRedirection::PointerButtonState>(), InputRedirection::PointerButtonPressed);
|
||||
|
||||
// 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<InputRedirection::PointerButtonState>(), InputRedirection::PointerButtonReleased);
|
||||
}
|
||||
|
||||
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<InputRedirection::PointerAxis>(), InputRedirection::PointerAxisVertical);
|
||||
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<InputRedirection::PointerAxis>(), InputRedirection::PointerAxisHorizontal);
|
||||
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<InputRedirection::KeyboardKeyState>(), InputRedirection::KeyboardKeyPressed);
|
||||
|
||||
// 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<InputRedirection::KeyboardKeyState>(), InputRedirection::KeyboardKeyReleased);
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
||||
WAYLANDTEST_MAIN(KWin::FakeInputTest)
|
||||
#include "fakeinput_test.moc"
|
|
@ -21,6 +21,7 @@
|
|||
#include <optional>
|
||||
|
||||
#include "qwayland-cursor-shape-v1.h"
|
||||
#include "qwayland-fake-input.h"
|
||||
#include "qwayland-fractional-scale-v1.h"
|
||||
#include "qwayland-idle-inhibit-unstable-v1.h"
|
||||
#include "qwayland-input-method-unstable-v1.h"
|
||||
|
@ -521,6 +522,10 @@ public:
|
|||
~CursorShapeDeviceV1() override;
|
||||
};
|
||||
|
||||
class FakeInput : public QtWayland::org_kde_kwin_fake_input
|
||||
{
|
||||
};
|
||||
|
||||
enum class AdditionalWaylandInterface {
|
||||
Seat = 1 << 0,
|
||||
Decoration = 1 << 1,
|
||||
|
@ -541,6 +546,7 @@ enum class AdditionalWaylandInterface {
|
|||
ScreencastingV1 = 1 << 16,
|
||||
ScreenEdgeV1 = 1 << 17,
|
||||
CursorShapeV1 = 1 << 18,
|
||||
FakeInput = 1 << 19,
|
||||
};
|
||||
Q_DECLARE_FLAGS(AdditionalWaylandInterfaces, AdditionalWaylandInterface)
|
||||
|
||||
|
@ -636,6 +642,7 @@ QVector<KWayland::Client::Output *> waylandOutputs();
|
|||
KWayland::Client::Output *waylandOutput(const QString &name);
|
||||
ScreencastingV1 *screencasting();
|
||||
QVector<WaylandOutputDeviceV2 *> waylandOutputDevicesV2();
|
||||
FakeInput *waylandFakeInput();
|
||||
|
||||
bool waitForWaylandSurface(Window *window);
|
||||
|
||||
|
|
|
@ -292,6 +292,7 @@ static struct
|
|||
ScreencastingV1 *screencastingV1 = nullptr;
|
||||
ScreenEdgeManagerV1 *screenEdgeManagerV1 = nullptr;
|
||||
CursorShapeManagerV1 *cursorShapeManagerV1 = nullptr;
|
||||
FakeInput *fakeInput = nullptr;
|
||||
} s_waylandConnection;
|
||||
|
||||
MockInputMethod *inputMethod()
|
||||
|
@ -477,12 +478,18 @@ bool setupWaylandConnection(AdditionalWaylandInterfaces flags)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (flags &AdditionalWaylandInterface::CursorShapeV1) {
|
||||
if (flags & AdditionalWaylandInterface::CursorShapeV1) {
|
||||
if (interface == wp_cursor_shape_manager_v1_interface.name) {
|
||||
s_waylandConnection.cursorShapeManagerV1 = new CursorShapeManagerV1();
|
||||
s_waylandConnection.cursorShapeManagerV1->init(*registry, name, version);
|
||||
}
|
||||
}
|
||||
if (flags & AdditionalWaylandInterface::FakeInput) {
|
||||
if (interface == org_kde_kwin_fake_input_interface.name) {
|
||||
s_waylandConnection.fakeInput = new FakeInput();
|
||||
s_waylandConnection.fakeInput->init(*registry, name, version);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
QSignalSpy allAnnounced(registry, &KWayland::Client::Registry::interfacesAnnounced);
|
||||
|
@ -615,6 +622,8 @@ void destroyWaylandConnection()
|
|||
s_waylandConnection.screenEdgeManagerV1 = nullptr;
|
||||
delete s_waylandConnection.cursorShapeManagerV1;
|
||||
s_waylandConnection.cursorShapeManagerV1 = nullptr;
|
||||
delete s_waylandConnection.fakeInput;
|
||||
s_waylandConnection.fakeInput = nullptr;
|
||||
|
||||
delete s_waylandConnection.queue; // Must be destroyed last
|
||||
s_waylandConnection.queue = nullptr;
|
||||
|
@ -726,6 +735,11 @@ QVector<KWin::Test::WaylandOutputDeviceV2 *> waylandOutputDevicesV2()
|
|||
return s_waylandConnection.outputDevicesV2;
|
||||
}
|
||||
|
||||
FakeInput *waylandFakeInput()
|
||||
{
|
||||
return s_waylandConnection.fakeInput;
|
||||
}
|
||||
|
||||
bool waitForWaylandSurface(Window *window)
|
||||
{
|
||||
if (window->surface()) {
|
||||
|
|
|
@ -6,30 +6,250 @@
|
|||
|
||||
#include "fakeinputbackend.h"
|
||||
#include "fakeinputdevice.h"
|
||||
#include "wayland/fakeinput.h"
|
||||
#include "wayland_server.h"
|
||||
#include "wayland/display.h"
|
||||
|
||||
#include "wayland/qwayland-server-fake-input.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
FakeInputBackend::FakeInputBackend() = default;
|
||||
static const quint32 s_version = 4;
|
||||
|
||||
class FakeInputBackendPrivate : public QtWaylandServer::org_kde_kwin_fake_input
|
||||
{
|
||||
public:
|
||||
FakeInputBackendPrivate(FakeInputBackend *q, Display *display);
|
||||
|
||||
FakeInputDevice *findDevice(Resource *resource);
|
||||
std::chrono::microseconds currentTime() const;
|
||||
|
||||
FakeInputBackend *q;
|
||||
Display *display;
|
||||
std::map<Resource *, std::unique_ptr<FakeInputDevice>> devices;
|
||||
static QList<quint32> touchIds;
|
||||
|
||||
protected:
|
||||
void org_kde_kwin_fake_input_bind_resource(Resource *resource) override;
|
||||
void org_kde_kwin_fake_input_destroy_resource(Resource *resource) override;
|
||||
void org_kde_kwin_fake_input_authenticate(Resource *resource, const QString &application, const QString &reason) override;
|
||||
void org_kde_kwin_fake_input_pointer_motion(Resource *resource, wl_fixed_t delta_x, wl_fixed_t delta_y) override;
|
||||
void org_kde_kwin_fake_input_button(Resource *resource, uint32_t button, uint32_t state) override;
|
||||
void org_kde_kwin_fake_input_axis(Resource *resource, uint32_t axis, wl_fixed_t value) override;
|
||||
void org_kde_kwin_fake_input_touch_down(Resource *resource, uint32_t id, wl_fixed_t x, wl_fixed_t y) override;
|
||||
void org_kde_kwin_fake_input_touch_motion(Resource *resource, uint32_t id, wl_fixed_t x, wl_fixed_t y) override;
|
||||
void org_kde_kwin_fake_input_touch_up(Resource *resource, uint32_t id) override;
|
||||
void org_kde_kwin_fake_input_touch_cancel(Resource *resource) override;
|
||||
void org_kde_kwin_fake_input_touch_frame(Resource *resource) override;
|
||||
void org_kde_kwin_fake_input_pointer_motion_absolute(Resource *resource, wl_fixed_t x, wl_fixed_t y) override;
|
||||
void org_kde_kwin_fake_input_keyboard_key(Resource *resource, uint32_t button, uint32_t state) override;
|
||||
};
|
||||
|
||||
QList<quint32> FakeInputBackendPrivate::touchIds = QList<quint32>();
|
||||
|
||||
FakeInputBackendPrivate::FakeInputBackendPrivate(FakeInputBackend *q, Display *display)
|
||||
: q(q)
|
||||
, display(display)
|
||||
{
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_bind_resource(Resource *resource)
|
||||
{
|
||||
auto device = new FakeInputDevice(q);
|
||||
devices[resource] = std::unique_ptr<FakeInputDevice>(device);
|
||||
Q_EMIT q->deviceAdded(device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_destroy_resource(Resource *resource)
|
||||
{
|
||||
auto it = devices.find(resource);
|
||||
if (it != devices.end()) {
|
||||
const auto [resource, device] = std::move(*it);
|
||||
devices.erase(it);
|
||||
Q_EMIT q->deviceRemoved(device.get());
|
||||
}
|
||||
}
|
||||
|
||||
FakeInputDevice *FakeInputBackendPrivate::findDevice(Resource *resource)
|
||||
{
|
||||
return devices[resource].get();
|
||||
}
|
||||
|
||||
std::chrono::microseconds FakeInputBackendPrivate::currentTime() const
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_authenticate(Resource *resource, const QString &application, const QString &reason)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (device) {
|
||||
// TODO: make secure
|
||||
device->setAuthenticated(true);
|
||||
}
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_pointer_motion(Resource *resource, wl_fixed_t delta_x, wl_fixed_t delta_y)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
const QPointF delta(wl_fixed_to_double(delta_x), wl_fixed_to_double(delta_y));
|
||||
|
||||
Q_EMIT device->pointerMotion(delta, delta, currentTime(), device);
|
||||
Q_EMIT device->pointerFrame(device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_button(Resource *resource, uint32_t button, uint32_t state)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
InputRedirection::PointerButtonState nativeState;
|
||||
switch (state) {
|
||||
case WL_POINTER_BUTTON_STATE_PRESSED:
|
||||
nativeState = InputRedirection::PointerButtonPressed;
|
||||
break;
|
||||
case WL_POINTER_BUTTON_STATE_RELEASED:
|
||||
nativeState = InputRedirection::PointerButtonReleased;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT device->pointerButtonChanged(button, nativeState, currentTime(), device);
|
||||
Q_EMIT device->pointerFrame(device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_axis(Resource *resource, uint32_t axis, wl_fixed_t value)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
InputRedirection::PointerAxis nativeAxis;
|
||||
switch (axis) {
|
||||
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
||||
nativeAxis = InputRedirection::PointerAxisHorizontal;
|
||||
break;
|
||||
|
||||
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
||||
nativeAxis = InputRedirection::PointerAxisVertical;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT device->pointerAxisChanged(nativeAxis, wl_fixed_to_double(value), 0, InputRedirection::PointerAxisSourceUnknown, currentTime(), device);
|
||||
Q_EMIT device->pointerFrame(device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_touch_down(Resource *resource, uint32_t id, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
if (touchIds.contains(id)) {
|
||||
return;
|
||||
}
|
||||
touchIds << id;
|
||||
Q_EMIT device->touchDown(id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), currentTime(), device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_touch_motion(Resource *resource, uint32_t id, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
if (!touchIds.contains(id)) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT device->touchMotion(id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), currentTime(), device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_touch_up(Resource *resource, uint32_t id)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
if (!touchIds.contains(id)) {
|
||||
return;
|
||||
}
|
||||
touchIds.removeOne(id);
|
||||
Q_EMIT device->touchUp(id, currentTime(), device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_touch_cancel(Resource *resource)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
touchIds.clear();
|
||||
Q_EMIT device->touchCanceled(device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_touch_frame(Resource *resource)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT device->touchFrame(device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_pointer_motion_absolute(Resource *resource, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT device->pointerMotionAbsolute(QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), currentTime(), device);
|
||||
Q_EMIT device->pointerFrame(device);
|
||||
}
|
||||
|
||||
void FakeInputBackendPrivate::org_kde_kwin_fake_input_keyboard_key(Resource *resource, uint32_t button, uint32_t state)
|
||||
{
|
||||
FakeInputDevice *device = findDevice(resource);
|
||||
if (!device->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
InputRedirection::KeyboardKeyState nativeState;
|
||||
switch (state) {
|
||||
case WL_KEYBOARD_KEY_STATE_PRESSED:
|
||||
nativeState = InputRedirection::KeyboardKeyPressed;
|
||||
break;
|
||||
|
||||
case WL_KEYBOARD_KEY_STATE_RELEASED:
|
||||
nativeState = InputRedirection::KeyboardKeyReleased;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT device->keyChanged(button, nativeState, currentTime(), device);
|
||||
}
|
||||
|
||||
FakeInputBackend::FakeInputBackend(Display *display)
|
||||
: d(std::make_unique<FakeInputBackendPrivate>(this, display))
|
||||
{
|
||||
}
|
||||
|
||||
FakeInputBackend::~FakeInputBackend() = default;
|
||||
|
||||
void FakeInputBackend::initialize()
|
||||
{
|
||||
m_interface = std::make_unique<FakeInputInterface>(waylandServer()->display());
|
||||
connect(m_interface.get(), &FakeInputInterface::deviceCreated, this, [this](FakeInputDeviceInterface *fakeDevice) {
|
||||
m_devices[fakeDevice] = std::make_unique<FakeInputDevice>(fakeDevice);
|
||||
Q_EMIT deviceAdded(m_devices[fakeDevice].get());
|
||||
});
|
||||
connect(m_interface.get(), &FakeInputInterface::deviceDestroyed, this, [this](FakeInputDeviceInterface *fakeDevice) {
|
||||
auto it = m_devices.find(fakeDevice);
|
||||
if (it != m_devices.end()) {
|
||||
const std::unique_ptr<FakeInputDevice> device = std::move(it->second);
|
||||
m_devices.erase(it);
|
||||
Q_EMIT deviceRemoved(device.get());
|
||||
}
|
||||
});
|
||||
d->init(*d->display, s_version);
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -14,23 +14,22 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
class Display;
|
||||
class FakeInputBackendPrivate;
|
||||
class FakeInputDevice;
|
||||
class FakeInputInterface;
|
||||
class FakeInputDeviceInterface;
|
||||
|
||||
class FakeInputBackend : public InputBackend
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FakeInputBackend();
|
||||
explicit FakeInputBackend(Display *display);
|
||||
~FakeInputBackend();
|
||||
|
||||
void initialize() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<FakeInputInterface> m_interface;
|
||||
std::map<FakeInputDeviceInterface *, std::unique_ptr<FakeInputDevice>> m_devices;
|
||||
std::unique_ptr<FakeInputBackendPrivate> d;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -5,83 +5,25 @@
|
|||
*/
|
||||
|
||||
#include "fakeinputdevice.h"
|
||||
#include "wayland/fakeinput.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
static int s_lastDeviceId = 0;
|
||||
|
||||
FakeInputDevice::FakeInputDevice(FakeInputDeviceInterface *device, QObject *parent)
|
||||
FakeInputDevice::FakeInputDevice(QObject *parent)
|
||||
: InputDevice(parent)
|
||||
, m_name(QStringLiteral("Fake Input Device %1").arg(++s_lastDeviceId))
|
||||
{
|
||||
connect(device, &FakeInputDeviceInterface::authenticationRequested, this, [device](const QString &application, const QString &reason) {
|
||||
// TODO: make secure
|
||||
device->setAuthentication(true);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::pointerMotionRequested, this, [this](const QPointF &delta) {
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT pointerMotion(delta, delta, time, this);
|
||||
Q_EMIT pointerFrame(this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::pointerMotionAbsoluteRequested, this, [this](const QPointF &pos) {
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT pointerMotionAbsolute(pos, time, this);
|
||||
Q_EMIT pointerFrame(this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::pointerButtonPressRequested, this, [this](quint32 button) {
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT pointerButtonChanged(button, InputRedirection::PointerButtonPressed, time, this);
|
||||
Q_EMIT pointerFrame(this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::pointerButtonReleaseRequested, this, [this](quint32 button) {
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT pointerButtonChanged(button, InputRedirection::PointerButtonReleased, time, this);
|
||||
Q_EMIT pointerFrame(this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::pointerAxisRequested, this, [this](Qt::Orientation orientation, qreal delta) {
|
||||
InputRedirection::PointerAxis axis;
|
||||
switch (orientation) {
|
||||
case Qt::Horizontal:
|
||||
axis = InputRedirection::PointerAxisHorizontal;
|
||||
break;
|
||||
case Qt::Vertical:
|
||||
axis = InputRedirection::PointerAxisVertical;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT pointerAxisChanged(axis, delta, 0, InputRedirection::PointerAxisSourceUnknown, time, this);
|
||||
Q_EMIT pointerFrame(this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::touchDownRequested, this, [this](qint32 id, const QPointF &pos) {
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT touchDown(id, pos, time, this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::touchMotionRequested, this, [this](qint32 id, const QPointF &pos) {
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT touchMotion(id, pos, time, this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::touchUpRequested, this, [this](qint32 id) {
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT touchUp(id, time, this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::touchCancelRequested, this, [this]() {
|
||||
Q_EMIT touchCanceled(this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::touchFrameRequested, this, [this]() {
|
||||
Q_EMIT touchFrame(this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::keyboardKeyPressRequested, this, [this](quint32 button) {
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT keyChanged(button, InputRedirection::KeyboardKeyPressed, time, this);
|
||||
});
|
||||
connect(device, &FakeInputDeviceInterface::keyboardKeyReleaseRequested, this, [this](quint32 button) {
|
||||
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
Q_EMIT keyChanged(button, InputRedirection::KeyboardKeyReleased, time, this);
|
||||
});
|
||||
}
|
||||
|
||||
bool FakeInputDevice::isAuthenticated() const
|
||||
{
|
||||
return m_authenticated;
|
||||
}
|
||||
|
||||
void FakeInputDevice::setAuthenticated(bool authenticated)
|
||||
{
|
||||
m_authenticated = authenticated;
|
||||
}
|
||||
|
||||
QString FakeInputDevice::sysName() const
|
||||
|
|
|
@ -11,14 +11,12 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
class FakeInputDeviceInterface;
|
||||
|
||||
class KWIN_EXPORT FakeInputDevice : public InputDevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FakeInputDevice(FakeInputDeviceInterface *device, QObject *parent = nullptr);
|
||||
explicit FakeInputDevice(QObject *parent = nullptr);
|
||||
|
||||
QString sysName() const override;
|
||||
QString name() const override;
|
||||
|
@ -39,8 +37,12 @@ public:
|
|||
bool isTabletModeSwitch() const override;
|
||||
bool isLidSwitch() const override;
|
||||
|
||||
void setAuthenticated(bool authenticated);
|
||||
bool isAuthenticated() const;
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
bool m_authenticated = false;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -3139,7 +3139,7 @@ void InputRedirection::setupInputBackends()
|
|||
addInputBackend(std::move(inputBackend));
|
||||
}
|
||||
if (waylandServer()) {
|
||||
addInputBackend(std::make_unique<FakeInputBackend>());
|
||||
addInputBackend(std::make_unique<FakeInputBackend>(waylandServer()->display()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -244,7 +244,6 @@ target_sources(kwin PRIVATE
|
|||
dpms.cpp
|
||||
drmclientbuffer.cpp
|
||||
drmlease_v1.cpp
|
||||
fakeinput.cpp
|
||||
fractionalscale_v1.cpp
|
||||
filtered_display.cpp
|
||||
idle.cpp
|
||||
|
@ -327,7 +326,6 @@ install(FILES
|
|||
datasource.h
|
||||
dpms.h
|
||||
drmlease_v1.h
|
||||
fakeinput.h
|
||||
fractionalscale_v1.h
|
||||
idle.h
|
||||
idleinhibit_v1.h
|
||||
|
|
|
@ -168,17 +168,6 @@ target_link_libraries( testShadow Qt::Test Qt::Gui KF6::WaylandClient kwin)
|
|||
add_test(NAME kwayland-testShadow COMMAND testShadow)
|
||||
ecm_mark_as_test(testShadow)
|
||||
|
||||
########################################################
|
||||
# Test FakeInput
|
||||
########################################################
|
||||
set( testFakeInput_SRCS
|
||||
test_fake_input.cpp
|
||||
)
|
||||
add_executable(testFakeInput ${testFakeInput_SRCS})
|
||||
target_link_libraries( testFakeInput Qt::Test Qt::Gui KF6::WaylandClient kwin)
|
||||
add_test(NAME kwayland-testFakeInput COMMAND testFakeInput)
|
||||
ecm_mark_as_test(testFakeInput)
|
||||
|
||||
########################################################
|
||||
# Test TextInputV2
|
||||
########################################################
|
||||
|
|
|
@ -1,448 +0,0 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
// Qt
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
// client
|
||||
#include "KWayland/Client/connection_thread.h"
|
||||
#include "KWayland/Client/event_queue.h"
|
||||
#include "KWayland/Client/fakeinput.h"
|
||||
#include "KWayland/Client/registry.h"
|
||||
// server
|
||||
#include "wayland/display.h"
|
||||
#include "wayland/fakeinput.h"
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
using namespace KWin;
|
||||
|
||||
Q_DECLARE_METATYPE(Qt::MouseButton)
|
||||
|
||||
class FakeInputTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private Q_SLOTS:
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
void testAuthenticate();
|
||||
void testMotion();
|
||||
void testMotionAbsolute();
|
||||
void testPointerButtonQt_data();
|
||||
void testPointerButtonQt();
|
||||
void testPointerButtonLinux_data();
|
||||
void testPointerButtonLinux();
|
||||
void testAxis_data();
|
||||
void testAxis();
|
||||
void testTouch();
|
||||
void testKeyboardKeyLinux_data();
|
||||
void testKeyboardKeyLinux();
|
||||
|
||||
private:
|
||||
KWin::Display *m_display = nullptr;
|
||||
FakeInputInterface *m_fakeInputInterface = nullptr;
|
||||
FakeInputDeviceInterface *m_device = nullptr;
|
||||
KWayland::Client::ConnectionThread *m_connection = nullptr;
|
||||
QThread *m_thread = nullptr;
|
||||
KWayland::Client::EventQueue *m_queue = nullptr;
|
||||
KWayland::Client::FakeInput *m_fakeInput = nullptr;
|
||||
};
|
||||
|
||||
static const QString s_socketName = QStringLiteral("kwayland-test-fake-input-0");
|
||||
|
||||
void FakeInputTest::init()
|
||||
{
|
||||
delete m_display;
|
||||
m_display = new KWin::Display(this);
|
||||
m_display->addSocketName(s_socketName);
|
||||
m_display->start();
|
||||
QVERIFY(m_display->isRunning());
|
||||
m_display->createShm();
|
||||
m_fakeInputInterface = new FakeInputInterface(m_display);
|
||||
QSignalSpy deviceCreatedSpy(m_fakeInputInterface, &FakeInputInterface::deviceCreated);
|
||||
|
||||
// setup connection
|
||||
m_connection = new KWayland::Client::ConnectionThread;
|
||||
QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
|
||||
m_connection->setSocketName(s_socketName);
|
||||
|
||||
m_thread = new QThread(this);
|
||||
m_connection->moveToThread(m_thread);
|
||||
m_thread->start();
|
||||
|
||||
m_connection->initConnection();
|
||||
QVERIFY(connectedSpy.wait());
|
||||
|
||||
m_queue = new KWayland::Client::EventQueue(this);
|
||||
m_queue->setup(m_connection);
|
||||
|
||||
KWayland::Client::Registry registry;
|
||||
QSignalSpy interfacesAnnouncedSpy(®istry, &KWayland::Client::Registry::interfacesAnnounced);
|
||||
registry.setEventQueue(m_queue);
|
||||
registry.create(m_connection);
|
||||
QVERIFY(registry.isValid());
|
||||
registry.setup();
|
||||
QVERIFY(interfacesAnnouncedSpy.wait());
|
||||
|
||||
m_fakeInput =
|
||||
registry.createFakeInput(registry.interface(KWayland::Client::Registry::Interface::FakeInput).name, registry.interface(KWayland::Client::Registry::Interface::FakeInput).version, this);
|
||||
QVERIFY(m_fakeInput->isValid());
|
||||
|
||||
QVERIFY(deviceCreatedSpy.wait());
|
||||
m_device = deviceCreatedSpy.first().first().value<FakeInputDeviceInterface *>();
|
||||
QVERIFY(m_device);
|
||||
}
|
||||
|
||||
void FakeInputTest::cleanup()
|
||||
{
|
||||
#define CLEANUP(variable) \
|
||||
if (variable) { \
|
||||
delete variable; \
|
||||
variable = nullptr; \
|
||||
}
|
||||
CLEANUP(m_fakeInput)
|
||||
CLEANUP(m_queue)
|
||||
if (m_connection) {
|
||||
m_connection->deleteLater();
|
||||
m_connection = nullptr;
|
||||
}
|
||||
if (m_thread) {
|
||||
m_thread->quit();
|
||||
m_thread->wait();
|
||||
delete m_thread;
|
||||
m_thread = nullptr;
|
||||
}
|
||||
|
||||
CLEANUP(m_display)
|
||||
#undef CLEANUP
|
||||
|
||||
// these are the children of the display
|
||||
m_fakeInputInterface = nullptr;
|
||||
}
|
||||
|
||||
void FakeInputTest::testAuthenticate()
|
||||
{
|
||||
// this test verifies that an authenticate request is passed to the Server
|
||||
QVERIFY(!m_device->isAuthenticated());
|
||||
QSignalSpy authenticationRequestedSpy(m_device, &FakeInputDeviceInterface::authenticationRequested);
|
||||
|
||||
m_fakeInput->authenticate(QStringLiteral("test-case"), QStringLiteral("to test"));
|
||||
QVERIFY(authenticationRequestedSpy.wait());
|
||||
QCOMPARE(authenticationRequestedSpy.count(), 1);
|
||||
QCOMPARE(authenticationRequestedSpy.first().at(0).toString(), QStringLiteral("test-case"));
|
||||
QCOMPARE(authenticationRequestedSpy.first().at(1).toString(), QStringLiteral("to test"));
|
||||
m_device->setAuthentication(true);
|
||||
QVERIFY(m_device->isAuthenticated());
|
||||
}
|
||||
|
||||
void FakeInputTest::testMotion()
|
||||
{
|
||||
// this test verifies that motion is properly passed to the server
|
||||
QVERIFY(!m_device->isAuthenticated());
|
||||
QSignalSpy motionSpy(m_device, &FakeInputDeviceInterface::pointerMotionRequested);
|
||||
|
||||
// without an authentication we shouldn't get the signals
|
||||
m_fakeInput->requestPointerMove(QSizeF(1, 2));
|
||||
QVERIFY(!motionSpy.wait(100));
|
||||
|
||||
// now let's authenticate the interface
|
||||
m_device->setAuthentication(true);
|
||||
m_fakeInput->requestPointerMove(QSizeF(1, 2));
|
||||
QVERIFY(motionSpy.wait());
|
||||
QCOMPARE(motionSpy.count(), 1);
|
||||
QCOMPARE(motionSpy.last().first().toPointF(), QPointF(1, 2));
|
||||
|
||||
// just for the fun: once more
|
||||
m_fakeInput->requestPointerMove(QSizeF(0, 0));
|
||||
QVERIFY(motionSpy.wait());
|
||||
QCOMPARE(motionSpy.count(), 2);
|
||||
QCOMPARE(motionSpy.last().first().toPointF(), QPointF(0, 0));
|
||||
}
|
||||
|
||||
void FakeInputTest::testMotionAbsolute()
|
||||
{
|
||||
// this test verifies that motion is properly passed to the server
|
||||
QVERIFY(!m_device->isAuthenticated());
|
||||
QSignalSpy motionSpy(m_device, &FakeInputDeviceInterface::pointerMotionAbsoluteRequested);
|
||||
|
||||
// without an authentication we shouldn't get the signals
|
||||
m_fakeInput->requestPointerMoveAbsolute(QPointF(1, 2));
|
||||
QVERIFY(!motionSpy.wait(100));
|
||||
|
||||
// now let's authenticate the interface
|
||||
m_device->setAuthentication(true);
|
||||
m_fakeInput->requestPointerMoveAbsolute(QPointF(1, 2));
|
||||
QVERIFY(motionSpy.wait());
|
||||
QCOMPARE(motionSpy.count(), 1);
|
||||
QCOMPARE(motionSpy.last().first().toPointF(), QPointF(1, 2));
|
||||
|
||||
// just for the fun: once more
|
||||
m_fakeInput->requestPointerMoveAbsolute(QPointF(0, 0));
|
||||
QVERIFY(motionSpy.wait());
|
||||
QCOMPARE(motionSpy.count(), 2);
|
||||
QCOMPARE(motionSpy.last().first().toPointF(), QPointF(0, 0));
|
||||
}
|
||||
|
||||
void FakeInputTest::testPointerButtonQt_data()
|
||||
{
|
||||
QTest::addColumn<Qt::MouseButton>("qtButton");
|
||||
QTest::addColumn<quint32>("linuxButton");
|
||||
|
||||
QTest::newRow("left") << Qt::LeftButton << quint32(BTN_LEFT);
|
||||
QTest::newRow("right") << Qt::RightButton << quint32(BTN_RIGHT);
|
||||
QTest::newRow("middle") << Qt::MiddleButton << quint32(BTN_MIDDLE);
|
||||
}
|
||||
|
||||
void FakeInputTest::testPointerButtonQt()
|
||||
{
|
||||
// this test verifies that pointer button events are properly passed to the server with Qt button codes
|
||||
QVERIFY(!m_device->isAuthenticated());
|
||||
QSignalSpy pressedSpy(m_device, &FakeInputDeviceInterface::pointerButtonPressRequested);
|
||||
QSignalSpy releasedSpy(m_device, &FakeInputDeviceInterface::pointerButtonReleaseRequested);
|
||||
|
||||
// without an authentication we shouldn't get the signals
|
||||
QFETCH(Qt::MouseButton, qtButton);
|
||||
m_fakeInput->requestPointerButtonClick(qtButton);
|
||||
QVERIFY(!pressedSpy.wait(100));
|
||||
QVERIFY(pressedSpy.isEmpty());
|
||||
QVERIFY(releasedSpy.isEmpty());
|
||||
|
||||
// now authenticate
|
||||
m_device->setAuthentication(true);
|
||||
// now our click should work
|
||||
m_fakeInput->requestPointerButtonClick(qtButton);
|
||||
QVERIFY(releasedSpy.wait());
|
||||
QCOMPARE(pressedSpy.count(), 1);
|
||||
QCOMPARE(releasedSpy.count(), 1);
|
||||
QTEST(pressedSpy.last().first().value<quint32>(), "linuxButton");
|
||||
QTEST(releasedSpy.last().first().value<quint32>(), "linuxButton");
|
||||
|
||||
// and a press/release "manually"
|
||||
m_fakeInput->requestPointerButtonPress(qtButton);
|
||||
QVERIFY(pressedSpy.wait());
|
||||
QCOMPARE(pressedSpy.count(), 2);
|
||||
QCOMPARE(releasedSpy.count(), 1);
|
||||
QTEST(pressedSpy.last().first().value<quint32>(), "linuxButton");
|
||||
// and release
|
||||
m_fakeInput->requestPointerButtonRelease(qtButton);
|
||||
QVERIFY(releasedSpy.wait());
|
||||
QCOMPARE(pressedSpy.count(), 2);
|
||||
QCOMPARE(releasedSpy.count(), 2);
|
||||
QTEST(releasedSpy.last().first().value<quint32>(), "linuxButton");
|
||||
}
|
||||
|
||||
void FakeInputTest::testPointerButtonLinux_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::testPointerButtonLinux()
|
||||
{
|
||||
// this test verifies that pointer button events are properly passed to the server with Qt button codes
|
||||
QVERIFY(!m_device->isAuthenticated());
|
||||
QSignalSpy pressedSpy(m_device, &FakeInputDeviceInterface::pointerButtonPressRequested);
|
||||
QSignalSpy releasedSpy(m_device, &FakeInputDeviceInterface::pointerButtonReleaseRequested);
|
||||
|
||||
// without an authentication we shouldn't get the signals
|
||||
QFETCH(quint32, linuxButton);
|
||||
m_fakeInput->requestPointerButtonClick(linuxButton);
|
||||
QVERIFY(!pressedSpy.wait(100));
|
||||
QVERIFY(pressedSpy.isEmpty());
|
||||
QVERIFY(releasedSpy.isEmpty());
|
||||
|
||||
// now authenticate
|
||||
m_device->setAuthentication(true);
|
||||
// now our click should work
|
||||
m_fakeInput->requestPointerButtonClick(linuxButton);
|
||||
QVERIFY(releasedSpy.wait());
|
||||
QCOMPARE(pressedSpy.count(), 1);
|
||||
QCOMPARE(releasedSpy.count(), 1);
|
||||
QTEST(pressedSpy.last().first().value<quint32>(), "linuxButton");
|
||||
QTEST(releasedSpy.last().first().value<quint32>(), "linuxButton");
|
||||
|
||||
// and a press/release "manually"
|
||||
m_fakeInput->requestPointerButtonPress(linuxButton);
|
||||
QVERIFY(pressedSpy.wait());
|
||||
QCOMPARE(pressedSpy.count(), 2);
|
||||
QCOMPARE(releasedSpy.count(), 1);
|
||||
QTEST(pressedSpy.last().first().value<quint32>(), "linuxButton");
|
||||
// and release
|
||||
m_fakeInput->requestPointerButtonRelease(linuxButton);
|
||||
QVERIFY(releasedSpy.wait());
|
||||
QCOMPARE(pressedSpy.count(), 2);
|
||||
QCOMPARE(releasedSpy.count(), 2);
|
||||
QTEST(releasedSpy.last().first().value<quint32>(), "linuxButton");
|
||||
}
|
||||
|
||||
void FakeInputTest::testAxis_data()
|
||||
{
|
||||
QTest::addColumn<Qt::Orientation>("orientation");
|
||||
QTest::addColumn<qreal>("delta");
|
||||
|
||||
QTest::newRow("horizontal/1") << Qt::Horizontal << 1.0;
|
||||
QTest::newRow("horizontal/-2") << Qt::Horizontal << -2.0;
|
||||
QTest::newRow("vertical/10") << Qt::Vertical << 10.0;
|
||||
QTest::newRow("vertical/-20") << Qt::Vertical << -22.0;
|
||||
}
|
||||
|
||||
void FakeInputTest::testAxis()
|
||||
{
|
||||
// this test verifies that pointer axis events are properly passed to the server
|
||||
QVERIFY(!m_device->isAuthenticated());
|
||||
QSignalSpy axisSpy(m_device, &FakeInputDeviceInterface::pointerAxisRequested);
|
||||
|
||||
QFETCH(Qt::Orientation, orientation);
|
||||
QFETCH(qreal, delta);
|
||||
// without an authentication we shouldn't get the signals
|
||||
m_fakeInput->requestPointerAxis(orientation, delta);
|
||||
QVERIFY(!axisSpy.wait(100));
|
||||
|
||||
// now authenticate
|
||||
m_device->setAuthentication(true);
|
||||
|
||||
// now we can properly test
|
||||
m_fakeInput->requestPointerAxis(orientation, delta);
|
||||
QVERIFY(axisSpy.wait());
|
||||
QCOMPARE(axisSpy.count(), 1);
|
||||
QCOMPARE(axisSpy.first().at(0).value<Qt::Orientation>(), orientation);
|
||||
QCOMPARE(axisSpy.first().at(1).value<qreal>(), delta);
|
||||
}
|
||||
|
||||
void FakeInputTest::testTouch()
|
||||
{
|
||||
QVERIFY(!m_device->isAuthenticated());
|
||||
QSignalSpy touchDownSpy(m_device, &FakeInputDeviceInterface::touchDownRequested);
|
||||
QSignalSpy touchMotionSpy(m_device, &FakeInputDeviceInterface::touchMotionRequested);
|
||||
QSignalSpy touchUpSpy(m_device, &FakeInputDeviceInterface::touchUpRequested);
|
||||
QSignalSpy touchFrameSpy(m_device, &FakeInputDeviceInterface::touchFrameRequested);
|
||||
QSignalSpy touchCancelSpy(m_device, &FakeInputDeviceInterface::touchCancelRequested);
|
||||
|
||||
// without an authentication we shouldn't get the signals
|
||||
m_fakeInput->requestTouchDown(0, QPointF(1, 2));
|
||||
QVERIFY(!touchDownSpy.wait(100));
|
||||
|
||||
m_fakeInput->requestTouchMotion(0, QPointF(3, 4));
|
||||
QVERIFY(!touchMotionSpy.wait(100));
|
||||
|
||||
m_fakeInput->requestTouchUp(0);
|
||||
QVERIFY(!touchUpSpy.wait(100));
|
||||
|
||||
m_fakeInput->requestTouchDown(1, QPointF(5, 6));
|
||||
QVERIFY(!touchDownSpy.wait(100));
|
||||
|
||||
m_fakeInput->requestTouchFrame();
|
||||
QVERIFY(!touchFrameSpy.wait(100));
|
||||
|
||||
m_fakeInput->requestTouchCancel();
|
||||
QVERIFY(!touchCancelSpy.wait(100));
|
||||
|
||||
// now let's authenticate the interface
|
||||
m_device->setAuthentication(true);
|
||||
m_fakeInput->requestTouchDown(0, QPointF(1, 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.
|
||||
m_fakeInput->requestTouchDown(0, QPointF(5, 6));
|
||||
QVERIFY(!touchDownSpy.wait(100));
|
||||
|
||||
m_fakeInput->requestTouchMotion(0, QPointF(3, 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.
|
||||
m_fakeInput->requestTouchMotion(1, QPointF(3, 4));
|
||||
QVERIFY(!touchMotionSpy.wait(100));
|
||||
|
||||
m_fakeInput->requestTouchUp(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.
|
||||
m_fakeInput->requestTouchUp(1);
|
||||
QVERIFY(!touchUpSpy.wait(100));
|
||||
|
||||
m_fakeInput->requestTouchDown(1, QPointF(5, 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));
|
||||
|
||||
m_fakeInput->requestTouchFrame();
|
||||
QVERIFY(touchFrameSpy.wait());
|
||||
QCOMPARE(touchFrameSpy.count(), 1);
|
||||
|
||||
m_fakeInput->requestTouchCancel();
|
||||
QVERIFY(touchCancelSpy.wait());
|
||||
QCOMPARE(touchCancelSpy.count(), 1);
|
||||
}
|
||||
|
||||
void FakeInputTest::testKeyboardKeyLinux_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::testKeyboardKeyLinux()
|
||||
{
|
||||
// this test verifies that keyboard key events are properly passed to the server with Qt button codes
|
||||
QVERIFY(!m_device->isAuthenticated());
|
||||
QSignalSpy pressedSpy(m_device, &FakeInputDeviceInterface::keyboardKeyPressRequested);
|
||||
QSignalSpy releasedSpy(m_device, &FakeInputDeviceInterface::keyboardKeyReleaseRequested);
|
||||
|
||||
// without an authentication we shouldn't get the signals
|
||||
QFETCH(quint32, linuxKey);
|
||||
m_fakeInput->requestKeyboardKeyPress(linuxKey);
|
||||
m_fakeInput->requestKeyboardKeyRelease(linuxKey);
|
||||
QVERIFY(!pressedSpy.wait(100));
|
||||
QVERIFY(pressedSpy.isEmpty());
|
||||
QVERIFY(releasedSpy.isEmpty());
|
||||
|
||||
// now authenticate
|
||||
m_device->setAuthentication(true);
|
||||
// now our click should work
|
||||
m_fakeInput->requestKeyboardKeyPress(linuxKey);
|
||||
m_fakeInput->requestKeyboardKeyRelease(linuxKey);
|
||||
QVERIFY(releasedSpy.wait());
|
||||
QCOMPARE(pressedSpy.count(), 1);
|
||||
QCOMPARE(releasedSpy.count(), 1);
|
||||
QTEST(pressedSpy.last().first().value<quint32>(), "linuxKey");
|
||||
QTEST(releasedSpy.last().first().value<quint32>(), "linuxKey");
|
||||
|
||||
// and a press/release "manually"
|
||||
m_fakeInput->requestKeyboardKeyPress(linuxKey);
|
||||
QVERIFY(pressedSpy.wait());
|
||||
QCOMPARE(pressedSpy.count(), 2);
|
||||
QCOMPARE(releasedSpy.count(), 1);
|
||||
QTEST(pressedSpy.last().first().value<quint32>(), "linuxKey");
|
||||
// and release
|
||||
m_fakeInput->requestKeyboardKeyRelease(linuxKey);
|
||||
QVERIFY(releasedSpy.wait());
|
||||
QCOMPARE(pressedSpy.count(), 2);
|
||||
QCOMPARE(releasedSpy.count(), 2);
|
||||
QTEST(releasedSpy.last().first().value<quint32>(), "linuxKey");
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(FakeInputTest)
|
||||
#include "test_fake_input.moc"
|
|
@ -1,266 +0,0 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "fakeinput.h"
|
||||
#include "display.h"
|
||||
|
||||
#include <QPointF>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <qwayland-server-fake-input.h>
|
||||
#include <wayland-server.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
static const quint32 s_version = 4;
|
||||
|
||||
class FakeInputInterfacePrivate : public QtWaylandServer::org_kde_kwin_fake_input
|
||||
{
|
||||
public:
|
||||
FakeInputInterfacePrivate(FakeInputInterface *_q, Display *display);
|
||||
std::map<wl_resource *, std::unique_ptr<FakeInputDeviceInterface>> devices;
|
||||
|
||||
private:
|
||||
FakeInputDeviceInterface *device(wl_resource *r);
|
||||
|
||||
FakeInputInterface *q;
|
||||
static QList<quint32> touchIds;
|
||||
|
||||
protected:
|
||||
void org_kde_kwin_fake_input_bind_resource(Resource *resource) override;
|
||||
void org_kde_kwin_fake_input_destroy_resource(Resource *resource) override;
|
||||
void org_kde_kwin_fake_input_authenticate(Resource *resource, const QString &application, const QString &reason) override;
|
||||
void org_kde_kwin_fake_input_pointer_motion(Resource *resource, wl_fixed_t delta_x, wl_fixed_t delta_y) override;
|
||||
void org_kde_kwin_fake_input_button(Resource *resource, uint32_t button, uint32_t state) override;
|
||||
void org_kde_kwin_fake_input_axis(Resource *resource, uint32_t axis, wl_fixed_t value) override;
|
||||
void org_kde_kwin_fake_input_touch_down(Resource *resource, uint32_t id, wl_fixed_t x, wl_fixed_t y) override;
|
||||
void org_kde_kwin_fake_input_touch_motion(Resource *resource, uint32_t id, wl_fixed_t x, wl_fixed_t y) override;
|
||||
void org_kde_kwin_fake_input_touch_up(Resource *resource, uint32_t id) override;
|
||||
void org_kde_kwin_fake_input_touch_cancel(Resource *resource) override;
|
||||
void org_kde_kwin_fake_input_touch_frame(Resource *resource) override;
|
||||
void org_kde_kwin_fake_input_pointer_motion_absolute(Resource *resource, wl_fixed_t x, wl_fixed_t y) override;
|
||||
void org_kde_kwin_fake_input_keyboard_key(Resource *resource, uint32_t button, uint32_t state) override;
|
||||
};
|
||||
|
||||
QList<quint32> FakeInputInterfacePrivate::touchIds = QList<quint32>();
|
||||
|
||||
FakeInputInterfacePrivate::FakeInputInterfacePrivate(FakeInputInterface *_q, Display *display)
|
||||
: QtWaylandServer::org_kde_kwin_fake_input(*display, s_version)
|
||||
, q(_q)
|
||||
{
|
||||
}
|
||||
|
||||
FakeInputInterface::FakeInputInterface(Display *display)
|
||||
: d(std::make_unique<FakeInputInterfacePrivate>(this, display))
|
||||
{
|
||||
}
|
||||
|
||||
FakeInputInterface::~FakeInputInterface() = default;
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_bind_resource(Resource *resource)
|
||||
{
|
||||
auto device = new FakeInputDeviceInterface(q, resource->handle);
|
||||
devices[resource->handle] = std::unique_ptr<FakeInputDeviceInterface>(device);
|
||||
Q_EMIT q->deviceCreated(device);
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_destroy_resource(Resource *resource)
|
||||
{
|
||||
auto it = devices.find(resource->handle);
|
||||
if (it != devices.end()) {
|
||||
const auto [resource, device] = std::move(*it);
|
||||
devices.erase(it);
|
||||
Q_EMIT q->deviceDestroyed(device.get());
|
||||
}
|
||||
}
|
||||
|
||||
FakeInputDeviceInterface *FakeInputInterfacePrivate::device(wl_resource *r)
|
||||
{
|
||||
return devices[r].get();
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_authenticate(Resource *resource, const QString &application, const QString &reason)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT d->authenticationRequested(application, reason);
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_pointer_motion(Resource *resource, wl_fixed_t delta_x, wl_fixed_t delta_y)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT d->pointerMotionRequested(QPointF(wl_fixed_to_double(delta_x), wl_fixed_to_double(delta_y)));
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_button(Resource *resource, uint32_t button, uint32_t state)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
switch (state) {
|
||||
case WL_POINTER_BUTTON_STATE_PRESSED:
|
||||
Q_EMIT d->pointerButtonPressRequested(button);
|
||||
break;
|
||||
case WL_POINTER_BUTTON_STATE_RELEASED:
|
||||
Q_EMIT d->pointerButtonReleaseRequested(button);
|
||||
break;
|
||||
default:
|
||||
// nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_axis(Resource *resource, uint32_t axis, wl_fixed_t value)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
Qt::Orientation orientation;
|
||||
switch (axis) {
|
||||
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
||||
orientation = Qt::Horizontal;
|
||||
break;
|
||||
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
||||
orientation = Qt::Vertical;
|
||||
break;
|
||||
default:
|
||||
// invalid
|
||||
return;
|
||||
}
|
||||
Q_EMIT d->pointerAxisRequested(orientation, wl_fixed_to_double(value));
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_touch_down(Resource *resource, uint32_t id, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
if (touchIds.contains(id)) {
|
||||
return;
|
||||
}
|
||||
touchIds << id;
|
||||
Q_EMIT d->touchDownRequested(id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)));
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_touch_motion(Resource *resource, uint32_t id, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
if (!touchIds.contains(id)) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT d->touchMotionRequested(id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)));
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_touch_up(Resource *resource, uint32_t id)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
if (!touchIds.contains(id)) {
|
||||
return;
|
||||
}
|
||||
touchIds.removeOne(id);
|
||||
Q_EMIT d->touchUpRequested(id);
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_touch_cancel(Resource *resource)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
touchIds.clear();
|
||||
Q_EMIT d->touchCancelRequested();
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_touch_frame(Resource *resource)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT d->touchFrameRequested();
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_pointer_motion_absolute(Resource *resource, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT d->pointerMotionAbsoluteRequested(QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)));
|
||||
}
|
||||
|
||||
void FakeInputInterfacePrivate::org_kde_kwin_fake_input_keyboard_key(Resource *resource, uint32_t button, uint32_t state)
|
||||
{
|
||||
FakeInputDeviceInterface *d = device(resource->handle);
|
||||
if (!d || !d->isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
switch (state) {
|
||||
case WL_KEYBOARD_KEY_STATE_PRESSED:
|
||||
Q_EMIT d->keyboardKeyPressRequested(button);
|
||||
break;
|
||||
case WL_KEYBOARD_KEY_STATE_RELEASED:
|
||||
Q_EMIT d->keyboardKeyReleaseRequested(button);
|
||||
break;
|
||||
default:
|
||||
// nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeInputDeviceInterfacePrivate
|
||||
{
|
||||
public:
|
||||
FakeInputDeviceInterfacePrivate(FakeInputInterface *interface, wl_resource *resource);
|
||||
wl_resource *resource;
|
||||
FakeInputInterface *interface;
|
||||
bool authenticated = false;
|
||||
};
|
||||
|
||||
FakeInputDeviceInterfacePrivate::FakeInputDeviceInterfacePrivate(FakeInputInterface *interface, wl_resource *resource)
|
||||
: resource(resource)
|
||||
, interface(interface)
|
||||
{
|
||||
}
|
||||
|
||||
FakeInputDeviceInterface::FakeInputDeviceInterface(FakeInputInterface *parent, wl_resource *resource)
|
||||
: d(std::make_unique<FakeInputDeviceInterfacePrivate>(parent, resource))
|
||||
{
|
||||
}
|
||||
|
||||
FakeInputDeviceInterface::~FakeInputDeviceInterface() = default;
|
||||
|
||||
void FakeInputDeviceInterface::setAuthentication(bool authenticated)
|
||||
{
|
||||
d->authenticated = authenticated;
|
||||
}
|
||||
|
||||
wl_resource *FakeInputDeviceInterface::resource()
|
||||
{
|
||||
return d->resource;
|
||||
}
|
||||
|
||||
bool FakeInputDeviceInterface::isAuthenticated() const
|
||||
{
|
||||
return d->authenticated;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "moc_fakeinput.cpp"
|
|
@ -1,156 +0,0 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "kwin_export.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointF>
|
||||
#include <memory>
|
||||
|
||||
struct wl_resource;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class Display;
|
||||
class FakeInputDeviceInterface;
|
||||
class FakeInputDeviceInterfacePrivate;
|
||||
class FakeInputInterfacePrivate;
|
||||
|
||||
/**
|
||||
* @brief Represents the Global for org_kde_kwin_fake_input interface.
|
||||
*
|
||||
* The fake input interface allows clients to send fake input events to the
|
||||
* Wayland server. For the actual events it creates a FakeInputDevice. Whenever
|
||||
* the FakeInputInterface creates a device the signal deviceCreated gets emitted.
|
||||
*
|
||||
* Accepting fake input events is a security risk. The server should make a
|
||||
* dedicated decision about whether it wants to accept fake input events from a
|
||||
* device. Because of that by default no events are forwarded to the server. The
|
||||
* device needs to request authentication and the server must explicitly authenticate
|
||||
* the device. The recommendation is that the server only accepts input for in some
|
||||
* way trusted clients.
|
||||
*
|
||||
* @see FakeInputDevice
|
||||
*/
|
||||
class KWIN_EXPORT FakeInputInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FakeInputInterface(Display *display);
|
||||
~FakeInputInterface() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Signal emitted whenever a client bound the fake input @p device.
|
||||
* @param device The created FakeInputDevice
|
||||
*/
|
||||
void deviceCreated(KWin::FakeInputDeviceInterface *device);
|
||||
|
||||
void deviceDestroyed(KWin::FakeInputDeviceInterface *device);
|
||||
|
||||
private:
|
||||
std::unique_ptr<FakeInputInterfacePrivate> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents the Resource for a org_kde_kwin_fake_input interface.
|
||||
*
|
||||
* @see FakeInputInterface
|
||||
*/
|
||||
class KWIN_EXPORT FakeInputDeviceInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~FakeInputDeviceInterface() override;
|
||||
/**
|
||||
* @returns the native wl_resource.
|
||||
*/
|
||||
wl_resource *resource();
|
||||
|
||||
/**
|
||||
* Authenticate this device to send events. If @p authenticated is @c true events are
|
||||
* accepted, for @c false events are no longer accepted.
|
||||
*
|
||||
* @param authenticated Whether the FakeInputDevice should be considered authenticated
|
||||
*/
|
||||
void setAuthentication(bool authenticated);
|
||||
/**
|
||||
* @returns whether the FakeInputDevice is authenticated and allowed to send events, default is @c false.
|
||||
*/
|
||||
bool isAuthenticated() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Request for authentication.
|
||||
*
|
||||
* The server might use the provided information to make a decision on whether the
|
||||
* FakeInputDevice should get authenticated. It is recommended to not trust the data
|
||||
* and to combine it with information from ClientConnection.
|
||||
*
|
||||
* @param application A textual description of the application
|
||||
* @param reason A textual description of the reason why the application wants to send fake input events
|
||||
*/
|
||||
void authenticationRequested(const QString &application, const QString &reason);
|
||||
/**
|
||||
* Request a pointer motion by @p delta.
|
||||
*/
|
||||
void pointerMotionRequested(const QPointF &delta);
|
||||
/**
|
||||
* Request an absolute pointer motion to @p pos.
|
||||
*/
|
||||
void pointerMotionAbsoluteRequested(const QPointF &pos);
|
||||
/**
|
||||
* Requests a pointer button pressed for @p button.
|
||||
*/
|
||||
void pointerButtonPressRequested(quint32 button);
|
||||
/**
|
||||
* Requests a pointer button release for @p button.
|
||||
*/
|
||||
void pointerButtonReleaseRequested(quint32 button);
|
||||
/**
|
||||
* Requests a pointer axis for the given @p orientation by @p delta.
|
||||
*/
|
||||
void pointerAxisRequested(Qt::Orientation orientation, qreal delta);
|
||||
/**
|
||||
* Requests a touch down at @p pos and identified by @p id.
|
||||
*/
|
||||
void touchDownRequested(quint32 id, const QPointF &pos);
|
||||
/**
|
||||
* Requests a touch motion by @p pos and identified by @p id.
|
||||
*/
|
||||
void touchMotionRequested(quint32 id, const QPointF &pos);
|
||||
/**
|
||||
* Requests a touch up identified by @p id.
|
||||
*/
|
||||
void touchUpRequested(quint32 id);
|
||||
/**
|
||||
* Requests a touch cancel event.
|
||||
*/
|
||||
void touchCancelRequested();
|
||||
/**
|
||||
* Requests a touch frame event.
|
||||
*/
|
||||
void touchFrameRequested();
|
||||
/**
|
||||
* Requests a keyboard key pressed for @p key.
|
||||
*/
|
||||
void keyboardKeyPressRequested(quint32 key);
|
||||
/**
|
||||
* Requests a keyboard key release for @p key.
|
||||
*/
|
||||
void keyboardKeyReleaseRequested(quint32 key);
|
||||
|
||||
private:
|
||||
friend class FakeInputInterfacePrivate;
|
||||
FakeInputDeviceInterface(FakeInputInterface *parent, wl_resource *resource);
|
||||
std::unique_ptr<FakeInputDeviceInterfacePrivate> d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWin::FakeInputDeviceInterface *)
|
Loading…
Reference in a new issue