File indexing completed on 2024-05-19 05:32:35

0001 /*
0002     SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "inputmethod_v1.h"
0008 #include "display.h"
0009 #include "keyboard.h"
0010 #include "keyboard_p.h"
0011 #include "output.h"
0012 #include "seat.h"
0013 #include "surface.h"
0014 #include "utils/common.h"
0015 #include "utils/ramfile.h"
0016 
0017 #include <QHash>
0018 
0019 #include <unistd.h>
0020 
0021 #include "qwayland-server-input-method-unstable-v1.h"
0022 #include "qwayland-server-text-input-unstable-v1.h"
0023 #include "qwayland-server-wayland.h"
0024 
0025 namespace KWin
0026 {
0027 static int s_version = 1;
0028 
0029 class InputKeyboardV1InterfacePrivate : public QtWaylandServer::wl_keyboard
0030 {
0031 public:
0032     InputKeyboardV1InterfacePrivate()
0033     {
0034     }
0035 };
0036 
0037 InputMethodGrabV1::InputMethodGrabV1(QObject *parent)
0038     : QObject(parent)
0039     , d(new InputKeyboardV1InterfacePrivate)
0040 {
0041 }
0042 
0043 InputMethodGrabV1::~InputMethodGrabV1()
0044 {
0045 }
0046 
0047 void InputMethodGrabV1::sendKeymap(const QByteArray &keymap)
0048 {
0049     RamFile keymapFile("kwin-xkb-input-method-grab-keymap", keymap.constData(), keymap.size() + 1); // include QByteArray null terminator
0050 
0051     const auto resources = d->resourceMap();
0052     for (auto r : resources) {
0053         d->send_keymap(r->handle, QtWaylandServer::wl_keyboard::keymap_format::keymap_format_xkb_v1, keymapFile.fd(), keymapFile.size());
0054     }
0055 }
0056 
0057 void InputMethodGrabV1::sendKey(quint32 serial, quint32 timestamp, quint32 key, KeyboardKeyState state)
0058 {
0059     const auto resources = d->resourceMap();
0060     for (auto r : resources) {
0061         d->send_key(r->handle, serial, timestamp, key, quint32(state));
0062     }
0063 }
0064 
0065 void InputMethodGrabV1::sendModifiers(quint32 serial, quint32 depressed, quint32 latched, quint32 locked, quint32 group)
0066 {
0067     const auto resources = d->resourceMap();
0068     for (auto r : resources) {
0069         d->send_modifiers(r->handle, serial, depressed, latched, locked, group);
0070     }
0071 }
0072 
0073 class InputMethodContextV1InterfacePrivate : public QtWaylandServer::zwp_input_method_context_v1
0074 {
0075 public:
0076     InputMethodContextV1InterfacePrivate(InputMethodContextV1Interface *q)
0077         : zwp_input_method_context_v1()
0078         , q(q)
0079     {
0080     }
0081 
0082     ~InputMethodContextV1InterfacePrivate()
0083     {
0084     }
0085 
0086     void zwp_input_method_context_v1_commit_string(Resource *, uint32_t serial, const QString &text) override
0087     {
0088         Q_EMIT q->commitString(serial, text);
0089     }
0090     void zwp_input_method_context_v1_preedit_string(Resource *, uint32_t serial, const QString &text, const QString &commit) override
0091     {
0092         Q_EMIT q->preeditString(serial, text, commit);
0093     }
0094 
0095     void zwp_input_method_context_v1_preedit_styling(Resource *, uint32_t index, uint32_t length, uint32_t style) override
0096     {
0097         Q_EMIT q->preeditStyling(index, length, style);
0098     }
0099     void zwp_input_method_context_v1_preedit_cursor(Resource *, int32_t index) override
0100     {
0101         Q_EMIT q->preeditCursor(index);
0102     }
0103     void zwp_input_method_context_v1_delete_surrounding_text(Resource *, int32_t index, uint32_t length) override
0104     {
0105         Q_EMIT q->deleteSurroundingText(index, length);
0106     }
0107     void zwp_input_method_context_v1_cursor_position(Resource *, int32_t index, int32_t anchor) override
0108     {
0109         Q_EMIT q->cursorPosition(index, anchor);
0110     }
0111     void zwp_input_method_context_v1_modifiers_map(Resource *, wl_array *map) override
0112     {
0113         const auto mods = QByteArray::fromRawData(static_cast<const char *>(map->data), map->size);
0114 
0115         Q_EMIT q->modifiersMap(mods);
0116     }
0117     void zwp_input_method_context_v1_keysym(Resource *, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) override
0118     {
0119         Q_EMIT q->keysym(serial, time, sym, state == WL_KEYBOARD_KEY_STATE_PRESSED, modifiers);
0120     }
0121     void zwp_input_method_context_v1_grab_keyboard(Resource *resource, uint32_t id) override
0122     {
0123         m_keyboardGrab.reset(new InputMethodGrabV1(q));
0124         m_keyboardGrab->d->add(resource->client(), id, 1);
0125         Q_EMIT q->keyboardGrabRequested(m_keyboardGrab.get());
0126     }
0127     void zwp_input_method_context_v1_key(Resource *, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) override
0128     {
0129         Q_EMIT q->key(serial, time, key, state == WL_KEYBOARD_KEY_STATE_PRESSED);
0130     }
0131     void zwp_input_method_context_v1_modifiers(Resource *,
0132                                                uint32_t serial,
0133                                                uint32_t mods_depressed,
0134                                                uint32_t mods_latched,
0135                                                uint32_t mods_locked,
0136                                                uint32_t group) override
0137     {
0138         Q_EMIT q->modifiers(serial, mods_depressed, mods_latched, mods_locked, group);
0139     }
0140     void zwp_input_method_context_v1_language(Resource *, uint32_t serial, const QString &language) override
0141     {
0142         Q_EMIT q->language(serial, language);
0143     }
0144     void zwp_input_method_context_v1_text_direction(Resource *, uint32_t serial, uint32_t direction) override
0145     {
0146         Qt::LayoutDirection qtDirection;
0147         switch (direction) {
0148         case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR:
0149             qtDirection = Qt::LeftToRight;
0150             break;
0151         case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL:
0152             qtDirection = Qt::RightToLeft;
0153             break;
0154         case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_AUTO:
0155             qtDirection = Qt::LayoutDirectionAuto;
0156             break;
0157         default:
0158             Q_UNREACHABLE();
0159             break;
0160         }
0161         Q_EMIT q->textDirection(serial, qtDirection);
0162     }
0163 
0164     void zwp_input_method_context_v1_destroy(Resource *resource) override
0165     {
0166         wl_resource_destroy(resource->handle);
0167     }
0168 
0169     InputMethodContextV1Interface *const q;
0170     std::unique_ptr<InputMethodGrabV1> m_keyboardGrab;
0171 };
0172 
0173 InputMethodContextV1Interface::InputMethodContextV1Interface(InputMethodV1Interface *parent)
0174     : QObject(parent)
0175     , d(new InputMethodContextV1InterfacePrivate(this))
0176 {
0177 }
0178 
0179 InputMethodContextV1Interface::~InputMethodContextV1Interface() = default;
0180 
0181 void InputMethodContextV1Interface::sendCommitState(uint32_t serial)
0182 {
0183     for (auto r : d->resourceMap()) {
0184         d->send_commit_state(r->handle, serial);
0185     }
0186 }
0187 
0188 void InputMethodContextV1Interface::sendContentType(TextInputContentHints hint, TextInputContentPurpose purpose)
0189 {
0190     quint32 contentHint = QtWaylandServer::zwp_text_input_v1::content_hint_none;
0191     quint32 contentPurpose;
0192 
0193     if (hint.testFlag(TextInputContentHint::AutoCapitalization)) {
0194         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_auto_capitalization;
0195     }
0196     if (hint.testFlag(TextInputContentHint::AutoCorrection)) {
0197         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_auto_correction;
0198     }
0199     if (hint.testFlag(TextInputContentHint::AutoCompletion)) {
0200         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_auto_completion;
0201     }
0202     if (hint.testFlag(TextInputContentHint::LowerCase)) {
0203         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_lowercase;
0204     }
0205     if (hint.testFlag(TextInputContentHint::UpperCase)) {
0206         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_uppercase;
0207     }
0208     if (hint.testFlag(TextInputContentHint::TitleCase)) {
0209         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_titlecase;
0210     }
0211     if (hint.testFlag(TextInputContentHint::HiddenText)) {
0212         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_hidden_text;
0213     }
0214     if (hint.testFlag(TextInputContentHint::SensitiveData)) {
0215         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_lowercase;
0216     }
0217     if (hint.testFlag(TextInputContentHint::Latin)) {
0218         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_latin;
0219     }
0220     if (hint.testFlag(TextInputContentHint::MultiLine)) {
0221         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_multiline;
0222     }
0223     if (hint.testFlag(TextInputContentHint::None)) {
0224         contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_none;
0225     }
0226 
0227     switch (purpose) {
0228     case TextInputContentPurpose::Alpha:
0229         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_alpha;
0230         break;
0231     case TextInputContentPurpose::Digits:
0232         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_digits;
0233         break;
0234     case TextInputContentPurpose::Number:
0235         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_number;
0236         break;
0237     case TextInputContentPurpose::Phone:
0238         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_phone;
0239         break;
0240     case TextInputContentPurpose::Url:
0241         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_url;
0242         break;
0243     case TextInputContentPurpose::Email:
0244         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_email;
0245         break;
0246     case TextInputContentPurpose::Name:
0247         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_name;
0248         break;
0249     case TextInputContentPurpose::Password:
0250         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_password;
0251         break;
0252     case TextInputContentPurpose::Date:
0253         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_date;
0254         break;
0255     case TextInputContentPurpose::Time:
0256         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_time;
0257         break;
0258     case TextInputContentPurpose::DateTime:
0259         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_datetime;
0260         break;
0261     case TextInputContentPurpose::Terminal:
0262         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_terminal;
0263         break;
0264     case TextInputContentPurpose::Normal:
0265     default:
0266         contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_normal;
0267     }
0268 
0269     for (auto r : d->resourceMap()) {
0270         d->send_content_type(r->handle, contentHint, contentPurpose);
0271     }
0272 }
0273 
0274 void InputMethodContextV1Interface::sendInvokeAction(uint32_t button, uint32_t index)
0275 {
0276     for (auto r : d->resourceMap()) {
0277         d->send_invoke_action(r->handle, button, index);
0278     }
0279 }
0280 
0281 void InputMethodContextV1Interface::sendPreferredLanguage(const QString &language)
0282 {
0283     for (auto r : d->resourceMap()) {
0284         d->send_preferred_language(r->handle, language);
0285     }
0286 }
0287 
0288 void InputMethodContextV1Interface::sendReset()
0289 {
0290     for (auto r : d->resourceMap()) {
0291         d->send_reset(r->handle);
0292     }
0293 }
0294 
0295 void InputMethodContextV1Interface::sendSurroundingText(const QString &text, uint32_t cursor, uint32_t anchor)
0296 {
0297     for (auto r : d->resourceMap()) {
0298         d->send_surrounding_text(r->handle, text, cursor, anchor);
0299     }
0300 }
0301 
0302 InputMethodGrabV1 *InputMethodContextV1Interface::keyboardGrab() const
0303 {
0304     return d->m_keyboardGrab.get();
0305 }
0306 
0307 class InputPanelSurfaceV1InterfacePrivate : public QtWaylandServer::zwp_input_panel_surface_v1
0308 {
0309     friend class InputPanelSurfaceV1Interface;
0310 
0311 public:
0312     InputPanelSurfaceV1InterfacePrivate(SurfaceInterface *surface, quint32 id, InputPanelSurfaceV1Interface *q)
0313         : zwp_input_panel_surface_v1()
0314         , q(q)
0315         , surface(surface)
0316     {
0317     }
0318 
0319     void zwp_input_panel_surface_v1_set_overlay_panel(Resource *) override
0320     {
0321         Q_EMIT q->overlayPanel();
0322     }
0323 
0324     void zwp_input_panel_surface_v1_set_toplevel(Resource *, struct ::wl_resource *output, uint32_t position) override
0325     {
0326         Q_EMIT q->topLevel(OutputInterface::get(output), InputPanelSurfaceV1Interface::Position(position));
0327     }
0328 
0329     void zwp_input_panel_surface_v1_destroy_resource(Resource *) override
0330     {
0331         delete q;
0332     }
0333 
0334     InputPanelSurfaceV1Interface *const q;
0335     QPointer<SurfaceInterface> surface;
0336 };
0337 
0338 InputPanelSurfaceV1Interface::InputPanelSurfaceV1Interface(SurfaceInterface *surface, quint32 id, QObject *parent)
0339     : QObject(parent)
0340     , d(new InputPanelSurfaceV1InterfacePrivate(surface, id, this))
0341 {
0342 }
0343 
0344 InputPanelSurfaceV1Interface::~InputPanelSurfaceV1Interface()
0345 {
0346     Q_EMIT aboutToBeDestroyed();
0347 }
0348 
0349 SurfaceRole *InputPanelSurfaceV1Interface::role()
0350 {
0351     static SurfaceRole role(QByteArrayLiteral("input_panel_surface_v1"));
0352     return &role;
0353 }
0354 
0355 class InputPanelV1InterfacePrivate : public QtWaylandServer::zwp_input_panel_v1
0356 {
0357 public:
0358     InputPanelV1InterfacePrivate(InputPanelV1Interface *q, Display *d)
0359         : zwp_input_panel_v1(*d, s_version)
0360         , q(q)
0361     {
0362     }
0363 
0364     void zwp_input_panel_v1_get_input_panel_surface(Resource *resource, uint32_t id, struct ::wl_resource *surfaceResource) override
0365     {
0366         auto surface = SurfaceInterface::get(surfaceResource);
0367 
0368         if (const SurfaceRole *role = surface->role()) {
0369             if (role != InputPanelSurfaceV1Interface::role()) {
0370                 wl_resource_post_error(resource->handle, 0, "the surface already has a role assigned %s", role->name().constData());
0371                 return;
0372             }
0373         } else {
0374             surface->setRole(InputPanelSurfaceV1Interface::role());
0375         }
0376 
0377         auto interface = new InputPanelSurfaceV1Interface(surface, id, nullptr);
0378         interface->d->init(resource->client(), id, resource->version());
0379 
0380         Q_EMIT q->inputPanelSurfaceAdded(interface);
0381     }
0382 
0383     InputPanelV1Interface *const q;
0384 };
0385 
0386 InputPanelV1Interface::InputPanelV1Interface(Display *display, QObject *parent)
0387     : QObject(parent)
0388     , d(new InputPanelV1InterfacePrivate(this, display))
0389 {
0390 }
0391 
0392 InputPanelV1Interface::~InputPanelV1Interface() = default;
0393 
0394 SurfaceInterface *InputPanelSurfaceV1Interface::surface() const
0395 {
0396     return d->surface;
0397 }
0398 
0399 class InputMethodV1InterfacePrivate : public QtWaylandServer::zwp_input_method_v1
0400 {
0401 public:
0402     InputMethodV1InterfacePrivate(Display *d, InputMethodV1Interface *q)
0403         : zwp_input_method_v1(*d, s_version)
0404         , q(q)
0405         , m_display(d)
0406     {
0407     }
0408 
0409     void zwp_input_method_v1_bind_resource(Resource *resource) override
0410     {
0411         if (!m_context) {
0412             return;
0413         }
0414 
0415         auto addedResource = m_context->d->add(resource->client(), resource->version());
0416         send_activate(resource->handle, addedResource->handle);
0417     }
0418 
0419     std::unique_ptr<InputMethodContextV1Interface> m_context;
0420     InputMethodV1Interface *const q;
0421     Display *const m_display;
0422 };
0423 
0424 InputMethodV1Interface::InputMethodV1Interface(Display *d, QObject *parent)
0425     : QObject(parent)
0426     , d(new InputMethodV1InterfacePrivate(d, this))
0427 {
0428 }
0429 
0430 InputMethodV1Interface::~InputMethodV1Interface() = default;
0431 
0432 void InputMethodV1Interface::sendActivate()
0433 {
0434     if (d->m_context) {
0435         return;
0436     }
0437 
0438     d->m_context.reset(new InputMethodContextV1Interface(this));
0439 
0440     for (auto resource : d->resourceMap()) {
0441         auto connection = d->m_context->d->add(resource->client(), resource->version());
0442         d->send_activate(resource->handle, connection->handle);
0443     }
0444 }
0445 
0446 void InputMethodV1Interface::sendDeactivate()
0447 {
0448     if (!d->m_context) {
0449         return;
0450     }
0451 
0452     for (auto resource : d->resourceMap()) {
0453         auto connection = d->m_context->d->resourceMap().value(resource->client());
0454         if (connection) {
0455             d->send_deactivate(resource->handle, connection->handle);
0456         }
0457     }
0458     d->m_context.reset();
0459 }
0460 
0461 InputMethodContextV1Interface *InputMethodV1Interface::context() const
0462 {
0463     return d->m_context.get();
0464 }
0465 
0466 }
0467 
0468 #include "moc_inputmethod_v1.cpp"