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