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
This commit is contained in:
parent
5702c3f1bf
commit
a98a1b1376
3 changed files with 54 additions and 3 deletions
|
@ -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"
|
||||
|
|
|
@ -42,6 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <QTemporaryFile>
|
||||
// xkbcommon
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-compose.h>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
// system
|
||||
#include <sys/mman.h>
|
||||
|
@ -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<xkb_key_direction>(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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue