summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@digia.com>2013-03-25 14:44:48 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-05-07 22:43:14 +0200
commit05351b0cde3e80d2d0ae3a838e802ff6086e4b59 (patch)
treedbcbb18247aafe9485e7ccbbbc903c858bb1c75d /src/plugins/platforms
parent9c1d62cc95ed2579fa25d83901c7a1aa315aa2d3 (diff)
Utilize libxkbcommon API for the keyboard backend on X11
libxkbcommon is a keymap compiler [1] which utilizes xkb keyboard configuration database [2]. xkbcommon simplifies keyboard state handling by providing xkb_state object which holds the current state of all modifiers, groups, LEDs, etc, relating to the provided keymap. Detecting modifier mapping should become simpler once it gets supported in libxkbcommon. Also with xinput2 we could get rid of the XkbStateNotify events, because xinput2 key press/release already include all the mod/group info. [1] http://xkbcommon.org/ [2] http://www.freedesktop.org/wiki/Software/XKeyboardConfig This patch: - Removes a dependency to -lxcb-keysyms - Removes a dependency to XLib call - XLookupString - Enables required functionality to fix QTBUG-27681 Task-number: QTBUG-27680 Change-Id: I10e10f873821ee02f6df72238e215a541150f38f Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp118
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h14
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp727
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h58
-rw-r--r--src/plugins/platforms/xcb/xcb-plugin.pro11
5 files changed, 484 insertions, 444 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index a7c60cac84..34508260d9 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -253,11 +253,13 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
#endif
, xfixes_first_event(0)
, xrandr_first_event(0)
+ , xkb_first_event(0)
, has_glx_extension(false)
, has_shape_extension(false)
, has_randr_extension(false)
, has_input_shape(false)
, has_touch_without_mouse_emulation(false)
+ , has_xkb(false)
, m_buttons(0)
, m_focusWindow(0)
{
@@ -297,7 +299,7 @@ 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_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, &xcb_xkb_id,
#ifdef XCB_USE_RENDER
&xcb_render_id,
#endif
@@ -336,6 +338,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeXInput2();
#endif
initializeXShape();
+ initializeXKB();
m_wmSupport.reset(new QXcbWMSupport(this));
m_keyboard = new QXcbKeyboard(this);
@@ -479,7 +482,6 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event)
PRINT_XCB_EVENT(XCB_SELECTION_NOTIFY);
PRINT_XCB_EVENT(XCB_COLORMAP_NOTIFY);
PRINT_XCB_EVENT(XCB_CLIENT_MESSAGE);
- PRINT_XCB_EVENT(XCB_MAPPING_NOTIFY);
default:
qDebug("QXcbConnection: %s: unknown event - response_type: %d - sequence: %d", message, int(event->response_type & ~0x80), int(event->sequence));
}
@@ -745,6 +747,21 @@ void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev)
m_buttons &= ~translateMouseButton(event->detail);
}
+namespace {
+ typedef union {
+ /* All XKB events share these fields. */
+ struct {
+ uint8_t response_type;
+ uint8_t xkbType;
+ uint16_t sequence;
+ xcb_timestamp_t time;
+ uint8_t deviceID;
+ } any;
+ xcb_xkb_map_notify_event_t map_notify;
+ xcb_xkb_state_notify_event_t state_notify;
+ } _xkb_event;
+}
+
void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
{
#ifdef Q_XCB_DEBUG
@@ -797,9 +814,6 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
case XCB_KEY_RELEASE:
HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
- case XCB_MAPPING_NOTIFY:
- m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
- break;
case XCB_SELECTION_REQUEST:
{
xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
@@ -862,6 +876,22 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
}
}
handled = true;
+ } 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()) {
+ switch (xkb_event->any.xkbType) {
+ case XCB_XKB_STATE_NOTIFY:
+ m_keyboard->updateXKBState(&xkb_event->state_notify);
+ handled = true;
+ break;
+ case XCB_XKB_MAP_NOTIFY:
+ m_keyboard->handleMappingNotifyEvent(&xkb_event->map_notify);
+ handled = true;
+ break;
+ default:
+ break;
+ }
+ }
}
}
@@ -869,7 +899,6 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
if (!handled) {
// Check if a custom XEvent constructor was registered in xlib for this event type, and call it discarding the constructed XEvent if any.
// XESetWireToEvent might be used by libraries to intercept messages from the X server e.g. the OpenGL lib waiting for DRI2 events.
-
Display *xdisplay = (Display *)m_xlib_display;
XLockDisplay(xdisplay);
Bool (*proc)(Display*, XEvent*, xEvent*) = XESetWireToEvent(xdisplay, response_type, 0);
@@ -1017,32 +1046,36 @@ namespace
xcb_timestamp_t QXcbConnection::getTimestamp()
{
// send a dummy event to myself to get the timestamp from X server.
- xcb_window_t rootWindow = screens().at(primaryScreen())->root();
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, rootWindow, atom(QXcbAtom::CLIP_TEMPORARY),
+ xcb_window_t root_win = rootWindow();
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, root_win, atom(QXcbAtom::CLIP_TEMPORARY),
XCB_ATOM_INTEGER, 32, 0, NULL);
connection()->flush();
- PropertyNotifyEvent checker(rootWindow, atom(QXcbAtom::CLIP_TEMPORARY));
+ PropertyNotifyEvent checker(root_win, atom(QXcbAtom::CLIP_TEMPORARY));
xcb_generic_event_t *event = 0;
// lets keep this inside a loop to avoid a possible race condition, where
// reader thread has not yet had the time to acquire the mutex in order
// to add the new set of events to its event queue
- while (true) {
+ while (!event) {
connection()->sync();
- if ((event = checkEvent(checker)))
- break;
+ event = checkEvent(checker);
}
xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
xcb_timestamp_t timestamp = pn->time;
free(event);
- xcb_delete_property(xcb_connection(), rootWindow, atom(QXcbAtom::CLIP_TEMPORARY));
+ xcb_delete_property(xcb_connection(), root_win, atom(QXcbAtom::CLIP_TEMPORARY));
return timestamp;
}
+xcb_window_t QXcbConnection::rootWindow()
+{
+ return screens().at(primaryScreen())->root();
+}
+
void QXcbConnection::processXcbEvents()
{
int connection_error = xcb_connection_has_error(xcb_connection());
@@ -1539,6 +1572,65 @@ void QXcbConnection::initializeXShape()
free(shape_query);
}
+void QXcbConnection::initializeXKB()
+{
+ const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xkb_id);
+ if (!reply || !reply->present) {
+ xkb_first_event = 0;
+ return;
+ }
+ xkb_first_event = reply->first_event;
+
+ xcb_connection_t *c = connection()->xcb_connection();
+ xcb_xkb_use_extension_cookie_t xkb_query_cookie;
+ xcb_xkb_use_extension_reply_t *xkb_query;
+
+ xkb_query_cookie = xcb_xkb_use_extension(c, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION);
+ xkb_query = xcb_xkb_use_extension_reply(c, xkb_query_cookie, 0);
+
+ if (!xkb_query) {
+ qWarning("Qt: Failed to initialize XKB extension");
+ return;
+ } else if (!xkb_query->supported) {
+ qWarning("Qt: Unsupported XKB version (want %d %d, has %d %d)",
+ XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION,
+ xkb_query->serverMajor, xkb_query->serverMinor);
+ free(xkb_query);
+ return;
+ }
+
+ has_xkb = true;
+ free(xkb_query);
+
+ uint affectMap, map;
+ affectMap = map = XCB_XKB_MAP_PART_KEY_TYPES |
+ XCB_XKB_MAP_PART_KEY_SYMS |
+ XCB_XKB_MAP_PART_MODIFIER_MAP |
+ XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
+ XCB_XKB_MAP_PART_KEY_ACTIONS |
+ XCB_XKB_MAP_PART_KEY_BEHAVIORS |
+ XCB_XKB_MAP_PART_VIRTUAL_MODS |
+ XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP;
+
+ // Xkb events are reported to all interested clients without regard
+ // to the current keyboard input focus or grab state
+ xcb_void_cookie_t select = xcb_xkb_select_events_checked(c,
+ XCB_XKB_ID_USE_CORE_KBD,
+ XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY,
+ 0,
+ XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY,
+ affectMap,
+ map,
+ 0);
+
+ xcb_generic_error_t *error = xcb_request_check(c, select);
+ if (error) {
+ free(error);
+ qWarning() << "Qt: failed to select notify events from xcb-xkb";
+ return;
+ }
+}
+
#if defined(XCB_USE_EGL)
bool QXcbConnection::hasEgl() const
{
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 1d6f09a2bc..3aa13a8b3a 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -53,6 +53,14 @@
#include <QVarLengthArray>
#include <qpa/qwindowsysteminterface.h>
+// This is needed to make Qt compile together with XKB. xkb.h is using a variable
+// which is called 'explicit', this is a reserved keyword in c++ */
+#ifndef QT_NO_XKB
+#define explicit dont_use_cxx_explicit
+#include <xcb/xkb.h>
+#undef explicit
+#endif
+
#ifndef QT_NO_TABLETEVENT
#include <QTabletEvent>
#endif
@@ -355,7 +363,7 @@ public:
#endif
QXcbWMSupport *wmSupport() const { return m_wmSupport.data(); }
-
+ xcb_window_t rootWindow();
#ifdef XCB_USE_XLIB
void *xlib_display() const { return m_xlib_display; }
#endif
@@ -402,6 +410,7 @@ public:
bool hasXRandr() const { return has_randr_extension; }
bool hasInputShape() const { return has_input_shape; }
bool hasTouchWithoutMouseEmulation() const { return has_touch_without_mouse_emulation; }
+ bool hasXKB() const { return has_xkb; }
bool supportsThreadedRendering() const { return m_reader->isRunning(); }
@@ -430,6 +439,7 @@ private:
void initializeXRender();
void initializeXRandr();
void initializeXShape();
+ void initializeXKB();
#ifdef XCB_USE_XINPUT2_MAEMO
void initializeXInput2Maemo();
void finalizeXInput2Maemo();
@@ -539,12 +549,14 @@ private:
uint32_t xfixes_first_event;
uint32_t xrandr_first_event;
+ uint32_t xkb_first_event;
bool has_glx_extension;
bool has_shape_extension;
bool has_randr_extension;
bool has_input_shape;
bool has_touch_without_mouse_emulation;
+ bool has_xkb;
Qt::MouseButtons m_buttons;
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 51c400ed9c..1a96a49890 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -42,8 +42,6 @@
#include "qxcbkeyboard.h"
#include "qxcbwindow.h"
#include "qxcbscreen.h"
-#include "qxlibconvenience.h"
-#include <xcb/xcb_keysyms.h>
#include <X11/keysym.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/QTextCodec>
@@ -561,183 +559,158 @@ static const unsigned int KeyTbl[] = {
0, 0
};
-static const unsigned short katakanaKeysymsToUnicode[] = {
- 0x0000, 0x3002, 0x300C, 0x300D, 0x3001, 0x30FB, 0x30F2, 0x30A1,
- 0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30E3, 0x30E5, 0x30E7, 0x30C3,
- 0x30FC, 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD,
- 0x30AF, 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD,
- 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC,
- 0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, 0x30DE,
- 0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9,
- 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F3, 0x309B, 0x309C
-};
+Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const
+{
+ Qt::KeyboardModifiers ret = 0;
+ if (s & XCB_MOD_MASK_SHIFT)
+ ret |= Qt::ShiftModifier;
+ if (s & XCB_MOD_MASK_CONTROL)
+ ret |= Qt::ControlModifier;
+ if (s & rmod_masks.alt)
+ ret |= Qt::AltModifier;
+ if (s & rmod_masks.meta)
+ ret |= Qt::MetaModifier;
+ if (s & rmod_masks.altgr)
+ ret |= Qt::GroupSwitchModifier;
+ return ret;
+}
-static const unsigned short cyrillicKeysymsToUnicode[] = {
- 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457,
- 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0000, 0x045e, 0x045f,
- 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407,
- 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0000, 0x040e, 0x040f,
- 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
- 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
- 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
- 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a,
- 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
- 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
- 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
- 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a
-};
+void QXcbKeyboard::readXKBConfig(struct xkb_rule_names *xkb_names)
+{
+ xcb_generic_error_t *error;
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *config_reply;
-static const unsigned short greekKeysymsToUnicode[] = {
- 0x0000, 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c,
- 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015,
- 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc,
- 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
- 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
- 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
- 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
- 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
- 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
- 0x03c8, 0x03c9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
-};
+ xcb_connection_t *c = xcb_connection();
+ xcb_window_t rootWindow = connection()->rootWindow();
-static const unsigned short technicalKeysymsToUnicode[] = {
- 0x0000, 0x23B7, 0x250C, 0x2500, 0x2320, 0x2321, 0x2502, 0x23A1,
- 0x23A3, 0x23A4, 0x23A6, 0x239B, 0x239D, 0x239E, 0x23A0, 0x23A8,
- 0x23AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222B,
- 0x2234, 0x221D, 0x221E, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000,
- 0x223C, 0x2243, 0x0000, 0x0000, 0x0000, 0x21D4, 0x21D2, 0x2261,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221A, 0x0000,
- 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222A, 0x2227, 0x2228,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193, 0x0000
-};
+ cookie = xcb_get_property(c, 0, rootWindow,
+ atom(QXcbAtom::_XKB_RULES_NAMES), XCB_ATOM_STRING, 0, 1024);
-static const unsigned short specialKeysymsToUnicode[] = {
- 0x25C6, 0x2592, 0x2409, 0x240C, 0x240D, 0x240A, 0x0000, 0x0000,
- 0x2424, 0x240B, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x23BA,
- 0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251C, 0x2524, 0x2534, 0x252C,
- 0x2502, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
-};
+ config_reply = xcb_get_property_reply(c, cookie, &error);
+ if (!config_reply) {
+ qWarning("Qt: Couldn't interpret the _XKB_RULES_NAMES property");
+ return;
+ }
+ char *xkb_config = (char *)xcb_get_property_value(config_reply);
+ int length = xcb_get_property_value_length(config_reply);
+
+ char *names[5] = { 0, 0, 0, 0, 0 };
+ char *p = xkb_config, *end = p + length;
+ int i = 0;
+ // The result from xcb_get_property_value() is not necessarily \0-terminated,
+ // we need to make sure that too many or missing '\0' symbols are handled safely.
+ do {
+ uint len = qstrnlen(p, length);
+ names[i++] = p;
+ p += len + 1;
+ length -= len + 1;
+ } while (p < end || i < 5);
+
+ xkb_names->rules = qstrdup(names[0]);
+ xkb_names->model = qstrdup(names[1]);
+ xkb_names->layout = qstrdup(names[2]);
+ xkb_names->variant = qstrdup(names[3]);
+ xkb_names->options = qstrdup(names[4]);
+
+ free(config_reply);
+}
-static const unsigned short publishingKeysymsToUnicode[] = {
- 0x0000, 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009,
- 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025,
- 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a,
- 0x2105, 0x0000, 0x0000, 0x2012, 0x2329, 0x0000, 0x232a, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000,
- 0x0000, 0x2122, 0x2613, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25af,
- 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033,
- 0x0000, 0x271d, 0x0000, 0x25ac, 0x25c0, 0x25b6, 0x25cf, 0x25ae,
- 0x25e6, 0x25ab, 0x25ad, 0x25b3, 0x25bd, 0x2606, 0x2022, 0x25aa,
- 0x25b2, 0x25bc, 0x261c, 0x261e, 0x2663, 0x2666, 0x2665, 0x0000,
- 0x2720, 0x2020, 0x2021, 0x2713, 0x2717, 0x266f, 0x266d, 0x2642,
- 0x2640, 0x260e, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e, 0x0000
-};
+void QXcbKeyboard::updateKeymap()
+{
+ m_config = true;
+ if (!xkb_context) {
+ xkb_context = xkb_context_new((xkb_context_flags)0);
+ if (!xkb_context) {
+ qWarning("Qt: Failed to create XKB context");
+ m_config = false;
+ return;
+ }
+ }
-static const unsigned short aplKeysymsToUnicode[] = {
- 0x0000, 0x0000, 0x0000, 0x003c, 0x0000, 0x0000, 0x003e, 0x0000,
- 0x2228, 0x2227, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x00af, 0x0000, 0x22a5, 0x2229, 0x230a, 0x0000, 0x005f, 0x0000,
- 0x0000, 0x0000, 0x2218, 0x0000, 0x2395, 0x0000, 0x22a4, 0x25cb,
- 0x0000, 0x0000, 0x0000, 0x2308, 0x0000, 0x0000, 0x222a, 0x0000,
- 0x2283, 0x0000, 0x2282, 0x0000, 0x22a2, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x22a3, 0x0000, 0x0000, 0x0000
-};
+ struct xkb_rule_names xkb_names = {0, 0, 0, 0, 0};
-static const unsigned short koreanKeysymsToUnicode[] = {
- 0x0000, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137,
- 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f,
- 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147,
- 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x314f,
- 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156, 0x3157,
- 0x3158, 0x3159, 0x315a, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f,
- 0x3160, 0x3161, 0x3162, 0x3163, 0x11a8, 0x11a9, 0x11aa, 0x11ab,
- 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3,
- 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb,
- 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x316d,
- 0x3171, 0x3178, 0x317f, 0x3181, 0x3184, 0x3186, 0x318d, 0x318e,
- 0x11eb, 0x11f0, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9
-};
+ readXKBConfig(&xkb_names);
+ // Compile a keymap from RMLVO (rules, models, layouts, variants and options) names
+ if (xkb_keymap)
+ xkb_keymap_unref(xkb_keymap);
-static QChar keysymToUnicode(unsigned char byte3, unsigned char byte4)
-{
- switch (byte3) {
- case 0x04:
- // katakana
- if (byte4 > 0xa0 && byte4 < 0xe0)
- return QChar(katakanaKeysymsToUnicode[byte4 - 0xa0]);
- else if (byte4 == 0x7e)
- return QChar(0x203e); // Overline
- break;
- case 0x06:
- // russian, use lookup table
- if (byte4 > 0xa0)
- return QChar(cyrillicKeysymsToUnicode[byte4 - 0xa0]);
- break;
- case 0x07:
- // greek
- if (byte4 > 0xa0)
- return QChar(greekKeysymsToUnicode[byte4 - 0xa0]);
- break;
- case 0x08:
- // technical
- if (byte4 > 0xa0)
- return QChar(technicalKeysymsToUnicode[byte4 - 0xa0]);
- break;
- case 0x09:
- // special
- if (byte4 >= 0xe0)
- return QChar(specialKeysymsToUnicode[byte4 - 0xe0]);
- break;
- case 0x0a:
- // publishing
- if (byte4 > 0xa0)
- return QChar(publishingKeysymsToUnicode[byte4 - 0xa0]);
- break;
- case 0x0b:
- // APL
- if (byte4 > 0xa0)
- return QChar(aplKeysymsToUnicode[byte4 - 0xa0]);
- break;
- case 0x0e:
- // Korean
- if (byte4 > 0xa0)
- return QChar(koreanKeysymsToUnicode[byte4 - 0xa0]);
- break;
- default:
- break;
+ xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0);
+
+ delete[] xkb_names.rules;
+ delete[] xkb_names.model;
+ delete[] xkb_names.layout;
+ delete[] xkb_names.variant;
+ delete[] xkb_names.options;
+
+ if (!xkb_keymap) {
+ qWarning("Qt: Failed to compile a keymap");
+ m_config = false;
+ return;
+ }
+ // Create a new keyboard state object for a keymap
+ struct xkb_state *new_state = xkb_state_new(xkb_keymap);
+ if (!new_state) {
+ qWarning("Qt: Failed to create a new keyboard state");
+ m_config = false;
+ return;
+ }
+
+ if (xkb_state) {
+ 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;
+ xcb_xkb_get_state_cookie_t state;
+ xcb_xkb_get_state_reply_t *init_state;
+
+ xcb_connection_t *c = xcb_connection();
+ state = xcb_xkb_get_state(c, XCB_XKB_ID_USE_CORE_KBD);
+ init_state = xcb_xkb_get_state_reply(c, state, 0);
+ if (!init_state) {
+ qWarning("Qt: couldn't retrieve an initial keyboard state");
+ return;
+ }
+ /* The xkb keyboard state is comprised of the state of all keyboard modifiers,
+ the keyboard group, and the state of the pointer buttons */
+ xkb_state_update_mask(xkb_state,
+ init_state->baseMods,
+ init_state->latchedMods,
+ init_state->lockedMods,
+ init_state->baseGroup,
+ init_state->latchedGroup,
+ init_state->lockedGroup);
+ free(init_state);
}
- return QChar(0x0);
}
-Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s)
+void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
{
- Qt::KeyboardModifiers ret = 0;
- if (s & XCB_MOD_MASK_SHIFT)
- ret |= Qt::ShiftModifier;
- if (s & XCB_MOD_MASK_CONTROL)
- ret |= Qt::ControlModifier;
- if (s & m_alt_mask)
- ret |= Qt::AltModifier;
- if (s & m_meta_mask)
- ret |= Qt::MetaModifier;
- return ret;
+ if (!m_config)
+ return;
+
+ if (connection()->hasXKB()) {
+
+ xkb_state_component newState;
+ newState = xkb_state_update_mask(xkb_state,
+ state->baseMods,
+ state->latchedMods,
+ state->lockedMods,
+ state->baseGroup,
+ state->latchedGroup,
+ state->lockedGroup);
+
+ if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
+ qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
+ }
+ }
}
-int QXcbKeyboard::translateKeySym(uint key) const
+int QXcbKeyboard::keysymToQtKey(xcb_keysym_t key) const
{
- int code = -1;
- int i = 0; // any other keys
+ int code = 0;
+ int i = 0;
while (KeyTbl[i]) {
if (key == KeyTbl[i]) {
code = (int)KeyTbl[i+1];
@@ -745,104 +718,20 @@ int QXcbKeyboard::translateKeySym(uint key) const
}
i += 2;
}
- if (m_meta_mask) {
- // translate Super/Hyper keys to Meta if we're using them as the MetaModifier
- if (m_meta_mask == m_super_mask && (code == Qt::Key_Super_L || code == Qt::Key_Super_R)) {
- code = Qt::Key_Meta;
- } else if (m_meta_mask == m_hyper_mask && (code == Qt::Key_Hyper_L || code == Qt::Key_Hyper_R)) {
- code = Qt::Key_Meta;
- }
- }
+
return code;
}
-QString QXcbKeyboard::translateKeySym(xcb_keysym_t keysym, uint xmodifiers,
- int &code, Qt::KeyboardModifiers &modifiers,
- QByteArray &chars, int &count)
+int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const
{
- // all keysyms smaller than 0xff00 are actally keys that can be mapped to unicode chars
-
- QTextCodec *mapper = QTextCodec::codecForLocale();
- QChar converted;
-
- if (/*count == 0 &&*/ keysym < 0xff00) {
- unsigned char byte3 = (unsigned char)(keysym >> 8);
- int mib = -1;
- switch(byte3) {
- case 0: // Latin 1
- case 1: // Latin 2
- case 2: //latin 3
- case 3: // latin4
- mib = byte3 + 4; break;
- case 5: // arabic
- mib = 82; break;
- case 12: // Hebrew
- mib = 85; break;
- case 13: // Thai
- mib = 2259; break;
- case 4: // kana
- case 6: // cyrillic
- case 7: // greek
- case 8: // technical, no mapping here at the moment
- case 9: // Special
- case 10: // Publishing
- case 11: // APL
- case 14: // Korean, no mapping
- mib = -1; // manual conversion
- mapper= 0;
-#if !defined(QT_NO_XIM)
- converted = keysymToUnicode(byte3, keysym & 0xff);
-#endif
- case 0x20:
- // currency symbols
- if (keysym >= 0x20a0 && keysym <= 0x20ac) {
- mib = -1; // manual conversion
- mapper = 0;
- converted = (uint)keysym;
- }
- break;
- default:
- break;
- }
- if (mib != -1) {
- mapper = QTextCodec::codecForMib(mib);
- if (chars.isEmpty())
- chars.resize(1);
- chars[0] = (unsigned char) (keysym & 0xff); // get only the fourth bit for conversion later
- count = 1;
- }
- } else if (keysym >= 0x1000000 && keysym <= 0x100ffff) {
- converted = (ushort) (keysym - 0x1000000);
- mapper = 0;
- }
- if (count < (int)chars.size()-1)
- chars[count] = '\0';
-
- QString text;
- if (!mapper && converted.unicode() != 0x0) {
- text = converted;
- } else if (!chars.isEmpty()) {
- // convert chars (8bit) to text (unicode).
- if (mapper)
- text = mapper->toUnicode(chars.data(), count, 0);
- if (text.isEmpty()) {
- // no mapper, or codec couldn't convert to unicode (this
- // can happen when running in the C locale or with no LANG
- // set). try converting from latin-1
- text = QString::fromLatin1(chars);
- }
- }
-
- modifiers = translateModifiers(xmodifiers);
-
+ int code = 0;
+ QTextCodec *systemCodec = QTextCodec::codecForLocale();
// Commentary in X11/keysymdef says that X codes match ASCII, so it
// is safe to use the locale functions to process X codes in ISO8859-1.
- //
// This is mainly for compatibility - applications should not use the
- // Qt keycodes between 128 and 255, but should rather use the
- // QKeyEvent::text().
- //
- if (keysym < 128 || (keysym < 256 && (!mapper || mapper->mibEnum()==4))) {
+ // Qt keycodes between 128 and 255 (extended ACSII codes), but should
+ // rather use the QKeyEvent::text().
+ if (keysym < 128 || (keysym < 256 && systemCodec->mibEnum() == 4)) {
// upper-case key, if known
code = isprint((int)keysym) ? toupper((int)keysym) : 0;
} else if (keysym >= XK_F1 && keysym <= XK_F35) {
@@ -853,138 +742,193 @@ QString QXcbKeyboard::translateKeySym(xcb_keysym_t keysym, uint xmodifiers,
// numeric keypad keys
code = Qt::Key_0 + ((int)keysym - XK_KP_0);
} else {
- code = translateKeySym(keysym);
+ code = keysymToQtKey(keysym);
}
modifiers |= Qt::KeypadModifier;
- } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f && text.unicode()->unicode() != 0x7f && !(keysym >= XK_dead_grave && keysym <= XK_dead_horn)) {
+ } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f
+ && text.unicode()->unicode() != 0x7f
+ && !(keysym >= XK_dead_grave && keysym <= XK_dead_currency)) {
code = text.unicode()->toUpper().unicode();
} else {
// any other keys
- code = translateKeySym(keysym);
-
- if (code == Qt::Key_Tab && (modifiers & Qt::ShiftModifier)) {
- // map shift+tab to shift+backtab, QShortcutMap knows about it
- // and will handle it.
- code = Qt::Key_Backtab;
- text = QString();
- }
+ code = keysymToQtKey(keysym);
}
- return text;
+ return code;
}
QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
: QXcbObject(connection)
, m_autorepeat_code(0)
+ , xkb_context(0)
+ , xkb_keymap(0)
+ , xkb_state(0)
+ , core_device_id(0)
{
- m_key_symbols = xcb_key_symbols_alloc(xcb_connection());
- setupModifiers();
+ if (connection->hasXKB()) {
+
+ updateKeymap();
+ updateVModMapping();
+ updateVModToRModMapping();
+
+ // get the core keyboard id
+ xcb_xkb_get_device_info_cookie_t device_id_cookie;
+ xcb_xkb_get_device_info_reply_t *device_id;
+
+ device_id_cookie = xcb_xkb_get_device_info(xcb_connection(),
+ XCB_XKB_ID_USE_CORE_KBD,
+ 0, 0, 0, 0, 0, 0);
+
+ device_id = xcb_xkb_get_device_info_reply(xcb_connection(), device_id_cookie, 0);
+ if (!device_id) {
+ qWarning("Qt: couldn't get core keyboard device info");
+ return;
+ }
+
+ core_device_id = device_id->deviceID;
+ free(device_id);
+ }
}
QXcbKeyboard::~QXcbKeyboard()
{
- xcb_key_symbols_free(m_key_symbols);
+ if (xkb_state)
+ xkb_state_unref(xkb_state);
+ if (xkb_keymap)
+ xkb_keymap_unref(xkb_keymap);
+ if (xkb_context)
+ xkb_context_unref(xkb_context);
}
-void QXcbKeyboard::setupModifiers()
+void QXcbKeyboard::updateVModMapping()
{
- m_alt_mask = 0;
- m_super_mask = 0;
- m_hyper_mask = 0;
- m_meta_mask = 0;
- m_mode_switch_mask = 0;
- m_num_lock_mask = 0;
- m_caps_lock_mask = 0;
-
- 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("QXcbKeyboard: failed to get modifier mapping");
- free(error);
+ xcb_xkb_get_names_cookie_t names_cookie;
+ xcb_xkb_get_names_reply_t *name_reply;
+ xcb_xkb_get_names_value_list_t names_list;
+
+ memset(&vmod_masks, 0, sizeof(vmod_masks));
+
+ names_cookie = xcb_xkb_get_names(xcb_connection(),
+ XCB_XKB_ID_USE_CORE_KBD,
+ XCB_XKB_NAME_DETAIL_VIRTUAL_MOD_NAMES);
+
+ name_reply = xcb_xkb_get_names_reply(xcb_connection(), names_cookie, 0);
+ if (!name_reply) {
+ qWarning("Qt: failed to retrieve the virtual modifier names from XKB");
return;
}
- // for Alt and Meta L and R are the same
- static const xcb_keysym_t symbols[] = {
- XK_Alt_L, XK_Meta_L, XK_Super_L, XK_Super_R,
- XK_Hyper_L, XK_Hyper_R, XK_Num_Lock, XK_Mode_switch, XK_Caps_Lock,
- };
- 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)
- setMask(symbols[i], mask);
- }
- }
+ const void *buffer = xcb_xkb_get_names_value_list(name_reply);
+ xcb_xkb_get_names_value_list_unpack(buffer,
+ name_reply->nTypes,
+ name_reply->indicators,
+ name_reply->virtualMods,
+ name_reply->groupNames,
+ name_reply->nKeys,
+ name_reply->nKeyAliases,
+ name_reply->nRadioGroups,
+ name_reply->which,
+ &names_list);
+
+ int count = 0;
+ uint vmod_mask, bit;
+ char *vmod_name;
+ vmod_mask = name_reply->virtualMods;
+ // find the virtual modifiers for which names are defined.
+ for (bit = 1; vmod_mask; bit <<= 1) {
+ vmod_name = 0;
+
+ if (!(vmod_mask & bit))
+ continue;
+
+ vmod_mask &= ~bit;
+ // virtualModNames - the list of virtual modifier atoms beginning with the lowest-numbered
+ // virtual modifier for which a name is defined and proceeding to the highest.
+ QByteArray atomName = connection()->atomName(names_list.virtualModNames[count]);
+ vmod_name = atomName.data();
+ count++;
+
+ if (!vmod_name)
+ continue;
+
+ // similarly we could retrieve NumLock, Super, Hyper modifiers if needed.
+ if (qstrcmp(vmod_name, "Alt") == 0)
+ vmod_masks.alt = bit;
+ else if (qstrcmp(vmod_name, "Meta") == 0)
+ vmod_masks.meta = bit;
+ else if (qstrcmp(vmod_name, "AltGr") == 0)
+ vmod_masks.altgr = bit;
}
- for (size_t i = 0; i < numSymbols; ++i)
- free(modKeyCodes[i]);
- free(modMapReply);
+ free(name_reply);
}
-void QXcbKeyboard::setMask(uint sym, uint mask)
+void QXcbKeyboard::updateVModToRModMapping()
{
- if (m_alt_mask == 0
- && m_meta_mask != mask
- && m_super_mask != mask
- && m_hyper_mask != mask
- && (sym == XK_Alt_L || sym == XK_Alt_R))
- m_alt_mask = mask;
-
- if (m_meta_mask == 0
- && m_alt_mask != mask
- && m_super_mask != mask
- && m_hyper_mask != mask
- && (sym == XK_Meta_L || sym == XK_Meta_R))
- m_meta_mask = mask;
-
- if (m_super_mask == 0
- && m_alt_mask != mask
- && m_meta_mask != mask
- && m_hyper_mask != mask
- && (sym == XK_Super_L || sym == XK_Super_R))
- m_super_mask = mask;
-
- if (m_hyper_mask == 0
- && m_alt_mask != mask
- && m_meta_mask != mask
- && m_super_mask != mask
- && (sym == XK_Hyper_L || sym == XK_Hyper_R))
- m_hyper_mask = mask;
-
- if (m_mode_switch_mask == 0
- && m_alt_mask != mask
- && m_meta_mask != mask
- && m_super_mask != mask
- && m_hyper_mask != mask
- && sym == XK_Mode_switch)
- m_mode_switch_mask = mask;
-
- if (m_num_lock_mask == 0 && sym == XK_Num_Lock)
- m_num_lock_mask = mask;
-
- if (m_caps_lock_mask == 0 && sym == XK_Caps_Lock)
- m_caps_lock_mask = mask;
-}
+ xcb_xkb_get_map_cookie_t map_cookie;
+ xcb_xkb_get_map_reply_t *map_reply;
+ xcb_xkb_get_map_map_t map;
-// #define XCB_KEYBOARD_DEBUG
+ memset(&rmod_masks, 0, sizeof(rmod_masks));
+
+ map_cookie = xcb_xkb_get_map(xcb_connection(),
+ XCB_XKB_ID_USE_CORE_KBD,
+ XCB_XKB_MAP_PART_VIRTUAL_MODS,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ map_reply = xcb_xkb_get_map_reply(xcb_connection(), map_cookie, 0);
+ if (!map_reply) {
+ qWarning("Qt: failed to retrieve the virtual modifier map from XKB");
+ return;
+ }
+
+ const void *buffer = xcb_xkb_get_map_map(map_reply);
+ xcb_xkb_get_map_map_unpack(buffer,
+ map_reply->nTypes,
+ map_reply->nKeySyms,
+ map_reply->nKeyActions,
+ map_reply->totalActions,
+ map_reply->totalKeyBehaviors,
+ map_reply->nVModMapKeys,
+ map_reply->totalKeyExplicit,
+ map_reply->totalModMapKeys,
+ map_reply->totalVModMapKeys,
+ map_reply->present,
+ &map);
+
+ uint vmod_mask, bit;
+ // the virtual modifiers mask for which a set of corresponding
+ // real modifiers is to be returned
+ vmod_mask = map_reply->virtualMods;
+ int count = 0;
+
+ for (bit = 1; vmod_mask; bit <<= 1) {
+ uint modmap;
+
+ if (!(vmod_mask & bit))
+ continue;
+
+ vmod_mask &= ~bit;
+ // real modifier bindings for the specified virtual modifiers
+ modmap = map.vmods_rtrn[count];
+ count++;
+
+ if (vmod_masks.alt == bit)
+ rmod_masks.alt = modmap;
+ else if (vmod_masks.meta == bit)
+ rmod_masks.meta = modmap;
+ else if (vmod_masks.altgr == bit)
+ 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);
+}
class KeyChecker
{
@@ -1046,16 +990,12 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
quint16 state, xcb_timestamp_t time)
{
Q_XCB_NOOP(connection());
-#ifdef XCB_KEYBOARD_DEBUG
- printf("key code: %d, state: %d, syms: ", code, state);
- for (int i = 0; i <= 5; ++i) {
- printf("%d ", xcb_key_symbols_get_keysym(m_key_symbols, code, i));
- }
- printf("\n");
-#endif
- QByteArray chars;
- xcb_keysym_t sym = lookupString(window, state, code, type, &chars);
+ if (!m_config)
+ return;
+
+ xcb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, code);
+
QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
QMetaMethod method;
@@ -1077,12 +1017,12 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
return;
}
- Qt::KeyboardModifiers modifiers;
- int qtcode = 0;
- int count = chars.count();
- QString string = translateKeySym(sym, state, qtcode, modifiers, chars, count);
+ Qt::KeyboardModifiers modifiers = translateModifiers(state);
+ QString string = keysymToUnicode(sym);
+ int count = string.size();
string.truncate(count);
+ int qtcode = keysymToQtKey(sym, modifiers, string);
bool isAutoRepeat = false;
if (type == QEvent::KeyPress) {
@@ -1141,35 +1081,17 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
}
}
-xcb_keysym_t QXcbKeyboard::lookupString(QWindow *window, uint state, xcb_keycode_t code,
- QEvent::Type type, QByteArray *chars)
+QString QXcbKeyboard::keysymToUnicode(xcb_keysym_t sym) const
{
-#ifdef XCB_USE_XLIB
- xcb_window_t xWindow = static_cast<QXcbWindow *>(window->handle())->xcb_window();
- xcb_window_t root = connection()->screens().at(0)->root();
- void *xDisplay = connection()->xlib_display();
- int xType = (type == QEvent::KeyRelease ? 3 : 2);
- return q_XLookupString(xDisplay, xWindow, root, state, code, xType, chars);
-#else
-
- // No XLookupString available. The following is really incomplete...
-
- int col = state & XCB_MOD_MASK_SHIFT ? 1 : 0;
- const int altGrOffset = 4;
- if (state & 128)
- col += altGrOffset;
- xcb_keysym_t sym = xcb_key_symbols_get_keysym(m_key_symbols, code, col);
- if (sym == XCB_NO_SYMBOL)
- sym = xcb_key_symbols_get_keysym(m_key_symbols, code, col ^ 0x1);
- if (state & XCB_MOD_MASK_LOCK && sym <= 0x7f && isprint(sym)) {
- if (isupper(sym))
- sym = tolower(sym);
- else
- sym = toupper(sym);
- }
- return sym;
+ QByteArray chars;
+ int bytes;
+ chars.resize(7);
-#endif
+ if ((bytes = xkb_keysym_to_utf8(sym, chars.data(), chars.size())) == -1)
+ qWarning("QXcbKeyboard::handleKeyEvent - buffer too small");
+ chars.resize(bytes-1);
+
+ return QString::fromUtf8(chars);
}
void QXcbKeyboard::handleKeyPressEvent(QXcbWindowEventListener *eventListener, const xcb_key_press_event_t *event)
@@ -1189,10 +1111,13 @@ void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindowEventListener *eventListener,
handleKeyEvent(window->window(), QEvent::KeyRelease, event->detail, event->state, event->time);
}
-void QXcbKeyboard::handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event)
+void QXcbKeyboard::handleMappingNotifyEvent(const xcb_xkb_map_notify_event_t *)
{
- xcb_refresh_keyboard_mapping(m_key_symbols, const_cast<xcb_mapping_notify_event_t *>(event));
- setupModifiers();
+ if (connection()->hasXKB()) {
+ updateKeymap();
+ updateVModMapping();
+ updateVModToRModMapping();
+ }
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 3c71daa57f..ff774197d2 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -44,7 +44,7 @@
#include "qxcbobject.h"
-#include "xcb/xcb_keysyms.h"
+#include <xkbcommon/xkbcommon.h>
#include <QEvent>
@@ -56,37 +56,51 @@ class QXcbKeyboard : public QXcbObject
{
public:
QXcbKeyboard(QXcbConnection *connection);
+
~QXcbKeyboard();
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_mapping_notify_event_t *event);
+ void handleMappingNotifyEvent(const xcb_xkb_map_notify_event_t *event);
- Qt::KeyboardModifiers translateModifiers(int s);
+ Qt::KeyboardModifiers translateModifiers(int s) const;
-private:
+ void updateKeymap();
+ void updateXKBState(xcb_xkb_state_notify_event_t *state);
+ int coreDeviceId() { return core_device_id; }
+
+protected:
void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time);
- int translateKeySym(uint key) const;
- QString translateKeySym(xcb_keysym_t keysym, uint xmodifiers,
- int &code, Qt::KeyboardModifiers &modifiers,
- QByteArray &chars, int &count);
- void setupModifiers();
- void setMask(uint sym, uint mask);
- xcb_keysym_t lookupString(QWindow *window, uint state, xcb_keycode_t code,
- QEvent::Type type, QByteArray *chars);
-
- uint m_alt_mask;
- uint m_super_mask;
- uint m_hyper_mask;
- uint m_meta_mask;
- uint m_mode_switch_mask;
- uint m_num_lock_mask;
- uint m_caps_lock_mask;
-
- xcb_key_symbols_t *m_key_symbols;
+ QString keysymToUnicode(xcb_keysym_t sym) const;
+
+ int keysymToQtKey(xcb_keysym_t keysym) const;
+ int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const;
+
+ void readXKBConfig(struct xkb_rule_names *names);
+ void updateVModMapping();
+ void updateVModToRModMapping();
+
+private:
xcb_keycode_t m_autorepeat_code;
+
+ struct xkb_context *xkb_context;
+ struct xkb_keymap *xkb_keymap;
+ struct xkb_state *xkb_state;
+
+ struct _mod_masks {
+ uint alt;
+ uint altgr;
+ uint meta;
+ };
+
+ _mod_masks vmod_masks;
+ _mod_masks rmod_masks;
+
+ int core_device_id;
+
+ bool m_config;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro
index eb90f0ae10..e7d8802021 100644
--- a/src/plugins/platforms/xcb/xcb-plugin.pro
+++ b/src/plugins/platforms/xcb/xcb-plugin.pro
@@ -20,8 +20,7 @@ SOURCES = \
main.cpp \
qxcbnativeinterface.cpp \
qxcbcursor.cpp \
- qxcbimage.cpp \
- qxlibconvenience.cpp
+ qxcbimage.cpp
HEADERS = \
qxcbclipboard.h \
@@ -37,12 +36,11 @@ HEADERS = \
qxcbwmsupport.h \
qxcbnativeinterface.h \
qxcbcursor.h \
- qxcbimage.h \
- qxlibconvenience.h
+ qxcbimage.h
LIBS += -ldl
-# needed by GLX, Xcursor, XLookupString, ...
+# needed by GLX, Xcursor ...
contains(QT_CONFIG, xcb-xlib) {
DEFINES += XCB_USE_XLIB
LIBS += -lX11 -lX11-xcb
@@ -111,7 +109,7 @@ contains(QT_CONFIG, xcb-qt) {
INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/sysinclude
LIBS += -lxcb -L$$OUT_PWD/xcb-static -lxcb-static
} else {
- LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr
+ 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
}
@@ -122,5 +120,4 @@ contains(QT_CONFIG, xkbcommon-qt): {
} else {
LIBS += $$QMAKE_LIBS_XKBCOMMON
QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON
- LIBS += -lxkbcommon
}