From a98a1b1376a3fdec5ce40f476e7a8a79a9f84b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 29 Aug 2016 17:04:13 +0200 Subject: [PATCH] Support compose key in xkbcommon integration Summary: The Xkb class now creates a compose key table and a state object and feeds all key presses through the compose state machine. Xkb now tracks the latest keysym which is provided through new method currentKeysym. This is now used when creating a QKeyEvent instead of passing the key code to the xkb state. With that the keysym can also be updated through the compose state system. This only affects KWin internal usage where text is composed, e.g. the present windows effect filter. Wayland clients do not gain compose key support, though. Minimum xkbcommon version raised to 0.5 as compose key support is new in that version. Test Plan: Enabled compose key support in keymap and verified through DebugConsole Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D2622 --- CMakeLists.txt | 2 +- keyboard_input.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++-- keyboard_input.h | 11 +++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 06aa83c88a..69daa8ec01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,7 +158,7 @@ if(Wayland_Egl_FOUND) set(HAVE_WAYLAND_EGL TRUE) endif() -find_package(XKB 0.4.1) +find_package(XKB 0.5.0) set_package_properties(XKB PROPERTIES TYPE REQUIRED PURPOSE "Required for building KWin with Wayland support" diff --git a/keyboard_input.cpp b/keyboard_input.cpp index cf4dc00ea6..25ee022d30 100644 --- a/keyboard_input.cpp +++ b/keyboard_input.cpp @@ -42,6 +42,7 @@ along with this program. If not, see . #include // xkbcommon #include +#include #include // system #include @@ -90,12 +91,31 @@ Xkb::Xkb(InputRedirection *input) , m_altModifier(0) , m_metaModifier(0) , m_modifiers(Qt::NoModifier) + , m_keysym(XKB_KEY_NoSymbol) { if (!m_context) { qCDebug(KWIN_XKB) << "Could not create xkb context"; } else { xkb_context_set_log_level(m_context, XKB_LOG_LEVEL_DEBUG); xkb_context_set_log_fn(m_context, &xkbLogHandler); + + // get locale as described in xkbcommon doc + // cannot use QLocale as it drops the modifier part + QByteArray locale = qgetenv("LC_ALL"); + if (locale.isEmpty()) { + locale = qgetenv("LC_CTYPE"); + } + if (locale.isEmpty()) { + locale = qgetenv("LANG"); + } + if (locale.isEmpty()) { + locale = QByteArrayLiteral("C"); + } + + m_compose.table = xkb_compose_table_new_from_locale(m_context, locale.constData(), XKB_COMPOSE_COMPILE_NO_FLAGS); + if (m_compose.table) { + m_compose.state = xkb_compose_state_new(m_compose.table, XKB_COMPOSE_STATE_NO_FLAGS); + } } auto resetModOnlyShortcut = [this] { @@ -108,6 +128,8 @@ Xkb::Xkb(InputRedirection *input) Xkb::~Xkb() { + xkb_compose_state_unref(m_compose.state); + xkb_compose_table_unref(m_compose.table); xkb_state_unref(m_state); xkb_keymap_unref(m_keymap); xkb_context_unref(m_context); @@ -254,6 +276,24 @@ void Xkb::updateKey(uint32_t key, InputRedirection::KeyboardKeyState state) } const auto oldMods = m_modifiers; xkb_state_update_key(m_state, key + 8, static_cast(state)); + if (state == InputRedirection::KeyboardKeyPressed) { + const auto sym = toKeysym(key); + if (m_compose.state && xkb_compose_state_feed(m_compose.state, sym) == XKB_COMPOSE_FEED_ACCEPTED) { + switch (xkb_compose_state_get_status(m_compose.state)) { + case XKB_COMPOSE_NOTHING: + m_keysym = sym; + break; + case XKB_COMPOSE_COMPOSED: + m_keysym = xkb_compose_state_get_one_sym(m_compose.state); + break; + default: + m_keysym = XKB_KEY_NoSymbol; + break; + } + } else { + m_keysym = sym; + } + } updateModifiers(); if (state == InputRedirection::KeyboardKeyPressed) { m_modOnlyShortcut.pressCount++; @@ -525,13 +565,13 @@ void KeyboardInputRedirection::processKey(uint32_t key, InputRedirection::Keyboa } } - const xkb_keysym_t keySym = m_xkb->toKeysym(key); + const xkb_keysym_t keySym = m_xkb->currentKeysym(); KeyEvent event(type, m_xkb->toQtKey(keySym), m_xkb->modifiers(), key, keySym, - m_xkb->toString(m_xkb->toKeysym(key)), + m_xkb->toString(keySym), autoRepeat, time, device); diff --git a/keyboard_input.h b/keyboard_input.h index e47f06dceb..da0785985a 100644 --- a/keyboard_input.h +++ b/keyboard_input.h @@ -33,6 +33,8 @@ class QWindow; struct xkb_context; struct xkb_keymap; struct xkb_state; +struct xkb_compose_table; +struct xkb_compose_state; typedef uint32_t xkb_mod_index_t; typedef uint32_t xkb_keysym_t; @@ -58,6 +60,9 @@ public: void updateModifiers(uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group); void updateKey(uint32_t key, InputRedirection::KeyboardKeyState state); xkb_keysym_t toKeysym(uint32_t key); + xkb_keysym_t currentKeysym() const { + return m_keysym; + } QString toString(xkb_keysym_t keysym); Qt::Key toQtKey(xkb_keysym_t keysym); Qt::KeyboardModifiers modifiers() const; @@ -81,11 +86,17 @@ private: xkb_mod_index_t m_altModifier; xkb_mod_index_t m_metaModifier; Qt::KeyboardModifiers m_modifiers; + xkb_keysym_t m_keysym; struct { uint pressCount = 0; Qt::KeyboardModifier modifier = Qt::NoModifier; } m_modOnlyShortcut; quint32 m_currentLayout = 0; + + struct { + xkb_compose_table *table = nullptr; + xkb_compose_state *state = nullptr; + } m_compose; }; class KeyboardInputRedirection : public QObject