summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforminputcontexts/compose/compose.pro1
-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
6 files changed, 484 insertions, 445 deletions
diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro
index 8c73d29971..1bfd46ebca 100644
--- a/src/plugins/platforminputcontexts/compose/compose.pro
+++ b/src/plugins/platforminputcontexts/compose/compose.pro
@@ -23,7 +23,6 @@ contains(QT_CONFIG, xkbcommon-qt): {
} else {
LIBS += $$QMAKE_LIBS_XKBCOMMON
QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON
- LIBS += -lxkbcommon
}
OTHER_FILES += $$PWD/compose.json
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
}