diff --git a/src/3rdparty/wayland/protocols/input-method.xml b/src/3rdparty/wayland/protocols/input-method.xml deleted file mode 100644 index 70afdcb1dd4..00000000000 --- a/src/3rdparty/wayland/protocols/input-method.xml +++ /dev/null @@ -1,273 +0,0 @@ - - - - Copyright © 2012, 2013 Intel Corporation - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - - Corresponds to a text model on input method side. An input method context - is created on text mode activation on the input method side. It allows to - receive information about the text model from the application via events. - Input method contexts do not keep state after deactivation and should be - destroyed after deactivation is handled. - - Text is generally UTF-8 encoded, indices and lengths are in bytes. - - Serials are used to synchronize the state between the text input and - an input method. New serials are sent by the text input in the - commit_state request and are used by the input method to indicate - the known text input state in events like preedit_string, commit_string, - and keysym. The text input can then ignore events from the input method - which are based on an outdated state (for example after a reset). - - - - - Send the commit string text for insertion to the application. - - The text to commit could be either just a single character after a key - press or the result of some composing (pre-edit). It could be also an - empty text when some text should be removed (see - delete_surrounding_text) or when the input cursor should be moved (see - cursor_position). - - Any previously set composing text will be removed. - - - - - - - Send the pre-edit string text to the application text input. - - The commit text can be used to replace the preedit text on reset (for - example on unfocus). - - Also previously sent preedit_style and preedit_cursor requests are - processed bt the text_input also. - - - - - - - - Sets styling information on composing text. The style is applied for - length in bytes from index relative to the beginning of - the composing text (as byte offset). Multiple styles can - be applied to a composing text. - - This request should be sent before sending preedit_string request. - - - - - - - - Sets the cursor position inside the composing text (as byte offset) - relative to the start of the composing text. - - When index is negative no cursor should be displayed. - - This request should be sent before sending preedit_string request. - - - - - - - - This request will be handled on text_input side as part of a directly - following commit_string request. - - - - - - - Sets the cursor and anchor to a new position. Index is the new cursor - position in bytess (when >= 0 relative to the end of inserted text - else relative to beginning of inserted text). Anchor is the new anchor - position in bytes (when >= 0 relative to the end of inserted text, else - relative to beginning of inserted text). When there should be no - selected text anchor should be the same as index. - - This request will be handled on text_input side as part of a directly - following commit_string request. - - - - - - - - - - Notify when a key event was sent. Key events should not be used for - normal text input operations, which should be done with commit_string, - delete_surrounfing_text, etc. The key event follows the wl_keyboard key - event convention. Sym is a XKB keysym, state a wl_keyboard key_state. - - - - - - - - - - Allows an input method to receive hardware keyboard input and process - key events to generate text events (with pre-edit) over the wire. This - allows input methods which compose multiple key events for inputting - text like it is done for CJK languages. - - - - - - Should be used when filtering key events with grab_keyboard. - - When the wl_keyboard::key event is not processed by the input - method itself and should be sent to the client instead, forward it - with this request. The arguments should be the ones from the - wl_keyboard::key event. - - For generating custom key events use the keysym request instead. - - - - - - - - - Should be used when filtering key events with grab_keyboard. - - When the wl_keyboard::modifiers event should be also send to the - client, forward it with this request. The arguments should be the ones - from the wl_keyboard::modifiers event. - - - - - - - - - - - - - - - - - - The plain surrounding text around the input position. Cursor is the - position in bytes within the surrounding text relative to the beginning - of the text. Anchor is the position in bytes of the selection anchor - within the surrounding text relative to the beginning of the text. If - there is no selected text anchor is the same as cursor. - - - - - - - - - - - - - - - - - - - - - - - - - - An input method object is responsible to compose text in response to - input from hardware or virtual keyboards. There is one input method - object per seat. On activate there is a new input method context object - created which allows the input method to communicate with the text model. - - - - A text model was activated. Creates an input method context object - which allows communication with the text model. - - - - - - The text model corresponding to the context argument was deactivated. - The input method context should be destroyed after deactivation is - handled. - - - - - - - - Only one client can bind this interface at a time. - - - - - - - - - - - - - - - - A keybaord surface is only shown, when a text model is active - - - - - - - - An overlay panel is shown near the input cursor above the application - window when a text model is active. - - - - diff --git a/src/3rdparty/wayland/protocols/text-input-unstable-v2.xml b/src/3rdparty/wayland/protocols/text-input-unstable-v2.xml new file mode 100644 index 00000000000..bb366c9215c --- /dev/null +++ b/src/3rdparty/wayland/protocols/text-input-unstable-v2.xml @@ -0,0 +1,478 @@ + + + + + Copyright © 2012, 2013 Intel Corporation + Copyright © 2015, 2016 Jan Arne Petersen + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + The zwp_text_input_v2 interface represents text input and input methods + associated with a seat. It provides enter/leave events to follow the + text input focus for a seat. + + Requests are used to enable/disable the text-input object and set + state information like surrounding and selected text or the content type. + The information about the entered text is sent to the text-input object + via the pre-edit and commit events. Using this interface removes the need + for applications to directly process hardware key events and compose text + out of them. + + Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices + have to always point to the first byte of an UTF-8 encoded code point. + Lengths are not allowed to contain just a part of an UTF-8 encoded code + point. + + State is sent by the state requests (set_surrounding_text, + set_content_type, set_cursor_rectangle and set_preferred_language) and + an update_state request. After an enter or an input_method_change event + all state information is invalidated and needs to be resent from the + client. A reset or entering a new widget on client side also + invalidates all current state information. + + + + + Destroy the wp_text_input object. Also disables all surfaces enabled + through this wp_text_input object + + + + + + Enable text input in a surface (usually when a text entry inside of it + has focus). + + This can be called before or after a surface gets text (or keyboard) + focus via the enter event. Text input to a surface is only active + when it has the current text (or keyboard) focus and is enabled. + + + + + + + Disable text input in a surface (typically when there is no focus on any + text entry inside the surface). + + + + + + + Requests input panels (virtual keyboard) to show. + + This should be used for example to show a virtual keyboard again + (with a tap) after it was closed by pressing on a close button on the + keyboard. + + + + + + Requests input panels (virtual keyboard) to hide. + + + + + + Sets the plain surrounding text around the input position. Text is + UTF-8 encoded. Cursor is the byte offset within the surrounding text. + Anchor is the byte offset of the selection anchor within the + surrounding text. If there is no selected text, anchor is the same as + cursor. + + Make sure to always send some text before and after the cursor + except when the cursor is at the beginning or end of text. + + When there was a configure_surrounding_text event take the + before_cursor and after_cursor arguments into account for picking how + much surrounding text to send. + + There is a maximum length of wayland messages so text can not be + longer than 4000 bytes. + + + + + + + + + Content hint is a bitmask to allow to modify the behavior of the text + input. + + + + + + + + + + + + + + + + + The content purpose allows to specify the primary purpose of a text + input. + + This allows an input method to show special purpose input panels with + extra characters or to disallow some characters. + + + + + + + + + + + + + + + + + + + Sets the content purpose and content hint. While the purpose is the + basic purpose of an input field, the hint flags allow to modify some + of the behavior. + + When no content type is explicitly set, a normal content purpose with + none hint should be assumed. + + + + + + + + Sets the cursor outline as a x, y, width, height rectangle in surface + local coordinates. + + Allows the compositor to put a window with word suggestions near the + cursor. + + + + + + + + + + Sets a specific language. This allows for example a virtual keyboard to + show a language specific layout. The "language" argument is a RFC-3066 + format language tag. + + It could be used for example in a word processor to indicate language of + currently edited document or in an instant message application which + tracks languages of contacts. + + + + + + + Defines the reason for sending an updated state. + + + + + + + + + + Allows to atomically send state updates from client. + + This request should follow after a batch of state updating requests + like set_surrounding_text, set_content_type, set_cursor_rectangle and + set_preferred_language. + + The flags field indicates why an updated state is sent to the input + method. + + Reset should be used by an editor widget after the text was changed + outside of the normal input method flow. + + For "change" it is enough to send the changed state, else the full + state should be send. + + Serial should be set to the serial from the last enter or + input_method_changed event. + + To make sure to not receive outdated input method events after a + reset or switching to a new widget wl_display_sync() should be used + after update_state in these cases. + + + + + + + + Notification that this seat's text-input focus is on a certain surface. + + When the seat has the keyboard capability the text-input focus follows + the keyboard focus. + + + + + + + + Notification that this seat's text-input focus is no longer on + a certain surface. + + The leave notification is sent before the enter notification + for the new focus. + + When the seat has the keyboard capabillity the text-input focus follows + the keyboard focus. + + + + + + + + + + + + + Notification that the visibility of the input panel (virtual keyboard) + changed. + + The rectangle x, y, width, height defines the area overlapped by the + input panel (virtual keyboard) on the surface having the text + focus in surface local coordinates. + + That can be used to make sure widgets are visible and not covered by + a virtual keyboard. + + + + + + + + + + + Notify when a new composing text (pre-edit) should be set around the + current cursor position. Any previously set composing text should + be removed. + + The commit text can be used to replace the composing text in some cases + (for example when losing focus). + + The text input should also handle all preedit_style and preedit_cursor + events occurring directly before preedit_string. + + + + + + + + + + + + + + + + + + + Sets styling information on composing text. The style is applied for + length bytes from index relative to the beginning of the composing + text (as byte offset). Multiple styles can be applied to a composing + text by sending multiple preedit_styling events. + + This event is handled as part of a following preedit_string event. + + + + + + + + + Sets the cursor position inside the composing text (as byte + offset) relative to the start of the composing text. When index is a + negative number no cursor is shown. + + When no preedit_cursor event is sent the cursor will be at the end of + the composing text by default. + + This event is handled as part of a following preedit_string event. + + + + + + + Notify when text should be inserted into the editor widget. The text to + commit could be either just a single character after a key press or the + result of some composing (pre-edit). It could be also an empty text + when some text should be removed (see delete_surrounding_text) or when + the input cursor should be moved (see cursor_position). + + Any previously set composing text should be removed. + + + + + + + Notify when the cursor or anchor position should be modified. + + This event should be handled as part of a following commit_string + event. + + The text between anchor and index should be selected. + + + + + + + + Notify when the text around the current cursor position should be + deleted. BeforeLength and afterLength is the length (in bytes) of text + before and after the current cursor position (excluding the selection) + to delete. + + This event should be handled as part of a following commit_string + or preedit_string event. + + + + + + + + Transfer an array of 0-terminated modifiers names. The position in + the array is the index of the modifier as used in the modifiers + bitmask in the keysym event. + + + + + + + Notify when a key event was sent. Key events should not be used + for normal text input operations, which should be done with + commit_string, delete_surrounding_text, etc. The key event follows + the wl_keyboard key event convention. Sym is a XKB keysym, state a + wl_keyboard key_state. Modifiers are a mask for effective modifiers + (where the modifier indices are set by the modifiers_map event) + + + + + + + + + + Sets the language of the input text. The "language" argument is a RFC-3066 + format language tag. + + + + + + + + + + + + + Sets the text direction of input text. + + It is mainly needed for showing input cursor on correct side of the + editor when there is no input yet done and making sure neutral + direction text is laid out properly. + + + + + + + Configure what amount of surrounding text is expected by the + input method. The surrounding text will be sent in the + set_surrounding_text request on the following state information updates. + + + + + + + + The input method changed on compositor side, which invalidates all + current state information. New state information should be sent from + the client via state requests (set_surrounding_text, + set_content_hint, ...) and update_state. + + + + + + + + + A factory for text-input objects. This object is a global singleton. + + + + + Destroy the wp_text_input_manager object. + + + + + + Creates a new text-input object for a given seat. + + + + + + diff --git a/src/3rdparty/wayland/protocols/text.xml b/src/3rdparty/wayland/protocols/text.xml deleted file mode 100644 index 1b5284dc307..00000000000 --- a/src/3rdparty/wayland/protocols/text.xml +++ /dev/null @@ -1,346 +0,0 @@ - - - - - Copyright © 2012, 2013 Intel Corporation - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - An object used for text input. Adds support for text input and input - methods to applications. A text-input object is created from a - wl_text_input_manager and corresponds typically to a text entry in an - application. - Requests are used to activate/deactivate the text-input object and set - state information like surrounding and selected text or the content type. - The information about entered text is sent to the text-input object via - the pre-edit and commit events. Using this interface removes the need - for applications to directly process hardware key events and compose text - out of them. - - Text is generally UTF-8 encoded, indices and lengths are in bytes. - - Serials are used to synchronize the state between the text input and - an input method. New serials are sent by the text input in the - commit_state request and are used by the input method to indicate - the known text input state in events like preedit_string, commit_string, - and keysym. The text input can then ignore events from the input method - which are based on an outdated state (for example after a reset). - - - - Requests the text-input object to be activated (typically when the - text entry gets focus). - The seat argument is a wl_seat which maintains the focus for this - activation. The surface argument is a wl_surface assigned to the - text-input object and tracked for focus lost. The enter event - is emitted on successful activation. - - - - - - - Requests the text-input object to be deactivated (typically when the - text entry lost focus). The seat argument is a wl_seat which was used - for activation. - - - - - - Requests input panels (virtual keyboard) to show. - - - - - Requests input panels (virtual keyboard) to hide. - - - - - Should be called by an editor widget when the input state should be - reset, for example after the text was changed outside of the normal - input method flow. - - - - - Sets the plain surrounding text around the input position. Text is - UTF-8 encoded. Cursor is the byte offset within the - surrounding text. Anchor is the byte offset of the - selection anchor within the surrounding text. If there is no selected - text anchor is the same as cursor. - - - - - - - - Content hint is a bitmask to allow to modify the behavior of the text - input. - - - - - - - - - - - - - - - - - - The content purpose allows to specify the primary purpose of a text - input. - - This allows an input method to show special purpose input panels with - extra characters or to disallow some characters. - - - - - - - - - - - - - - - - - - Sets the content purpose and content hint. While the purpose is the - basic purpose of an input field, the hint flags allow to modify some - of the behavior. - - When no content type is explicitly set, a normal content purpose with - default hints (auto completion, auto correction, auto capitalization) - should be assumed. - - - - - - - - - - - - - Sets a specific language. This allows for example a virtual keyboard to - show a language specific layout. The "language" argument is a RFC-3066 - format language tag. - - It could be used for example in a word processor to indicate language of - currently edited document or in an instant message application which tracks - languages of contacts. - - - - - - - - - - - - - Notify the text-input object when it received focus. Typically in - response to an activate request. - - - - - - Notify the text-input object when it lost focus. Either in response - to a deactivate request or when the assigned surface lost focus or was - destroyed. - - - - - Transfer an array of 0-terminated modifiers names. The position in - the array is the index of the modifier as used in the modifiers - bitmask in the keysym event. - - - - - - Notify when the visibility state of the input panel changed. - - - - - - Notify when a new composing text (pre-edit) should be set around the - current cursor position. Any previously set composing text should - be removed. - - The commit text can be used to replace the preedit text on reset - (for example on unfocus). - - The text input should also handle all preedit_style and preedit_cursor - events occuring directly before preedit_string. - - - - - - - - - - - - - - - - - - Sets styling information on composing text. The style is applied for - length bytes from index relative to the beginning of the composing - text (as byte offset). Multiple styles can - be applied to a composing text by sending multiple preedit_styling - events. - - This event is handled as part of a following preedit_string event. - - - - - - - - Sets the cursor position inside the composing text (as byte - offset) relative to the start of the composing text. When index is a - negative number no cursor is shown. - - This event is handled as part of a following preedit_string event. - - - - - - Notify when text should be inserted into the editor widget. The text to - commit could be either just a single character after a key press or the - result of some composing (pre-edit). It could be also an empty text - when some text should be removed (see delete_surrounding_text) or when - the input cursor should be moved (see cursor_position). - - Any previously set composing text should be removed. - - - - - - - Notify when the cursor or anchor position should be modified. - - This event should be handled as part of a following commit_string - event. - - - - - - - Notify when the text around the current cursor position should be - deleted. - - Index is relative to the current cursor (in bytes). - Length is the length of deleted text (in bytes). - - This event should be handled as part of a following commit_string - event. - - - - - - - Notify when a key event was sent. Key events should not be used - for normal text input operations, which should be done with - commit_string, delete_surrounding_text, etc. The key event follows - the wl_keyboard key event convention. Sym is a XKB keysym, state a - wl_keyboard key_state. Modifiers are a mask for effective modifiers - (where the modifier indices are set by the modifiers_map event) - - - - - - - - - - Sets the language of the input text. The "language" argument is a RFC-3066 - format language tag. - - - - - - - - - - - - Sets the text direction of input text. - - It is mainly needed for showing input cursor on correct side of the - editor when there is no input yet done and making sure neutral - direction text is laid out properly. - - - - - - - - - A factory for text-input objects. This object is a global singleton. - - - - Creates a new text-input object. - - - - - diff --git a/src/plugins/platforms/wayland/client.pro b/src/plugins/platforms/wayland/client.pro index 1219ee3451d..61404eeb98c 100644 --- a/src/plugins/platforms/wayland/client.pro +++ b/src/plugins/platforms/wayland/client.pro @@ -39,7 +39,7 @@ WAYLANDCLIENTSOURCES += \ ../extensions/touch-extension.xml \ ../extensions/qtkey-extension.xml \ ../extensions/windowmanager.xml \ - ../3rdparty/protocol/text.xml \ + ../3rdparty/protocol/text-input-unstable-v2.xml \ ../3rdparty/protocol/xdg-shell.xml \ SOURCES += qwaylandintegration.cpp \ @@ -66,6 +66,7 @@ SOURCES += qwaylandintegration.cpp \ qwaylandqtkey.cpp \ ../shared/qwaylandmimehelper.cpp \ ../shared/qwaylandxkb.cpp \ + ../shared/qwaylandinputmethodeventbuilder.cpp \ qwaylandabstractdecoration.cpp \ qwaylanddecorationfactory.cpp \ qwaylanddecorationplugin.cpp \ @@ -100,6 +101,7 @@ HEADERS += qwaylandintegration_p.h \ qwaylandqtkey_p.h \ ../shared/qwaylandmimehelper.h \ ../shared/qwaylandxkb.h \ + ../shared/qwaylandinputmethodeventbuilder.h \ qwaylandabstractdecoration_p.h \ qwaylanddecorationfactory_p.h \ qwaylanddecorationplugin_p.h \ diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 7244363cd08..a18b9853faf 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -50,6 +50,7 @@ #include "qwaylandxdgshell_p.h" #include "qwaylandxdgsurface_p.h" #include "qwaylandwlshellsurface_p.h" +#include "qwaylandinputcontext_p.h" #include "qwaylandwindowmanagerintegration_p.h" #include "qwaylandshellintegration_p.h" @@ -60,7 +61,7 @@ #include "qwaylandtouch_p.h" #include "qwaylandqtkey_p.h" -#include +#include #include #include @@ -281,8 +282,11 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin mTouchExtension.reset(new QWaylandTouchExtension(this, id)); } else if (interface == QStringLiteral("qt_key_extension")) { mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id)); - } else if (interface == QStringLiteral("wl_text_input_manager")) { - mTextInputManager.reset(new QtWayland::wl_text_input_manager(registry, id, 1)); + } else if (interface == QStringLiteral("zwp_text_input_manager_v2")) { + mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1)); + foreach (QWaylandInputDevice *inputDevice, mInputDevices) { + inputDevice->setTextInput(new QWaylandTextInput(this, mTextInputManager->get_text_input(inputDevice->wl_seat()))); + } } else if (interface == QStringLiteral("qt_hardware_integration")) { mHardwareIntegration.reset(new QWaylandHardwareIntegration(registry, id)); // make a roundtrip here since we need to receive the events sent by diff --git a/src/plugins/platforms/wayland/qwaylanddisplay_p.h b/src/plugins/platforms/wayland/qwaylanddisplay_p.h index 82d87cb928f..618e57c59a8 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h @@ -76,7 +76,7 @@ namespace QtWayland { class qt_shell; class qt_sub_surface_extension; class qt_surface_extension; - class wl_text_input_manager; + class zwp_text_input_manager_v2; class xdg_shell; } @@ -147,7 +147,7 @@ public: QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); } QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); } - QtWayland::wl_text_input_manager *textInputManager() const { return mTextInputManager.data(); } + QtWayland::zwp_text_input_manager_v2 *textInputManager() const { return mTextInputManager.data(); } QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); } struct RegistryGlobal { @@ -207,7 +207,7 @@ private: QScopedPointer mTouchExtension; QScopedPointer mQtKeyExtension; QScopedPointer mWindowManagerIntegration; - QScopedPointer mTextInputManager; + QScopedPointer mTextInputManager; QScopedPointer mHardwareIntegration; QSocketNotifier *mReadNotifier; int mFd; diff --git a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp index 00f6a43038f..aeaf415d2cd 100644 --- a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Klarälvdalens Datakonsult AB (KDAB). +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWaylandClient module of the Qt Toolkit. @@ -40,147 +40,358 @@ #include "qwaylandinputcontext_p.h" -#include -#include -#ifndef QT_NO_WAYLAND_XKB -#include -#endif +#include +#include +#include +#include +#include #include "qwaylanddisplay_p.h" #include "qwaylandinputdevice_p.h" +#include "qwaylandinputmethodeventbuilder.h" #include "qwaylandwindow_p.h" +#include "qwaylandxkb.h" QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(qLcQpaInputMethods, "qt.qpa.input.methods") + namespace QtWaylandClient { -static Qt::Key toQtKey(uint32_t sym) -{ -#ifndef QT_NO_WAYLAND_XKB - switch (static_cast(sym)) { - case XKB_KEY_BackSpace: - return Qt::Key_Backspace; - case XKB_KEY_Return: - return Qt::Key_Return; - case XKB_KEY_Left: - return Qt::Key_Left; - case XKB_KEY_Up: - return Qt::Key_Up; - case XKB_KEY_Right: - return Qt::Key_Right; - case XKB_KEY_Down: - return Qt::Key_Down; - default: - return Qt::Key_unknown; - } -#else - Q_UNUSED(sym) - return Qt::Key_unknown; -#endif +namespace { +const Qt::InputMethodQueries supportedQueries = Qt::ImEnabled | + Qt::ImSurroundingText | + Qt::ImCursorPosition | + Qt::ImAnchorPosition | + Qt::ImHints | + Qt::ImCursorRectangle | + Qt::ImPreferredLanguage; } -static QEvent::Type toQEventType(uint32_t state) -{ - switch (static_cast(state)) { - default: - case WL_KEYBOARD_KEY_STATE_PRESSED: - return QEvent::KeyPress; - case WL_KEYBOARD_KEY_STATE_RELEASED: - return QEvent::KeyRelease; - } -} - -QWaylandTextInput::QWaylandTextInput(struct ::wl_text_input *text_input) - : QtWayland::wl_text_input(text_input) - , m_commit() +QWaylandTextInput::QWaylandTextInput(QWaylandDisplay *display, struct ::zwp_text_input_v2 *text_input) + : QtWayland::zwp_text_input_v2(text_input) + , m_display(display) + , m_builder() , m_serial(0) - , m_resetSerial(0) + , m_surface(nullptr) + , m_preeditCommit() + , m_inputPanelVisible(false) + , m_keyboardRectangle() + , m_locale() + , m_inputDirection(Qt::LayoutDirectionAuto) + , m_resetCallback(nullptr) { } -QString QWaylandTextInput::commitString() const +QWaylandTextInput::~QWaylandTextInput() { - return m_commit; + if (m_resetCallback) + wl_callback_destroy(m_resetCallback); } void QWaylandTextInput::reset() { - wl_text_input::reset(); - updateState(); - m_resetSerial = m_serial; + m_builder.reset(); + m_preeditCommit = QString(); + updateState(Qt::ImQueryAll, update_state_reset); } -void QWaylandTextInput::updateState() +void QWaylandTextInput::commit() +{ + if (QObject *o = QGuiApplication::focusObject()) { + QInputMethodEvent event; + event.setCommitString(m_preeditCommit); + QCoreApplication::sendEvent(o, &event); + } + + reset(); +} + +const wl_callback_listener QWaylandTextInput::callbackListener = { + QWaylandTextInput::resetCallback +}; + +void QWaylandTextInput::resetCallback(void *data, wl_callback *, uint32_t) +{ + QWaylandTextInput *self = static_cast(data); + + if (self->m_resetCallback) { + wl_callback_destroy(self->m_resetCallback); + self->m_resetCallback = nullptr; + } +} + +void QWaylandTextInput::updateState(Qt::InputMethodQueries queries, uint32_t flags) { if (!QGuiApplication::focusObject()) return; - QInputMethodQueryEvent event(Qt::ImQueryAll); + if (!QGuiApplication::focusWindow() || !QGuiApplication::focusWindow()->handle()) + return; + + struct ::wl_surface *surface = static_cast(QGuiApplication::focusWindow()->handle())->object(); + if (!surface || (surface != m_surface)) + return; + + queries &= supportedQueries; + + // Surrounding text, cursor and anchor positions are transferred together + if ((queries & Qt::ImSurroundingText) || (queries & Qt::ImCursorPosition) || (queries & Qt::ImAnchorPosition)) + queries |= Qt::ImSurroundingText | Qt::ImCursorPosition | Qt::ImAnchorPosition; + + QInputMethodQueryEvent event(queries); QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); - const QString &text = event.value(Qt::ImSurroundingText).toString(); - const int cursor = event.value(Qt::ImCursorPosition).toInt(); - const int anchor = event.value(Qt::ImAnchorPosition).toInt(); + if ((queries & Qt::ImSurroundingText) || (queries & Qt::ImCursorPosition) || (queries & Qt::ImAnchorPosition)) { + QString text = event.value(Qt::ImSurroundingText).toString(); + int cursor = event.value(Qt::ImCursorPosition).toInt(); + int anchor = event.value(Qt::ImAnchorPosition).toInt(); - set_surrounding_text(text, text.leftRef(cursor).toUtf8().size(), text.leftRef(anchor).toUtf8().size()); + // Make sure text is not too big + if (text.toUtf8().size() > 2048) { + int c = qAbs(cursor - anchor) <= 512 ? qMin(cursor, anchor) + qAbs(cursor - anchor) / 2: cursor; - commit_state(++m_serial); + const int offset = c - qBound(0, c, 512 - qMin(text.size() - c, 256)); + text = text.mid(offset + c - 256, 512); + cursor -= offset; + anchor -= offset; + } + + set_surrounding_text(text, text.leftRef(cursor).toUtf8().size(), text.leftRef(anchor).toUtf8().size()); + } + + if (queries & Qt::ImHints) { + QWaylandInputMethodContentType contentType = QWaylandInputMethodContentType::convert(static_cast(event.value(Qt::ImHints).toInt())); + set_content_type(contentType.hint, contentType.purpose); + } + + if (queries & Qt::ImCursorRectangle) { + const QRect &cRect = event.value(Qt::ImCursorRectangle).toRect(); + const QRect &tRect = QGuiApplication::inputMethod()->inputItemTransform().mapRect(cRect); + set_cursor_rectangle(tRect.x(), tRect.y(), tRect.width(), tRect.height()); + } + + if (queries & Qt::ImPreferredLanguage) { + const QString &language = event.value(Qt::ImPreferredLanguage).toString(); + set_preferred_language(language); + } + + update_state(m_serial, flags); + if (flags != update_state_change) { + if (m_resetCallback) + wl_callback_destroy(m_resetCallback); + m_resetCallback = wl_display_sync(m_display->wl_display()); + wl_callback_add_listener(m_resetCallback, &QWaylandTextInput::callbackListener, this); + } } -void QWaylandTextInput::text_input_preedit_string(uint32_t serial, const QString &text, const QString &commit) +bool QWaylandTextInput::isInputPanelVisible() const { - Q_UNUSED(serial) + return m_inputPanelVisible; +} + +QRectF QWaylandTextInput::keyboardRect() const +{ + return m_keyboardRectangle; +} + +QLocale QWaylandTextInput::locale() const +{ + return m_locale; +} + +Qt::LayoutDirection QWaylandTextInput::inputDirection() const +{ + return m_inputDirection; +} + +void QWaylandTextInput::zwp_text_input_v2_enter(uint32_t serial, ::wl_surface *surface) +{ + m_serial = serial; + m_surface = surface; + + updateState(Qt::ImQueryAll, update_state_enter); +} + +void QWaylandTextInput::zwp_text_input_v2_leave(uint32_t serial, ::wl_surface *surface) +{ + m_serial = serial; + + if (m_surface != surface) { + qCDebug(qLcQpaInputMethods()) << Q_FUNC_INFO << "Got leave event for surface" << surface << "focused surface" << m_surface; + } + + m_surface = nullptr; +} + +void QWaylandTextInput::zwp_text_input_v2_modifiers_map(wl_array *map) +{ + QList modifiersMap = QByteArray::fromRawData(static_cast(map->data), map->size).split('\0'); + + m_modifiersMap.clear(); + + Q_FOREACH (const QByteArray &modifier, modifiersMap) { + if (modifier == "Shift") + m_modifiersMap.append(Qt::ShiftModifier); + else if (modifier == "Control") + m_modifiersMap.append(Qt::ControlModifier); + else if (modifier == "Alt") + m_modifiersMap.append(Qt::AltModifier); + else if (modifier == "Mod1") + m_modifiersMap.append(Qt::AltModifier); + else if (modifier == "Mod4") + m_modifiersMap.append(Qt::MetaModifier); + else + m_modifiersMap.append(Qt::NoModifier); + } +} + +void QWaylandTextInput::zwp_text_input_v2_input_panel_state(uint32_t visible, int32_t x, int32_t y, int32_t width, int32_t height) +{ + const bool inputPanelVisible = (visible == input_panel_visibility_visible); + if (m_inputPanelVisible != inputPanelVisible) { + m_inputPanelVisible = inputPanelVisible; + QGuiApplicationPrivate::platformIntegration()->inputContext()->emitInputPanelVisibleChanged(); + } + const QRectF keyboardRectangle(x, y, width, height); + if (m_keyboardRectangle != keyboardRectangle) { + m_keyboardRectangle = keyboardRectangle; + QGuiApplicationPrivate::platformIntegration()->inputContext()->emitKeyboardRectChanged(); + } +} + +void QWaylandTextInput::zwp_text_input_v2_preedit_string(const QString &text, const QString &commit) +{ + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard preedit_string: reset not confirmed"; + m_builder.reset(); + return; + } + if (!QGuiApplication::focusObject()) return; - m_commit = commit; - QList attributes; - QInputMethodEvent event(text, attributes); + QInputMethodEvent event = m_builder.buildPreedit(text); + + m_builder.reset(); + m_preeditCommit = commit; + QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); } -void QWaylandTextInput::text_input_commit_string(uint32_t serial, const QString &text) +void QWaylandTextInput::zwp_text_input_v2_preedit_styling(uint32_t index, uint32_t length, uint32_t style) { - Q_UNUSED(serial); + m_builder.addPreeditStyling(index, length, style); +} + +void QWaylandTextInput::zwp_text_input_v2_preedit_cursor(int32_t index) +{ + m_builder.setPreeditCursor(index); +} + +void QWaylandTextInput::zwp_text_input_v2_commit_string(const QString &text) +{ + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard commit_string: reset not confirmed"; + m_builder.reset(); + return; + } + if (!QGuiApplication::focusObject()) return; - QInputMethodEvent event; - event.setCommitString(text); + QInputMethodEvent event = m_builder.buildCommit(text); + + m_builder.reset(); + QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); - - m_commit = QString(); } -void QWaylandTextInput::text_input_enter(wl_surface *) +void QWaylandTextInput::zwp_text_input_v2_cursor_position(int32_t index, int32_t anchor) { - updateState(); - m_resetSerial = m_serial; + m_builder.setCursorPosition(index, anchor); } -void QWaylandTextInput::text_input_leave() +void QWaylandTextInput::zwp_text_input_v2_delete_surrounding_text(uint32_t before_length, uint32_t after_length) { - if (!m_commit.isEmpty()) - text_input_commit_string(0, m_commit); + m_builder.setDeleteSurroundingText(before_length, after_length); } -void QWaylandTextInput::text_input_keysym(uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) +void QWaylandTextInput::zwp_text_input_v2_keysym(uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) { - Q_UNUSED(serial); - Q_UNUSED(time); - Q_UNUSED(modifiers); - if (!QGuiApplication::focusObject()) + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard keysym: reset not confirmed"; + return; + } + + if (!QGuiApplication::focusWindow()) return; - // TODO: Convert modifiers to Qt::KeyboardModifiers. - QKeyEvent event(toQEventType(state), toQtKey(sym), Qt::NoModifier); - QCoreApplication::sendEvent(qGuiApp->focusWindow(), &event); + Qt::KeyboardModifiers qtModifiers = modifiersToQtModifiers(modifiers); + + QEvent::Type type = QWaylandXkb::toQtEventType(state); + const QString &text = QWaylandXkb::textFromKeysym(sym, qtModifiers); + int qtkey = QWaylandXkb::keysymToQtKey(sym, qtModifiers, text); + + QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(), + time, type, qtkey, qtModifiers, text); +} + +void QWaylandTextInput::zwp_text_input_v2_language(const QString &language) +{ + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard language: reset not confirmed"; + return; + } + + const QLocale locale(language); + if (m_locale != locale) { + m_locale = locale; + QGuiApplicationPrivate::platformIntegration()->inputContext()->emitLocaleChanged(); + } +} + +void QWaylandTextInput::zwp_text_input_v2_text_direction(uint32_t direction) +{ + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard text_direction: reset not confirmed"; + return; + } + + const Qt::LayoutDirection inputDirection = (direction == text_direction_auto) ? Qt::LayoutDirectionAuto : + (direction == text_direction_ltr) ? Qt::LeftToRight : + (direction == text_direction_rtl) ? Qt::RightToLeft : Qt::LayoutDirectionAuto; + if (m_inputDirection != inputDirection) { + m_inputDirection = inputDirection; + QGuiApplicationPrivate::platformIntegration()->inputContext()->emitInputDirectionChanged(m_inputDirection); + } +} + +void QWaylandTextInput::zwp_text_input_v2_input_method_changed(uint32_t serial, uint32_t flags) +{ + Q_UNUSED(flags); + + m_serial = serial; + updateState(Qt::ImQueryAll, update_state_full); +} + +Qt::KeyboardModifiers QWaylandTextInput::modifiersToQtModifiers(uint32_t modifiers) +{ + Qt::KeyboardModifiers ret = Qt::NoModifier; + for (int i = 0; modifiers >>= 1; ++i) { + ret |= m_modifiersMap[i]; + } + return ret; } QWaylandInputContext::QWaylandInputContext(QWaylandDisplay *display) : QPlatformInputContext() , mDisplay(display) - , mTextInput() + , mCurrentWindow() +{ +} + +QWaylandInputContext::~QWaylandInputContext() { } @@ -191,96 +402,141 @@ bool QWaylandInputContext::isValid() const void QWaylandInputContext::reset() { - if (!ensureTextInput()) + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + QPlatformInputContext::reset(); + + if (!textInput()) return; - mTextInput->reset(); + textInput()->reset(); } void QWaylandInputContext::commit() { - if (!ensureTextInput()) + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) return; - if (!QGuiApplication::focusObject()) - return; - - QInputMethodEvent event; - event.setCommitString(mTextInput->commitString()); - QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); - - mTextInput->reset(); + textInput()->commit(); } void QWaylandInputContext::update(Qt::InputMethodQueries queries) { - Q_UNUSED(queries); - if (!ensureTextInput()) + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO << queries; + + if (!QGuiApplication::focusObject() || !textInput()) return; - mTextInput->updateState(); -} + if (mCurrentWindow && mCurrentWindow->handle() && !inputMethodAccepted()) { + struct ::wl_surface *surface = static_cast(mCurrentWindow->handle())->object(); + textInput()->disable(surface); + mCurrentWindow.clear(); + } else if (!mCurrentWindow && inputMethodAccepted()) { + QWindow *window = QGuiApplication::focusWindow(); + if (window && window->handle()) { + struct ::wl_surface *surface = static_cast(window->handle())->object(); + textInput()->enable(surface); + mCurrentWindow = window; + } + } -void QWaylandInputContext::invokeAction(QInputMethod::Action, int cursorPosition) -{ - if (!ensureTextInput()) - return; - - mTextInput->invoke_action(0, cursorPosition); // FIXME button, to UTF8 cursor position + textInput()->updateState(queries, QtWayland::zwp_text_input_v2::update_state_change); } void QWaylandInputContext::showInputPanel() { - if (!ensureTextInput()) + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) return; - mTextInput->show_input_panel(); + textInput()->show_input_panel(); } void QWaylandInputContext::hideInputPanel() { - if (!ensureTextInput()) + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) return; - mTextInput->hide_input_panel(); + textInput()->hide_input_panel(); } bool QWaylandInputContext::isInputPanelVisible() const { - return false; + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) + return QPlatformInputContext::isInputPanelVisible(); + + return textInput()->isInputPanelVisible(); } -void QWaylandInputContext::setFocusObject(QObject *object) +QRectF QWaylandInputContext::keyboardRect() const { - if (!ensureTextInput()) - return; + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; - if (!object) { - mTextInput->deactivate(mDisplay->defaultInputDevice()->wl_seat()); + if (!textInput()) + return QPlatformInputContext::keyboardRect(); + + return textInput()->keyboardRect(); +} + +QLocale QWaylandInputContext::locale() const +{ + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) + return QPlatformInputContext::locale(); + + return textInput()->locale(); +} + +Qt::LayoutDirection QWaylandInputContext::inputDirection() const +{ + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) + return QPlatformInputContext::inputDirection(); + + return textInput()->inputDirection(); +} + +void QWaylandInputContext::setFocusObject(QObject *) +{ + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) return; - } QWindow *window = QGuiApplication::focusWindow(); - if (!window || !window->handle()) - return; - struct ::wl_surface *surface = static_cast(window->handle())->object(); - mTextInput->activate(mDisplay->defaultInputDevice()->wl_seat(), surface); + if (mCurrentWindow && mCurrentWindow->handle()) { + if (mCurrentWindow.data() != window || !inputMethodAccepted()) { + struct ::wl_surface *surface = static_cast(mCurrentWindow->handle())->object(); + textInput()->disable(surface); + mCurrentWindow.clear(); + } + } + + if (window && window->handle() && inputMethodAccepted()) { + if (mCurrentWindow.data() != window) { + struct ::wl_surface *surface = static_cast(window->handle())->object(); + textInput()->enable(surface); + mCurrentWindow = window; + } + textInput()->updateState(Qt::ImQueryAll, QtWayland::zwp_text_input_v2::update_state_enter); + } } -bool QWaylandInputContext::ensureTextInput() +QWaylandTextInput *QWaylandInputContext::textInput() const { - if (mTextInput) - return true; - - if (!isValid()) - return false; - - mTextInput.reset(new QWaylandTextInput(mDisplay->textInputManager()->create_text_input())); - return true; + return mDisplay->defaultInputDevice()->textInput(); } } QT_END_NAMESPACE - diff --git a/src/plugins/platforms/wayland/qwaylandinputcontext_p.h b/src/plugins/platforms/wayland/qwaylandinputcontext_p.h index cdabfcca492..0429dd14e19 100644 --- a/src/plugins/platforms/wayland/qwaylandinputcontext_p.h +++ b/src/plugins/platforms/wayland/qwaylandinputcontext_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Klarälvdalens Datakonsult AB (KDAB). +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWaylandClient module of the Qt Toolkit. @@ -54,36 +54,75 @@ #include -#include +#include +#include +#include +#include + +#include +#include QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(qLcQpaInputMethods) + namespace QtWaylandClient { class QWaylandDisplay; -class QWaylandTextInput : public QtWayland::wl_text_input +class QWaylandTextInput : public QtWayland::zwp_text_input_v2 { public: - QWaylandTextInput(struct ::wl_text_input *text_input); - - QString commitString() const; + QWaylandTextInput(QWaylandDisplay *display, struct ::zwp_text_input_v2 *text_input); + ~QWaylandTextInput(); void reset(); - void updateState(); + void commit(); + void updateState(Qt::InputMethodQueries queries, uint32_t flags); + + bool isInputPanelVisible() const; + QRectF keyboardRect() const; + + QLocale locale() const; + Qt::LayoutDirection inputDirection() const; protected: - void text_input_preedit_string(uint32_t serial, const QString &text, const QString &commit) Q_DECL_OVERRIDE; - void text_input_commit_string(uint32_t serial, const QString &text) Q_DECL_OVERRIDE; - void text_input_enter(wl_surface *surface) Q_DECL_OVERRIDE; - void text_input_leave() Q_DECL_OVERRIDE; - void text_input_keysym(uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers); + void zwp_text_input_v2_enter(uint32_t serial, struct ::wl_surface *surface) Q_DECL_OVERRIDE; + void zwp_text_input_v2_leave(uint32_t serial, struct ::wl_surface *surface) Q_DECL_OVERRIDE; + void zwp_text_input_v2_modifiers_map(wl_array *map) Q_DECL_OVERRIDE; + void zwp_text_input_v2_input_panel_state(uint32_t state, int32_t x, int32_t y, int32_t width, int32_t height) Q_DECL_OVERRIDE; + void zwp_text_input_v2_preedit_string(const QString &text, const QString &commit) Q_DECL_OVERRIDE; + void zwp_text_input_v2_preedit_styling(uint32_t index, uint32_t length, uint32_t style) Q_DECL_OVERRIDE; + void zwp_text_input_v2_preedit_cursor(int32_t index) Q_DECL_OVERRIDE; + void zwp_text_input_v2_commit_string(const QString &text) Q_DECL_OVERRIDE; + void zwp_text_input_v2_cursor_position(int32_t index, int32_t anchor) Q_DECL_OVERRIDE; + void zwp_text_input_v2_delete_surrounding_text(uint32_t before_length, uint32_t after_length) Q_DECL_OVERRIDE; + void zwp_text_input_v2_keysym(uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) Q_DECL_OVERRIDE; + void zwp_text_input_v2_language(const QString &language) Q_DECL_OVERRIDE; + void zwp_text_input_v2_text_direction(uint32_t direction) Q_DECL_OVERRIDE; + void zwp_text_input_v2_input_method_changed(uint32_t serial, uint32_t flags) Q_DECL_OVERRIDE; private: - QString m_commit; + Qt::KeyboardModifiers modifiersToQtModifiers(uint32_t modifiers); + + QWaylandDisplay *m_display; + QWaylandInputMethodEventBuilder m_builder; + + QVector m_modifiersMap; uint32_t m_serial; - uint32_t m_resetSerial; + struct ::wl_surface *m_surface; + + QString m_preeditCommit; + + bool m_inputPanelVisible; + QRectF m_keyboardRectangle; + QLocale m_locale; + Qt::LayoutDirection m_inputDirection; + + struct ::wl_callback *m_resetCallback; + static const wl_callback_listener callbackListener; + static void resetCallback(void *data, struct wl_callback *wl_callback, uint32_t time); }; class QWaylandInputContext : public QPlatformInputContext @@ -91,25 +130,29 @@ class QWaylandInputContext : public QPlatformInputContext Q_OBJECT public: explicit QWaylandInputContext(QWaylandDisplay *display); + ~QWaylandInputContext(); bool isValid() const Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; void commit() Q_DECL_OVERRIDE; void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE; - void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE; void showInputPanel() Q_DECL_OVERRIDE; void hideInputPanel() Q_DECL_OVERRIDE; bool isInputPanelVisible() const Q_DECL_OVERRIDE; + QRectF keyboardRect() const Q_DECL_OVERRIDE; + + QLocale locale() const Q_DECL_OVERRIDE; + Qt::LayoutDirection inputDirection() const Q_DECL_OVERRIDE; void setFocusObject(QObject *object) Q_DECL_OVERRIDE; private: - bool ensureTextInput(); + QWaylandTextInput *textInput() const; QWaylandDisplay *mDisplay; - QScopedPointer mTextInput; + QPointer mCurrentWindow; }; } diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp index 46c473e7075..cf1c7ac448e 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -50,6 +50,7 @@ #include "qwaylanddisplay_p.h" #include "qwaylandshmbackingstore_p.h" #include "../shared/qwaylandxkb.h" +#include "qwaylandinputcontext_p.h" #include #include @@ -185,6 +186,7 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, , mKeyboard(0) , mPointer(0) , mTouch(0) + , mTextInput(0) , mTime(0) , mSerial(0) , mTouchDevice(0) @@ -193,6 +195,9 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, mDataDevice = mQDisplay->dndSelectionHandler()->getDataDevice(this); } + if (mQDisplay->textInputManager()) { + mTextInput = new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat())); + } } QWaylandInputDevice::~QWaylandInputDevice() @@ -277,6 +282,16 @@ QWaylandDataDevice *QWaylandInputDevice::dataDevice() const return mDataDevice; } +void QWaylandInputDevice::setTextInput(QWaylandTextInput *textInput) +{ + mTextInput = textInput; +} + +QWaylandTextInput *QWaylandInputDevice::textInput() const +{ + return mTextInput; +} + void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button) { if (mPointer) @@ -693,19 +708,9 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, Qt::KeyboardModifiers modifiers = mParent->modifiers(); - uint utf32 = xkb_keysym_to_utf32(sym); - if (utf32) - text = QString::fromUcs4(&utf32, 1); - + text = QWaylandXkb::textFromKeysym(sym, modifiers); qtkey = QWaylandXkb::keysymToQtKey(sym, modifiers, text); - - // Map control + letter to proper text - if (utf32 >= 'A' && utf32 <= '~' && (modifiers & Qt::ControlModifier)) { - utf32 &= ~0x60; - text = QString::fromUcs4(&utf32, 1); - } - sendKey(window->window(), time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); #else // Generic fallback for single hard keys: Assume 'key' is a Qt key code. diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h index 0da45c38473..82b9d90c346 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h +++ b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h @@ -80,6 +80,7 @@ namespace QtWaylandClient { class QWaylandWindow; class QWaylandDisplay; class QWaylandDataDevice; +class QWaylandTextInput; class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice : public QObject @@ -108,6 +109,9 @@ public: void setDataDevice(QWaylandDataDevice *device); QWaylandDataDevice *dataDevice() const; + void setTextInput(QWaylandTextInput *textInput); + QWaylandTextInput *textInput() const; + void removeMouseButtonFromState(Qt::MouseButton button); QWaylandWindow *pointerFocus() const; @@ -138,6 +142,8 @@ private: Pointer *mPointer; Touch *mTouch; + QWaylandTextInput *mTextInput; + uint32_t mTime; uint32_t mSerial; diff --git a/src/plugins/platforms/wayland/shared/qwaylandinputmethodeventbuilder.cpp b/src/plugins/platforms/wayland/shared/qwaylandinputmethodeventbuilder.cpp new file mode 100644 index 00000000000..eb527c15a0a --- /dev/null +++ b/src/plugins/platforms/wayland/shared/qwaylandinputmethodeventbuilder.cpp @@ -0,0 +1,286 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandinputmethodeventbuilder.h" + +#include +#include + +#ifdef QT_BUILD_WAYLANDCOMPOSITOR_LIB +#include +#else +#include +#endif + +QT_BEGIN_NAMESPACE + +QWaylandInputMethodEventBuilder::QWaylandInputMethodEventBuilder() + : m_anchor(0) + , m_cursor(0) + , m_deleteBefore(0) + , m_deleteAfter(0) + , m_preeditCursor(0) + , m_preeditStyles() +{ +} + +QWaylandInputMethodEventBuilder::~QWaylandInputMethodEventBuilder() +{ +} + +void QWaylandInputMethodEventBuilder::reset() +{ + m_anchor = 0; + m_cursor = 0; + m_deleteBefore = 0; + m_deleteAfter = 0; + m_preeditCursor = 0; + m_preeditStyles.clear(); +} + +void QWaylandInputMethodEventBuilder::setCursorPosition(int32_t index, int32_t anchor) +{ + m_cursor = index; + m_anchor = anchor; +} + +void QWaylandInputMethodEventBuilder::setDeleteSurroundingText(uint32_t beforeLength, uint32_t afterLength) +{ + m_deleteBefore = beforeLength; + m_deleteAfter = afterLength; +} + +void QWaylandInputMethodEventBuilder::addPreeditStyling(uint32_t index, uint32_t length, uint32_t style) +{ + QTextCharFormat format; + + switch (style) { + case 0: + case 1: + format.setFontUnderline(true); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); + m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format)); + break; + case 2: + case 3: + format.setFontWeight(QFont::Bold); + format.setFontUnderline(true); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); + m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format)); + break; + case 4: + format.setFontUnderline(true); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); + m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format)); + case 5: + format.setFontUnderline(true); + format.setUnderlineStyle(QTextCharFormat::WaveUnderline); + format.setUnderlineColor(QColor(Qt::red)); + m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format)); + break; +// case QtWayland::wl_text_input::preedit_style_selection: +// case QtWayland::wl_text_input::preedit_style_none: + default: + break; + } +} + +void QWaylandInputMethodEventBuilder::setPreeditCursor(int32_t index) +{ + m_preeditCursor = index; +} + +QInputMethodEvent QWaylandInputMethodEventBuilder::buildCommit(const QString &text) +{ + QList attributes; + + const QPair replacement = replacementForDeleteSurrounding(); + + if (m_cursor != 0 || m_anchor != 0) { + QString surrounding = QInputMethod::queryFocusObject(Qt::ImSurroundingText, QVariant()).toString(); + const int cursor = QInputMethod::queryFocusObject(Qt::ImCursorPosition, QVariant()).toInt(); + const int anchor = QInputMethod::queryFocusObject(Qt::ImAnchorPosition, QVariant()).toInt(); + const int absoluteCursor = QInputMethod::queryFocusObject(Qt::ImAbsolutePosition, QVariant()).toInt(); + + const int absoluteOffset = absoluteCursor - cursor; + + const int cursorAfterCommit = qMin(anchor, cursor) + replacement.first + text.length(); + surrounding.replace(qMin(anchor, cursor) + replacement.first, + qAbs(anchor - cursor) + replacement.second, text); + + attributes.push_back(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, + indexFromWayland(surrounding, m_cursor, cursorAfterCommit) + absoluteOffset, + indexFromWayland(surrounding, m_anchor, cursorAfterCommit) + absoluteOffset, + QVariant())); + } + + QInputMethodEvent event(QString(), attributes); + event.setCommitString(text, replacement.first, replacement.second); + + return event; +} + +QInputMethodEvent QWaylandInputMethodEventBuilder::buildPreedit(const QString &text) +{ + QList attributes; + + if (m_preeditCursor < 0) { + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant())); + } else if (m_preeditCursor > 0) { + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, indexFromWayland(text, m_preeditCursor), 1, QVariant())); + } + + Q_FOREACH (const QInputMethodEvent::Attribute &attr, m_preeditStyles) { + int start = indexFromWayland(text, attr.start); + int length = indexFromWayland(text, attr.start + attr.length) - start; + attributes.append(QInputMethodEvent::Attribute(attr.type, start, length, attr.value)); + } + + QInputMethodEvent event(text, attributes); + + const QPair replacement = replacementForDeleteSurrounding(); + event.setCommitString(QString(), replacement.first, replacement.second); + + return event; +} + +QPair QWaylandInputMethodEventBuilder::replacementForDeleteSurrounding() +{ + if (m_deleteBefore == 0 && m_deleteAfter == 0) + return QPair(0, 0); + + const QString &surrounding = QInputMethod::queryFocusObject(Qt::ImSurroundingText, QVariant()).toString(); + const int cursor = QInputMethod::queryFocusObject(Qt::ImCursorPosition, QVariant()).toInt(); + const int anchor = QInputMethod::queryFocusObject(Qt::ImAnchorPosition, QVariant()).toInt(); + + const int selectionStart = qMin(cursor, anchor); + const int selectionEnd = qMax(cursor, anchor); + + const int deleteBefore = selectionStart - indexFromWayland(surrounding, -m_deleteBefore, selectionStart); + const int deleteAfter = indexFromWayland(surrounding, m_deleteAfter, selectionEnd) - selectionEnd; + + return QPair(-deleteBefore, deleteBefore + deleteAfter); +} + +QWaylandInputMethodContentType QWaylandInputMethodContentType::convert(Qt::InputMethodHints hints) +{ + uint32_t hint = ZWP_TEXT_INPUT_V2_CONTENT_HINT_NONE; + uint32_t purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NORMAL; + + if (hints & Qt::ImhHiddenText) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_HIDDEN_TEXT; + } + if (hints & Qt::ImhSensitiveData) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_SENSITIVE_DATA; + } + if ((hints & Qt::ImhNoAutoUppercase) == 0) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CAPITALIZATION; + } + if (hints & Qt::ImhPreferNumbers) { + // Nothing yet + } + if (hints & Qt::ImhPreferUppercase) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE; + } + if (hints & Qt::ImhPreferLowercase) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE; + } + if ((hints & Qt::ImhNoPredictiveText) == 0) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_COMPLETION | ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CORRECTION; + } + + if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime) == 0) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATE; + } else if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime)) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATETIME; + } else if ((hints & Qt::ImhDate) == 0 && (hints & Qt::ImhTime)) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TIME; + } + + if (hints & Qt::ImhPreferLatin) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN; + } + + if (hints & Qt::ImhMultiLine) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_MULTILINE; + } + + if (hints & Qt::ImhDigitsOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DIGITS; + } + if (hints & Qt::ImhFormattedNumbersOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NUMBER; + } + if (hints & Qt::ImhUppercaseOnly) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE; + } + if (hints & Qt::ImhLowercaseOnly) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE; + } + if (hints & Qt::ImhDialableCharactersOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PHONE; + } + if (hints & Qt::ImhEmailCharactersOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_EMAIL; + } + if (hints & Qt::ImhUrlCharactersOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_URL; + } + if (hints & Qt::ImhLatinOnly) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN; + } + return QWaylandInputMethodContentType{hint, purpose}; +} + +int QWaylandInputMethodEventBuilder::indexFromWayland(const QString &str, int utf8Index, int baseIndex) +{ + if (utf8Index == 0) + return baseIndex; + + if (utf8Index < 0) { + const QByteArray &utf8 = str.leftRef(baseIndex).toUtf8(); + return QString::fromUtf8(utf8.left(qMax(utf8.length() + utf8Index, 0))).length(); + } else { + const QByteArray &utf8 = str.midRef(baseIndex).toUtf8(); + return QString::fromUtf8(utf8.left(utf8Index)).length() + baseIndex; + } +} + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/wayland/shared/qwaylandinputmethodeventbuilder.h b/src/plugins/platforms/wayland/shared/qwaylandinputmethodeventbuilder.h new file mode 100644 index 00000000000..188a6a94b30 --- /dev/null +++ b/src/plugins/platforms/wayland/shared/qwaylandinputmethodeventbuilder.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDINPUTMETHODEVENTBUILDER_H +#define QWAYLANDINPUTMETHODEVENTBUILDER_H + +#include + +QT_BEGIN_NAMESPACE + +class QWaylandInputMethodEventBuilder +{ +public: + QWaylandInputMethodEventBuilder(); + ~QWaylandInputMethodEventBuilder(); + + void reset(); + + void setCursorPosition(int32_t index, int32_t anchor); + void setDeleteSurroundingText(uint32_t beforeLength, uint32_t afterLength); + + void addPreeditStyling(uint32_t index, uint32_t length, uint32_t style); + void setPreeditCursor(int32_t index); + + QInputMethodEvent buildCommit(const QString &text); + QInputMethodEvent buildPreedit(const QString &text); + + static int indexFromWayland(const QString &str, int utf8Index, int baseIndex = 0); +private: + QPair replacementForDeleteSurrounding(); + + int32_t m_anchor; + int32_t m_cursor; + uint32_t m_deleteBefore; + uint32_t m_deleteAfter; + + int32_t m_preeditCursor; + QList m_preeditStyles; +}; + +struct QWaylandInputMethodContentType { + uint32_t hint; + uint32_t purpose; + + static QWaylandInputMethodContentType convert(Qt::InputMethodHints hints); +}; + + +QT_END_NAMESPACE + +#endif // QWAYLANDINPUTMETHODEVENTBUILDER_H diff --git a/src/plugins/platforms/wayland/shared/qwaylandxkb.cpp b/src/plugins/platforms/wayland/shared/qwaylandxkb.cpp index f5d0527de39..32d24bd62d1 100644 --- a/src/plugins/platforms/wayland/shared/qwaylandxkb.cpp +++ b/src/plugins/platforms/wayland/shared/qwaylandxkb.cpp @@ -40,6 +40,7 @@ #include "qwaylandxkb.h" +#include #include #ifndef QT_NO_WAYLAND_XKB @@ -282,6 +283,16 @@ static int lookupKeysym(xkb_keysym_t key) return code; } +static xkb_keysym_t toKeysymFromTable(uint32_t key) +{ + for (int i = 0; KeyTbl[i]; i += 2) { + if (key == KeyTbl[i + 1]) + return KeyTbl[i]; + } + + return 0; +} + int QWaylandXkb::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text) { int code = 0; @@ -326,6 +337,50 @@ Qt::KeyboardModifiers QWaylandXkb::modifiers(struct xkb_state *state) return modifiers; } +QEvent::Type QWaylandXkb::toQtEventType(uint32_t state) +{ + return state != 0 ? QEvent::KeyPress : QEvent::KeyRelease; +} + +QString QWaylandXkb::textFromKeysym(uint32_t keysym, Qt::KeyboardModifiers modifiers) +{ + uint utf32 = xkb_keysym_to_utf32(keysym); + + // Map control + letter to proper text + if (utf32 >= 'A' && utf32 <= '~' && (modifiers & Qt::ControlModifier)) { + utf32 &= ~0x60; + return QString::fromUcs4(&utf32, 1); + } + + if (utf32) + return QString::fromUcs4(&utf32, 1); + + return QString(); +} + +QVector QWaylandXkb::toKeysym(QKeyEvent *event) +{ + QVector keysyms; + if (event->key() >= Qt::Key_F1 && event->key() <= Qt::Key_F35) { + keysyms.append(XKB_KEY_F1 + (event->key() - Qt::Key_F1)); + } else if (event->modifiers() & Qt::KeypadModifier) { + if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) + keysyms.append(XKB_KEY_KP_0 + (event->key() - Qt::Key_0)); + else + keysyms.append(toKeysymFromTable(event->key())); + } else if (!event->text().isEmpty()) { + // From libxkbcommon keysym-utf.c: + // "We allow to represent any UCS character in the range U-00000000 to + // U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff." + foreach (uint utf32, event->text().toUcs4()) { + keysyms.append(utf32 | 0x01000000); + } + } else { + keysyms.append(toKeysymFromTable(event->key())); + } + return keysyms; +} + QT_END_NAMESPACE #endif // QT_NO_WAYLAND_XKB diff --git a/src/plugins/platforms/wayland/shared/qwaylandxkb.h b/src/plugins/platforms/wayland/shared/qwaylandxkb.h index bfb38515f5f..9b5c935a5b5 100644 --- a/src/plugins/platforms/wayland/shared/qwaylandxkb.h +++ b/src/plugins/platforms/wayland/shared/qwaylandxkb.h @@ -44,15 +44,22 @@ #ifndef QT_NO_WAYLAND_XKB #include +#include #include QT_BEGIN_NAMESPACE +class QKeyEvent; + class QWaylandXkb { public: static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text); static Qt::KeyboardModifiers modifiers(struct xkb_state *state); + + static QEvent::Type toQtEventType(uint32_t state); + static QString textFromKeysym(uint32_t keysym, Qt::KeyboardModifiers modifiers); + static QVector toKeysym(QKeyEvent *event); }; QT_END_NAMESPACE