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
icc-effect-5.14.5
Martin Gräßlin 2016-08-29 17:04:13 +02:00
parent 5702c3f1bf
commit a98a1b1376
3 changed files with 54 additions and 3 deletions

View File

@ -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"

View File

@ -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);

View File

@ -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