17#include "KWayland/Client/compositor.h"
18#include "KWayland/Client/connection_thread.h"
19#include "KWayland/Client/event_queue.h"
20#include "KWayland/Client/registry.h"
21#include "KWayland/Client/seat.h"
22#include "KWayland/Client/surface.h"
24#include "qwayland-text-input-unstable-v3.h"
39 void preedit_string(
const QString &text, quint32 cursor_begin, quint32 cursor_end);
49 Q_EMIT surface_enter(surface);
53 Q_EMIT surface_leave(surface);
61 before = before_length;
66 Q_EMIT commit_string(commitText);
67 Q_EMIT preedit_string(preeditText, cursorBegin, cursorEnd);
68 Q_EMIT delete_surrounding_text(before, after);
74 cursorBegin = cursor_begin;
75 cursorEnd = cursor_end;
81 uint32_t cursorBegin, cursorEnd;
82 uint32_t before, after;
103 void testEnableDisable();
105 void testContentPurpose_data();
106 void testContentPurpose();
107 void testContentHints_data();
108 void testContentHints();
109 void testMultipleTextinputs();
112 KWayland::Client::ConnectionThread *m_connection;
113 KWayland::Client::EventQueue *m_queue;
114 KWayland::Client::Compositor *m_clientCompositor;
115 KWayland::Client::Seat *m_clientSeat =
nullptr;
125 quint32 m_totalCommits = 0;
128static const QString s_socketName = QStringLiteral(
"kwin-wayland-server-text-input-v3-test-0");
130void TestTextInputV3Interface::initTestCase()
142 m_connection =
new KWayland::Client::ConnectionThread;
143 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
144 m_connection->setSocketName(s_socketName);
146 m_thread =
new QThread(
this);
147 m_connection->moveToThread(m_thread);
150 m_connection->initConnection();
151 QVERIFY(connectedSpy.wait());
152 QVERIFY(!m_connection->connections().isEmpty());
154 m_queue =
new KWayland::Client::EventQueue(
this);
155 QVERIFY(!m_queue->isValid());
156 m_queue->setup(m_connection);
157 QVERIFY(m_queue->isValid());
159 auto registry =
new KWayland::Client::Registry(
this);
160 connect(registry, &KWayland::Client::Registry::interfaceAnnounced,
this, [
this, registry](
const QByteArray &interface, quint32
id, quint32
version) {
161 if (interface == QByteArrayLiteral(
"zwp_text_input_manager_v3")) {
163 m_clientTextInputManagerV3->init(*registry,
id,
version);
167 connect(registry, &KWayland::Client::Registry::seatAnnounced,
this, [
this, registry](quint32 name, quint32
version) {
171 QSignalSpy allAnnouncedSpy(registry, &KWayland::Client::Registry::interfaceAnnounced);
172 QSignalSpy compositorSpy(registry, &KWayland::Client::Registry::compositorAnnounced);
173 QSignalSpy shmSpy(registry, &KWayland::Client::Registry::shmAnnounced);
175 registry->create(m_connection->display());
178 QVERIFY(allAnnouncedSpy.wait());
180 m_clientCompositor =
registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(),
this);
181 QVERIFY(m_clientCompositor->isValid());
184 m_clientTextInputV3->init(m_clientTextInputManagerV3->get_text_input(*m_clientSeat));
185 QVERIFY(m_clientTextInputV3);
190 if (m_clientTextInputV3) {
191 delete m_clientTextInputV3;
192 m_clientTextInputV3 =
nullptr;
194 if (m_clientTextInputManagerV3) {
195 delete m_clientTextInputManagerV3;
196 m_clientTextInputManagerV3 =
nullptr;
208 m_connection->deleteLater();
209 m_connection =
nullptr;
213void TestTextInputV3Interface::testEnableDisable()
217 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(
this));
218 QVERIFY(serverSurfaceCreatedSpy.wait());
220 QVERIFY(serverSurface);
223 QVERIFY(m_serverTextInputV3);
235 QCOMPARE(focusedSurfaceChangedSpy.count(), 0);
239 QVERIFY(surfaceEnterSpy.wait());
240 QCOMPARE(surfaceEnterSpy.count(), 1);
241 QCOMPARE(focusedSurfaceChangedSpy.count(), 1);
242 QCOMPARE(textInputEnabledSpy.count(), 0);
245 m_clientTextInputV3->enable();
246 m_clientTextInputV3->set_cursor_rectangle(0, 0, 20, 20);
247 m_clientTextInputV3->set_surrounding_text(
"KDE Plasma Desktop", 0, 3);
248 QCOMPARE(textInputEnabledSpy.count(), 0);
249 QCOMPARE(cursorRectangleChangedSpy.count(), 0);
252 m_clientTextInputV3->commit();
253 QVERIFY(textInputEnabledSpy.wait());
256 QCOMPARE(enableRequestedSpy.count(), 0);
257 QCOMPARE(textInputEnabledSpy.count(), 1);
258 QCOMPARE(cursorRectangleChangedSpy.count(), 1);
260 QCOMPARE(m_serverTextInputV3->
surroundingText(), QString(
"KDE Plasma Desktop"));
265 m_clientTextInputV3->enable();
266 m_clientTextInputV3->set_cursor_rectangle(0, 0, 20, 20);
267 m_clientTextInputV3->set_surrounding_text(
"KDE Plasma Desktop", 0, 3);
268 m_clientTextInputV3->commit();
269 QVERIFY(enableRequestedSpy.wait());
270 QCOMPARE(textInputEnabledSpy.count(), 1);
271 QCOMPARE(cursorRectangleChangedSpy.count(), 1);
273 QCOMPARE(m_serverTextInputV3->
surroundingText(), QString(
"KDE Plasma Desktop"));
279 m_clientTextInputV3->disable();
280 QCOMPARE(textInputEnabledSpy.count(), 1);
283 m_clientTextInputV3->commit();
284 QVERIFY(textInputEnabledSpy.wait());
285 QCOMPARE(textInputEnabledSpy.count(), 2);
290 QVERIFY(surfaceLeaveSpy.wait());
291 QCOMPARE(surfaceLeaveSpy.count(), 1);
294void TestTextInputV3Interface::testEvents()
298 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(
this));
299 QVERIFY(serverSurfaceCreatedSpy.wait());
301 QVERIFY(serverSurface);
304 QVERIFY(m_serverTextInputV3);
311 QCOMPARE(focusedSurfaceChangedSpy.count(), 0);
317 QCOMPARE(focusedSurfaceChangedSpy.count(), 1);
320 m_clientTextInputV3->enable();
321 m_clientTextInputV3->commit();
323 QVERIFY(textInputEnabledSpy.wait());
324 QVERIFY(doneSpy.wait());
325 QCOMPARE(doneSpy.count(), 1);
334 m_serverTextInputV3->
done();
336 QVERIFY(doneSpy.wait());
337 QCOMPARE(doneSpy.count(), 2);
338 QCOMPARE(preEditSpy.count(), 1);
339 QCOMPARE(commitStringSpy.count(), 1);
340 QCOMPARE(deleteSurroundingSpy.count(), 1);
342 QCOMPARE(preEditSpy.last().at(0).value<QString>(),
"Hello KDE community!");
343 QCOMPARE(preEditSpy.last().at(1).value<quint32>(), 1);
344 QCOMPARE(preEditSpy.last().at(2).value<quint32>(), 2);
345 QCOMPARE(commitStringSpy.last().at(0).value<QString>(),
"Plasma");
346 QCOMPARE(deleteSurroundingSpy.last().at(0).value<quint32>(), 6);
347 QCOMPARE(deleteSurroundingSpy.last().at(1).value<quint32>(), 10);
350 QCOMPARE(doneSpy.last().at(0).value<quint32>(), m_totalCommits);
353 m_clientTextInputV3->disable();
354 m_clientTextInputV3->commit();
356 QVERIFY(textInputEnabledSpy.wait());
359void TestTextInputV3Interface::testContentPurpose_data()
361 QTest::addColumn<QtWayland::zwp_text_input_v3::content_purpose>(
"clientPurpose");
362 QTest::addColumn<KWin::TextInputContentPurpose>(
"serverPurpose");
364 QTest::newRow(
"Alpha") << QtWayland::zwp_text_input_v3::content_purpose_alpha << TextInputContentPurpose::Alpha;
365 QTest::newRow(
"Digits") << QtWayland::zwp_text_input_v3::content_purpose_digits << TextInputContentPurpose::Digits;
366 QTest::newRow(
"Number") << QtWayland::zwp_text_input_v3::content_purpose_number << TextInputContentPurpose::Number;
367 QTest::newRow(
"Phone") << QtWayland::zwp_text_input_v3::content_purpose_phone << TextInputContentPurpose::Phone;
368 QTest::newRow(
"Url") << QtWayland::zwp_text_input_v3::content_purpose_url << TextInputContentPurpose::Url;
369 QTest::newRow(
"Email") << QtWayland::zwp_text_input_v3::content_purpose_email << TextInputContentPurpose::Email;
370 QTest::newRow(
"Name") << QtWayland::zwp_text_input_v3::content_purpose_name << TextInputContentPurpose::Name;
371 QTest::newRow(
"Password") << QtWayland::zwp_text_input_v3::content_purpose_password << TextInputContentPurpose::Password;
372 QTest::newRow(
"Pin") << QtWayland::zwp_text_input_v3::content_purpose_pin << TextInputContentPurpose::Pin;
373 QTest::newRow(
"Date") << QtWayland::zwp_text_input_v3::content_purpose_date << TextInputContentPurpose::Date;
374 QTest::newRow(
"Time") << QtWayland::zwp_text_input_v3::content_purpose_time << TextInputContentPurpose::Time;
375 QTest::newRow(
"DateTime") << QtWayland::zwp_text_input_v3::content_purpose_datetime << TextInputContentPurpose::DateTime;
376 QTest::newRow(
"Terminal") << QtWayland::zwp_text_input_v3::content_purpose_terminal << TextInputContentPurpose::Terminal;
379void TestTextInputV3Interface::testContentPurpose()
383 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(
this));
384 QVERIFY(serverSurfaceCreatedSpy.wait());
386 QVERIFY(serverSurface);
389 QVERIFY(m_serverTextInputV3);
395 QCOMPARE(focusedSurfaceChangedSpy.count(), 0);
401 QCOMPARE(focusedSurfaceChangedSpy.count(), 1);
404 m_clientTextInputV3->enable();
405 m_clientTextInputV3->commit();
406 QVERIFY(textInputEnabledSpy.wait());
410 QCOMPARE(m_serverTextInputV3->
contentPurpose(), TextInputContentPurpose::Normal);
414 QFETCH(QtWayland::zwp_text_input_v3::content_purpose, clientPurpose);
415 m_clientTextInputV3->enable();
416 m_clientTextInputV3->set_content_type(QtWayland::zwp_text_input_v3::content_hint_none, clientPurpose);
417 m_clientTextInputV3->commit();
418 QVERIFY(contentTypeChangedSpy.wait());
423 m_clientTextInputV3->enable();
424 m_clientTextInputV3->set_content_type(QtWayland::zwp_text_input_v3::content_hint_none, clientPurpose);
425 m_clientTextInputV3->commit();
426 QVERIFY(!contentTypeChangedSpy.wait(100));
430 m_clientTextInputV3->enable();
431 m_clientTextInputV3->set_content_type(QtWayland::zwp_text_input_v3::content_hint_none, QtWayland::zwp_text_input_v3::content_purpose_normal);
432 m_clientTextInputV3->commit();
433 QVERIFY(contentTypeChangedSpy.wait());
435 QCOMPARE(m_serverTextInputV3->
contentPurpose(), TextInputContentPurpose::Normal);
438 m_clientTextInputV3->disable();
439 m_clientTextInputV3->commit();
441 QVERIFY(textInputEnabledSpy.wait());
444void TestTextInputV3Interface::testContentHints_data()
446 QTest::addColumn<quint32>(
"clientHint");
447 QTest::addColumn<KWin::TextInputContentHints>(
"serverHints");
449 QTest::addRow(
"Spellcheck") << quint32(QtWayland::zwp_text_input_v3::content_hint_spellcheck)
450 << TextInputContentHints(TextInputContentHint::AutoCorrection);
451 QTest::addRow(
"Completion") << quint32(QtWayland::zwp_text_input_v3::content_hint_completion)
452 << TextInputContentHints(TextInputContentHint::AutoCompletion);
453 QTest::addRow(
"AutoCapital") << quint32(QtWayland::zwp_text_input_v3::content_hint_auto_capitalization)
454 << TextInputContentHints(TextInputContentHint::AutoCapitalization);
455 QTest::addRow(
"Lowercase") << quint32(QtWayland::zwp_text_input_v3::content_hint_lowercase) << TextInputContentHints(TextInputContentHint::LowerCase);
456 QTest::addRow(
"Uppercase") << quint32(QtWayland::zwp_text_input_v3::content_hint_uppercase) << TextInputContentHints(TextInputContentHint::UpperCase);
457 QTest::addRow(
"Titlecase") << quint32(QtWayland::zwp_text_input_v3::content_hint_titlecase) << TextInputContentHints(TextInputContentHint::TitleCase);
458 QTest::addRow(
"HiddenText") << quint32(QtWayland::zwp_text_input_v3::content_hint_hidden_text) << TextInputContentHints(TextInputContentHint::HiddenText);
459 QTest::addRow(
"SensitiveData") << quint32(QtWayland::zwp_text_input_v3::content_hint_sensitive_data)
460 << TextInputContentHints(TextInputContentHint::SensitiveData);
461 QTest::addRow(
"Latin") << quint32(QtWayland::zwp_text_input_v3::content_hint_latin) << TextInputContentHints(TextInputContentHint::Latin);
462 QTest::addRow(
"Multiline") << quint32(QtWayland::zwp_text_input_v3::content_hint_multiline) << TextInputContentHints(TextInputContentHint::MultiLine);
463 QTest::addRow(
"Auto") << quint32(QtWayland::zwp_text_input_v3::content_hint_completion | QtWayland::zwp_text_input_v3::content_hint_spellcheck
464 | QtWayland::zwp_text_input_v3::content_hint_auto_capitalization)
465 << TextInputContentHints(TextInputContentHint::AutoCompletion | TextInputContentHint::AutoCorrection
466 | TextInputContentHint::AutoCapitalization);
469void TestTextInputV3Interface::testContentHints()
473 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(
this));
474 QVERIFY(serverSurfaceCreatedSpy.wait());
476 QVERIFY(serverSurface);
479 QVERIFY(m_serverTextInputV3);
485 QCOMPARE(focusedSurfaceChangedSpy.count(), 0);
491 QCOMPARE(focusedSurfaceChangedSpy.count(), 1);
494 m_clientTextInputV3->enable();
495 m_clientTextInputV3->commit();
496 QVERIFY(textInputEnabledSpy.wait());
499 QCOMPARE(m_serverTextInputV3->
contentHints(), TextInputContentHint::None);
502 m_clientTextInputV3->disable();
503 m_clientTextInputV3->commit();
504 QVERIFY(textInputEnabledSpy.wait());
509 QFETCH(quint32, clientHint);
510 m_clientTextInputV3->enable();
511 m_clientTextInputV3->set_content_type(clientHint, QtWayland::zwp_text_input_v3::content_purpose_normal);
512 m_clientTextInputV3->commit();
513 QVERIFY(contentTypeChangedSpy.wait());
514 QTEST(m_serverTextInputV3->
contentHints(),
"serverHints");
518 m_clientTextInputV3->enable();
519 m_clientTextInputV3->set_content_type(clientHint, QtWayland::zwp_text_input_v3::content_purpose_normal);
520 m_clientTextInputV3->commit();
521 QVERIFY(!contentTypeChangedSpy.wait(100));
525 m_clientTextInputV3->enable();
526 m_clientTextInputV3->set_content_type(QtWayland::zwp_text_input_v3::content_hint_none, QtWayland::zwp_text_input_v3::content_purpose_normal);
527 m_clientTextInputV3->commit();
528 QVERIFY(contentTypeChangedSpy.wait());
532 m_clientTextInputV3->disable();
533 m_clientTextInputV3->commit();
534 QVERIFY(textInputEnabledSpy.wait());
538void TestTextInputV3Interface::testMultipleTextinputs()
542 ti1->init(m_clientTextInputManagerV3->get_text_input(*m_clientSeat));
546 ti2->init(m_clientTextInputManagerV3->get_text_input(*m_clientSeat));
551 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(
this));
552 QVERIFY(serverSurfaceCreatedSpy.wait());
554 QVERIFY(serverSurface);
559 QCOMPARE(focusedSurfaceChangedSpy.count(), 1);
562 QVERIFY(m_serverTextInputV3);
563 QVERIFY(!m_serverTextInputV3->
isEnabled());
570 QVERIFY(committedSpy.wait());
571 QCOMPARE(committedSpy.last().at(0).value<quint32>(), 1);
572 QVERIFY(m_serverTextInputV3->
isEnabled());
573 QVERIFY(doneSpy1.wait());
577 ti1->set_surrounding_text(
"hello", 0, 1);
579 QVERIFY(committedSpy.wait());
580 QCOMPARE(committedSpy.last().at(0).value<quint32>(), 2);
581 QVERIFY(m_serverTextInputV3->
isEnabled());
582 QVERIFY(doneSpy1.wait());
585 ti1->set_content_type(QtWayland::zwp_text_input_v3::content_hint_none, QtWayland::zwp_text_input_v3::content_purpose_normal);
587 QVERIFY(committedSpy.wait());
588 QCOMPARE(committedSpy.last().at(0).value<quint32>(), 3);
589 QVERIFY(m_serverTextInputV3->
isEnabled());
590 QVERIFY(doneSpy1.wait());
596 m_serverTextInputV3->
done();
597 QVERIFY(doneSpy1.wait());
600 QCOMPARE(doneSpy1.last().at(0).value<quint32>(), 3);
605 QVERIFY(committedSpy.wait());
606 QCOMPARE(committedSpy.last().at(0).value<quint32>(), 4);
607 QVERIFY(!m_serverTextInputV3->
isEnabled());
612 QVERIFY(committedSpy.wait());
613 QCOMPARE(committedSpy.last().at(0).value<quint32>(), 1);
614 QVERIFY(m_serverTextInputV3->
isEnabled());
618 m_serverTextInputV3->
done();
619 QVERIFY(doneSpy2.wait());
622 QCOMPARE(doneSpy2.last().at(0).value<quint32>(), 1);
625 QVERIFY(committedSpy.wait());
626 QCOMPARE(committedSpy.last().at(0).value<quint32>(), 2);
627 QVERIFY(!m_serverTextInputV3->
isEnabled());
633 QVERIFY(committedSpy.wait());
634 QCOMPARE(committedSpy.last().at(0).value<quint32>(), 5);
635 QVERIFY(m_serverTextInputV3->
isEnabled());
639 m_serverTextInputV3->
done();
640 QVERIFY(doneSpy1.wait());
641 QCOMPARE(doneSpy1.last().at(0).value<quint32>(), 5);
656#include "test_textinputv3_interface.moc"
void surfaceCreated(KWin::SurfaceInterface *surface)
Class holding the Wayland server display loop.
bool addSocketName(const QString &name=QString())
Represents a Seat on the Wayland Display.
void setHasKeyboard(bool has)
void focusedTextInputSurfaceChanged()
void setFocusedTextInputSurface(SurfaceInterface *surface)
TextInputV3Interface * textInputV3() const
Resource representing a wl_surface.
Represent the Global for the interface.
Represents a generic Resource for a text input object.A TextInputV3Interface gets created by the Text...
void stateCommitted(quint32 serial)
void deleteSurroundingText(quint32 beforeLength, quint32 afterLength)
QRect cursorRectangle() const
void cursorRectangleChanged(const QRect &rect)
TextInputContentPurpose contentPurpose() const
qint32 surroundingTextSelectionAnchor() const
void commitString(const QString &text)
QString surroundingText() const
qint32 surroundingTextCursorPosition() const
TextInputContentHints contentHints() const
void contentTypeChanged()
void sendPreEditString(const QString &text, quint32 cursorBegin, quint32 cursorEnd)
~TestTextInputV3Interface() override
~TextInputManagerV3() override
void zwp_text_input_v3_leave(struct ::wl_surface *surface) override
void zwp_text_input_v3_enter(struct ::wl_surface *surface) override
void surface_leave(wl_surface *surface)
void zwp_text_input_v3_delete_surrounding_text(uint32_t before_length, uint32_t after_length) override
void zwp_text_input_v3_commit_string(const QString &text) override
void preedit_string(const QString &text, quint32 cursor_begin, quint32 cursor_end)
void zwp_text_input_v3_done(uint32_t serial) override
void zwp_text_input_v3_preedit_string(const QString &text, int32_t cursor_begin, int32_t cursor_end) override
void delete_surrounding_text(quint32 before_length, quint32 after_length)
void surface_enter(wl_surface *surface)
void done(quint32 serial)
void commit_string(const QString &text)
KWayland::Client::Registry * registry