summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp34
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp172
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h44
-rw-r--r--src/plugins/platforms/xcb/xcb-plugin.pro6
4 files changed, 236 insertions, 20 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 34508260d9..7381c8c886 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -299,7 +299,10 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
}
xcb_extension_t *extensions[] = {
- &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, &xcb_xkb_id,
+ &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id,
+#ifndef QT_NO_XKB
+ &xcb_xkb_id,
+#endif
#ifdef XCB_USE_RENDER
&xcb_render_id,
#endif
@@ -747,6 +750,7 @@ void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev)
m_buttons &= ~translateMouseButton(event->detail);
}
+#ifndef QT_NO_XKB
namespace {
typedef union {
/* All XKB events share these fields. */
@@ -761,6 +765,7 @@ namespace {
xcb_xkb_state_notify_event_t state_notify;
} _xkb_event;
}
+#endif
void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
{
@@ -786,12 +791,21 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
case XCB_EXPOSE:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
case XCB_BUTTON_PRESS:
+#ifdef QT_NO_XKB
+ m_keyboard->updateXKBStateFromCore(((xcb_button_press_event_t *)event)->state);
+#endif
handleButtonPress(event);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
case XCB_BUTTON_RELEASE:
+#ifdef QT_NO_XKB
+ m_keyboard->updateXKBStateFromCore(((xcb_button_release_event_t *)event)->state);
+#endif
handleButtonRelease(event);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
case XCB_MOTION_NOTIFY:
+#ifdef QT_NO_XKB
+ m_keyboard->updateXKBStateFromCore(((xcb_motion_notify_event_t *)event)->state);
+#endif
HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
case XCB_CONFIGURE_NOTIFY:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
@@ -805,15 +819,29 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
case XCB_ENTER_NOTIFY:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
case XCB_LEAVE_NOTIFY:
+#ifdef QT_NO_XKB
+ m_keyboard->updateXKBStateFromCore(((xcb_leave_notify_event_t *)event)->state);
+#endif
HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
case XCB_FOCUS_IN:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
case XCB_FOCUS_OUT:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
case XCB_KEY_PRESS:
+#ifdef QT_NO_XKB
+ m_keyboard->updateXKBStateFromCore(((xcb_key_press_event_t *)event)->state);
+#endif
HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
case XCB_KEY_RELEASE:
+#ifdef QT_NO_XKB
+ m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->state);
+#endif
HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
+#ifdef QT_NO_XKB
+ case XCB_MAPPING_NOTIFY:
+ m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
+ break;
+#endif
case XCB_SELECTION_REQUEST:
{
xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
@@ -876,6 +904,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
}
}
handled = true;
+#ifndef QT_NO_XKB
} else if (response_type == xkb_first_event) { // https://bugs.freedesktop.org/show_bug.cgi?id=51295
_xkb_event *xkb_event = reinterpret_cast<_xkb_event *>(event);
if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) {
@@ -892,6 +921,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
break;
}
}
+#endif
}
}
@@ -1574,6 +1604,7 @@ void QXcbConnection::initializeXShape()
void QXcbConnection::initializeXKB()
{
+#ifndef QT_NO_XKB
const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xkb_id);
if (!reply || !reply->present) {
xkb_first_event = 0;
@@ -1629,6 +1660,7 @@ void QXcbConnection::initializeXKB()
qWarning() << "Qt: failed to select notify events from xcb-xkb";
return;
}
+#endif
}
#if defined(XCB_USE_EGL)
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index e7dabd3351..f1b26853a1 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -673,8 +673,9 @@ void QXcbKeyboard::updateKeymap()
xkb_state_unref(xkb_state);
xkb_state = new_state;
} else {
- // get initial state from the X server (and keep it up-to-date at all times)
xkb_state = new_state;
+#ifndef QT_NO_XKB
+ // get initial state from the X server (and keep it up-to-date at all times)
xcb_xkb_get_state_cookie_t state;
xcb_xkb_get_state_reply_t *init_state;
@@ -695,9 +696,13 @@ void QXcbKeyboard::updateKeymap()
init_state->latchedGroup,
init_state->lockedGroup);
free(init_state);
+#else
+ updateXKBMods();
+#endif
}
}
+#ifndef QT_NO_XKB
void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
{
if (!m_config)
@@ -715,11 +720,74 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
state->lockedGroup);
if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
- qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
+ //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
}
}
}
+#else
+void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
+{
+ if (!m_config)
+ return;
+
+ quint32 modsDepressed, modsLatched, modsLocked;
+ modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED);
+ modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
+ modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
+
+ quint32 xkbMask = xkbModMask(state);
+ xkb_state_component newState;
+ newState = xkb_state_update_mask(xkb_state,
+ modsDepressed & xkbMask,
+ modsLatched & xkbMask,
+ modsLocked & xkbMask,
+ 0,
+ 0,
+ (state >> 13) & 3); // bits 13 and 14 report the state keyboard group
+
+ if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
+ //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
+ }
+}
+
+quint32 QXcbKeyboard::xkbModMask(quint16 state)
+{
+ quint32 xkb_mask = 0;
+
+ if ((state & XCB_MOD_MASK_SHIFT) && xkb_mods.shift != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.shift);
+ if ((state & XCB_MOD_MASK_LOCK) && xkb_mods.lock != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.lock);
+ if ((state & XCB_MOD_MASK_CONTROL) && xkb_mods.control != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.control);
+ if ((state & XCB_MOD_MASK_1) && xkb_mods.mod1 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod1);
+ if ((state & XCB_MOD_MASK_2) && xkb_mods.mod2 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod2);
+ if ((state & XCB_MOD_MASK_3) && xkb_mods.mod3 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod3);
+ if ((state & XCB_MOD_MASK_4) && xkb_mods.mod4 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod4);
+ if ((state & XCB_MOD_MASK_5) && xkb_mods.mod5 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod5);
+
+ return xkb_mask;
+}
+
+void QXcbKeyboard::updateXKBMods()
+{
+ xkb_mods.shift = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_SHIFT);
+ xkb_mods.lock = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_CAPS);
+ xkb_mods.control = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_CTRL);
+ xkb_mods.mod1 = xkb_map_mod_get_index(xkb_keymap, "Mod1");
+ xkb_mods.mod2 = xkb_map_mod_get_index(xkb_keymap, "Mod2");
+ xkb_mods.mod3 = xkb_map_mod_get_index(xkb_keymap, "Mod3");
+ xkb_mods.mod4 = xkb_map_mod_get_index(xkb_keymap, "Mod4");
+ xkb_mods.mod5 = xkb_map_mod_get_index(xkb_keymap, "Mod5");
+}
+#endif
+
QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
{
// turn off the modifier bits which doesn't participate in shortcuts
@@ -846,11 +914,14 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
, xkb_context(0)
, xkb_keymap(0)
, xkb_state(0)
+#ifndef QT_NO_XKB
, core_device_id(0)
+#endif
{
+ updateKeymap();
+#ifndef QT_NO_XKB
if (connection->hasXKB()) {
- updateKeymap();
updateVModMapping();
updateVModToRModMapping();
@@ -871,6 +942,10 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
core_device_id = device_id->deviceID;
free(device_id);
}
+#else
+ m_key_symbols = xcb_key_symbols_alloc(xcb_connection());
+ updateModifiers();
+#endif
}
QXcbKeyboard::~QXcbKeyboard()
@@ -881,8 +956,12 @@ QXcbKeyboard::~QXcbKeyboard()
xkb_keymap_unref(xkb_keymap);
if (xkb_context)
xkb_context_unref(xkb_context);
+#ifdef QT_NO_XKB
+ xcb_key_symbols_free(m_key_symbols);
+#endif
}
+#ifndef QT_NO_XKB
void QXcbKeyboard::updateVModMapping()
{
xcb_xkb_get_names_cookie_t names_cookie;
@@ -1004,14 +1083,67 @@ void QXcbKeyboard::updateVModToRModMapping()
rmod_masks.altgr = modmap;
}
-#if 0
- qDebug() << "alt: " << rmod_masks.alt;
- qDebug() << "meta: " << rmod_masks.meta;
- qDebug() << "altgr: " << rmod_masks.altgr;
-#endif
-
free(map_reply);
}
+#else
+void QXcbKeyboard::updateModifiers()
+{
+ // The core protocol does not provide a convenient way to determine the mapping
+ // of modifier bits. Clients must retrieve and search the modifier map to determine
+ // the keycodes bound to each modifier, and then retrieve and search the keyboard
+ // mapping to determine the keysyms bound to the keycodes. They must repeat this
+ // process for all modifiers whenever any part of the modifier mapping is changed.
+ memset(&rmod_masks, 0, sizeof(rmod_masks));
+
+ xcb_generic_error_t *error = 0;
+ xcb_connection_t *conn = xcb_connection();
+ xcb_get_modifier_mapping_cookie_t modMapCookie = xcb_get_modifier_mapping(conn);
+ xcb_get_modifier_mapping_reply_t *modMapReply =
+ xcb_get_modifier_mapping_reply(conn, modMapCookie, &error);
+ if (error) {
+ qWarning("Qt: failed to get modifier mapping");
+ free(error);
+ return;
+ }
+
+ // for Alt and Meta L and R are the same
+ static const xcb_keysym_t symbols[] = {
+ XK_Alt_L, XK_Meta_L, XK_Mode_switch
+ };
+ static const size_t numSymbols = sizeof symbols / sizeof *symbols;
+
+ // Figure out the modifier mapping, ICCCM 6.6
+ xcb_keycode_t* modKeyCodes[numSymbols];
+ for (size_t i = 0; i < numSymbols; ++i)
+ modKeyCodes[i] = xcb_key_symbols_get_keycode(m_key_symbols, symbols[i]);
+
+ xcb_keycode_t *modMap = xcb_get_modifier_mapping_keycodes(modMapReply);
+ const int w = modMapReply->keycodes_per_modifier;
+ for (size_t i = 0; i < numSymbols; ++i) {
+ for (int bit = 0; bit < 8; ++bit) {
+ uint mask = 1 << bit;
+ for (int x = 0; x < w; ++x) {
+ xcb_keycode_t keyCode = modMap[x + bit * w];
+ xcb_keycode_t *itk = modKeyCodes[i];
+ while (itk && *itk != XCB_NO_SYMBOL)
+ if (*itk++ == keyCode) {
+ uint sym = symbols[i];
+ if ((sym == XK_Alt_L || sym == XK_Alt_R))
+ rmod_masks.alt = mask;
+ if ((sym == XK_Meta_L || sym == XK_Meta_R))
+ rmod_masks.meta = mask;
+ if (sym == XK_Mode_switch)
+ rmod_masks.altgr = mask;
+ }
+ }
+ }
+ }
+
+ for (size_t i = 0; i < numSymbols; ++i)
+ free(modKeyCodes[i]);
+ free(modMapReply);
+}
+#endif
class KeyChecker
{
@@ -1076,8 +1208,17 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
if (!m_config)
return;
-
+ // It is crucial the order of xkb_state_key_get_one_sym &
+ // xkb_state_update_key operations is not reversed!
xcb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, code);
+#ifdef QT_NO_XKB
+ enum xkb_key_direction direction;
+ if (type == QEvent::KeyPress)
+ direction = XKB_KEY_DOWN;
+ else
+ direction = XKB_KEY_UP;
+ xkb_state_update_key(xkb_state, code, direction);
+#endif
QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
QMetaMethod method;
@@ -1194,13 +1335,20 @@ void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindowEventListener *eventListener,
handleKeyEvent(window->window(), QEvent::KeyRelease, event->detail, event->state, event->time);
}
-void QXcbKeyboard::handleMappingNotifyEvent(const xcb_xkb_map_notify_event_t *)
+void QXcbKeyboard::handleMappingNotifyEvent(const void *event)
{
+ updateKeymap();
+#ifdef QT_NO_XKB
+ void *ev = const_cast<void *>(event);
+ xcb_refresh_keyboard_mapping(m_key_symbols, static_cast<xcb_mapping_notify_event_t *>(ev));
+ updateModifiers();
+#else
+ Q_UNUSED(event)
if (connection()->hasXKB()) {
- updateKeymap();
updateVModMapping();
updateVModToRModMapping();
}
+#endif
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 9c278eeb8c..af6677c20f 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -44,6 +44,10 @@
#include "qxcbobject.h"
+#ifdef QT_NO_XKB
+#include <xcb/xcb_keysyms.h>
+#endif
+
#include <xkbcommon/xkbcommon.h>
#include <QEvent>
@@ -62,14 +66,21 @@ public:
void handleKeyPressEvent(QXcbWindowEventListener *eventListener, const xcb_key_press_event_t *event);
void handleKeyReleaseEvent(QXcbWindowEventListener *eventListener, const xcb_key_release_event_t *event);
- void handleMappingNotifyEvent(const xcb_xkb_map_notify_event_t *event);
+ void handleMappingNotifyEvent(const void *event);
Qt::KeyboardModifiers translateModifiers(int s) const;
- QList<int> possibleKeys(const QKeyEvent *e) const;
void updateKeymap();
- void updateXKBState(xcb_xkb_state_notify_event_t *state);
+ QList<int> possibleKeys(const QKeyEvent *e) const;
+
+#ifdef QT_NO_XKB
+ void updateXKBStateFromCore(quint16 state);
+ void updateXKBMods();
+ quint32 xkbModMask(quint16 state);
+#else
int coreDeviceId() { return core_device_id; }
+ void updateXKBState(xcb_xkb_state_notify_event_t *state);
+#endif
protected:
void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time);
@@ -80,10 +91,16 @@ protected:
int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const;
void readXKBConfig(struct xkb_rule_names *names);
+
+#ifdef QT_NO_XKB
+ void updateModifiers();
+#else
void updateVModMapping();
void updateVModToRModMapping();
+#endif
private:
+ bool m_config;
xcb_keycode_t m_autorepeat_code;
struct xkb_context *xkb_context;
@@ -96,12 +113,27 @@ private:
uint meta;
};
- _mod_masks vmod_masks;
_mod_masks rmod_masks;
- int core_device_id;
+#ifdef QT_NO_XKB
+ xcb_key_symbols_t *m_key_symbols;
+
+ struct _xkb_mods {
+ xkb_mod_index_t shift;
+ xkb_mod_index_t lock;
+ xkb_mod_index_t control;
+ xkb_mod_index_t mod1;
+ xkb_mod_index_t mod2;
+ xkb_mod_index_t mod3;
+ xkb_mod_index_t mod4;
+ xkb_mod_index_t mod5;
+ };
- bool m_config;
+ _xkb_mods xkb_mods;
+#else
+ _mod_masks vmod_masks;
+ int core_device_id;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro
index e7d8802021..e8d52ebf2f 100644
--- a/src/plugins/platforms/xcb/xcb-plugin.pro
+++ b/src/plugins/platforms/xcb/xcb-plugin.pro
@@ -111,7 +111,11 @@ contains(QT_CONFIG, xcb-qt) {
} else {
LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr
!contains(DEFINES, QT_NO_SHAPE):LIBS += -lxcb-shape
- !contains(DEFINES, QT_NO_XKB):LIBS += -lxcb-xkb
+ contains(DEFINES, QT_NO_XKB) {
+ LIBS += -lxcb-keysyms
+ } else {
+ LIBS += -lxcb-xkb
+ }
}
# libxkbcommon