Merge remote-tracking branch 'origin/5.11' into dev

Change-Id: Icddf8720dae2cf594e16bcddab4d1cafc9d094c0
This commit is contained in:
Qt Forward Merge Bot 2018-02-24 21:29:47 +01:00
commit 8a9f77ead1
12 changed files with 434 additions and 2280 deletions

View File

@ -298,8 +298,6 @@ Gui, printing, widget options:
-xinput2 ........... Enable XInput2 support [auto]
-xkbcommon-x11 ..... Select xkbcommon used in combination with xcb
[system/qt/no]
-xkb-config-root <dir> ... With -qt-xkbcommon-x11, set default XKB config
root <dir> [detect]
-xkbcommon-evdev ... Enable X-less xkbcommon in combination with libinput
[auto]

View File

@ -6,7 +6,7 @@ INCLUDEPATH += $$PWD/xkbcommon \
include($$shadowed($$PWD/../gui/qtgui-config.pri))
DEFINES += DFLT_XKB_CONFIG_ROOT='\\"$$QMAKE_XKB_CONFIG_ROOT\\"'
DEFINES += DFLT_XKB_CONFIG_ROOT='\\"/usr/share/X11/xkb\\"' # unused, but needs to be set to something
### RMLVO names can be overwritten with environmental variables (see libxkbcommon documentation)
DEFINES += DEFAULT_XKB_RULES='\\"evdev\\"'

View File

@ -318,7 +318,8 @@ QJsonArray QJsonArray::fromVariantList(const QVariantList &list)
array.a->tableOffset = currentOffset;
if (!array.detach2(sizeof(QJsonPrivate::offset)*values.size()))
return QJsonArray();
memcpy(array.a->table(), values.constData(), values.size()*sizeof(uint));
memcpy(static_cast<void *>(array.a->table()),
static_cast<const void *>(values.constData()), values.size()*sizeof(uint));
array.a->length = values.size();
array.a->size = currentOffset + sizeof(QJsonPrivate::offset)*values.size();

View File

@ -651,7 +651,8 @@ public:
inline void reserve(int extraCapacity) {
if (tos + extraCapacity + 1 > cap) {
cap = qMax(tos + extraCapacity + 1, cap << 1 );
data = reinterpret_cast<T *>(realloc(data, cap * sizeof(T)));
void *ptr = realloc(static_cast<void *>(data), cap * sizeof(T));
data = reinterpret_cast<T *>(ptr);
Q_CHECK_PTR(data);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,6 @@
"xcb-xlib": "boolean",
"xinput2": "boolean",
"xkb": "boolean",
"xkb-config-root": "string",
"xkbcommon": { "type": "enum", "values": [ "no", "qt", "system" ] },
"xkbcommon-evdev": "boolean",
"xkbcommon-x11": { "type": "enum", "name": "xkbcommon", "values": [ "no", "qt", "system" ] }
@ -624,8 +623,7 @@
},
"testTypeAliases": {
"files": [ "directX" ],
"getPkgConfigVariable": [ "xkbConfigRoot" ]
"files": [ "directX" ]
},
"tests": {
@ -888,13 +886,6 @@
"value": "/usr",
"log": "value"
},
"xkbconfigroot": {
"label": "XKB config root",
"type": "xkbConfigRoot",
"pkg-config-args": "xkeyboard-config",
"pkg-config-variable": "xkb_base",
"log": "value"
},
"xlib": {
"label": "XLib",
"type": "compile",
@ -1355,12 +1346,6 @@
"condition": "libs.xkbcommon_x11",
"output": [ "privateFeature" ]
},
"xkb-config-root": {
"label": "XKB config root",
"emitIf": "features.xcb",
"condition": "features.xcb && !features.xkbcommon-system && tests.xkbconfigroot",
"output": [ { "type": "varAssign", "name": "QMAKE_XKB_CONFIG_ROOT", "value": "tests.xkbconfigroot.value"} ]
},
"xlib": {
"label": "XLib",
"autoDetect": "!config.darwin || features.xcb",
@ -1579,12 +1564,6 @@
],
"report": [
{
"type": "warning",
"condition": "features.xcb && !features.xkbcommon-system && !features.xkb-config-root",
"message": "Could not find XKB config root, use -xkb-config-root to set a path to
XKB configuration data. This is required for keyboard input support."
},
{
"type": "note",
"condition": "features.xcb && config.darwin",

View File

@ -42,21 +42,6 @@ defineTest(qtConfTest_directX) {
return(false)
}
defineTest(qtConfTest_xkbConfigRoot) {
qtConfTest_getPkgConfigVariable($${1}): return(true)
for (dir, $$list("/usr/share/X11/xkb", "/usr/local/share/X11/xkb")) {
exists($$dir) {
$${1}.value = $$dir
export($${1}.value)
$${1}.cache += value
export($${1}.cache)
return(true)
}
}
return(false)
}
defineTest(qtConfTest_qpaDefaultPlatform) {
name =
!isEmpty(config.input.qpa_default_platform): name = $$config.input.qpa_default_platform

View File

@ -39,18 +39,17 @@
#include "qxcbkeyboard.h"
#include "qxcbwindow.h"
#include "qxcbscreen.h"
#include "qxcbxkbcommon.h"
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatforminputcontext.h>
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformcursor.h>
#include <QtCore/QTextCodec>
#include <QtCore/QMetaMethod>
#include <QtCore/QDir>
#include <QtCore/QMetaEnum>
#include <private/qguiapplication_p.h>
#include <stdio.h>
#include <X11/keysym.h>
#if QT_CONFIG(xinput2)
@ -59,12 +58,6 @@
#undef KeyRelease
#endif
#if QT_CONFIG(xcb_xlib)
#include <X11/Xutil.h>
#undef KeyPress
#undef KeyRelease
#endif
#ifndef XK_ISO_Left_Tab
#define XK_ISO_Left_Tab 0xFE20
#endif
@ -706,76 +699,6 @@ Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const
return ret;
}
void QXcbKeyboard::readXKBConfig()
{
clearXKBConfig();
xcb_connection_t *c = xcb_connection();
xcb_window_t rootWindow = connection()->rootWindow();
auto config_reply = Q_XCB_REPLY(xcb_get_property, c, 0, rootWindow,
atom(QXcbAtom::_XKB_RULES_NAMES), XCB_ATOM_STRING, 0, 1024);
if (!config_reply) {
qWarning("Qt: Couldn't interpret the _XKB_RULES_NAMES property");
return;
}
char *xkb_config = (char *)xcb_get_property_value(config_reply.get());
int length = xcb_get_property_value_length(config_reply.get());
// on old X servers xkb_config can be 0 even if config_reply indicates a succesfull read
if (!xkb_config || length == 0)
return;
// ### TODO some X servers don't set _XKB_RULES_NAMES at all, in these cases it is filled
// with gibberish, we would need to do some kind of sanity check
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]);
}
void QXcbKeyboard::clearXKBConfig()
{
if (xkb_names.rules)
delete[] xkb_names.rules;
if (xkb_names.model)
delete[] xkb_names.model;
if (xkb_names.layout)
delete[] xkb_names.layout;
if (xkb_names.variant)
delete[] xkb_names.variant;
if (xkb_names.options)
delete[] xkb_names.options;
memset(&xkb_names, 0, sizeof(xkb_names));
}
void QXcbKeyboard::printKeymapError(const char *error) const
{
qWarning() << error;
if (xkb_context) {
qWarning("Current XKB configuration data search paths are: ");
for (unsigned int i = 0; i < xkb_context_num_include_paths(xkb_context); ++i)
qWarning() << xkb_context_include_path_get(xkb_context, i);
}
qWarning("Use QT_XKB_CONFIG_ROOT environmental variable to provide an additional search path, "
"add ':' as separator to provide several search paths and/or make sure that XKB configuration data "
"directory contains recent enough contents, to update please see http://cgit.freedesktop.org/xkeyboard-config/ .");
}
#if QT_CONFIG(xcb_xlib)
/* Look at a pair of unshifted and shifted key symbols.
* If the 'unshifted' symbol is uppercase and there is no shifted symbol,
* return the matching lowercase symbol; otherwise return 0.
@ -787,18 +710,15 @@ static xcb_keysym_t getUnshiftedXKey(xcb_keysym_t unshifted, xcb_keysym_t shifte
if (shifted != XKB_KEY_NoSymbol) // Has a shifted symbol
return 0;
KeySym xlower;
KeySym xupper;
/* libxkbcommon >= 0.8.0 will have public API functions providing
* functionality equivalent to XConvertCase(), use these once the
* minimal libxkbcommon version is high enough. After that the
* xcb-xlib dependency can be removed */
XConvertCase(static_cast<KeySym>(unshifted), &xlower, &xupper);
xcb_keysym_t xlower;
xcb_keysym_t xupper;
xkbcommon_XConvertCase(unshifted, &xlower, &xupper);
if (xlower != xupper // Check if symbol is cased
&& unshifted == static_cast<xcb_keysym_t>(xupper)) { // Unshifted must be upper case
return static_cast<xcb_keysym_t>(xlower);
if (xlower != xupper // Check if symbol is cased
&& unshifted == xupper) { // Unshifted must be upper case
return xlower;
}
return 0;
}
@ -1060,92 +980,55 @@ struct xkb_keymap *QXcbKeyboard::keymapFromCore()
keymap += "};\n"; // xkb_keymap
return xkb_keymap_new_from_buffer(xkb_context,
return xkb_keymap_new_from_buffer(m_xkbContext.get(),
keymap.constData(),
keymap.size(),
XKB_KEYMAP_FORMAT_TEXT_V1,
static_cast<xkb_keymap_compile_flags>(0));
XKB_KEYMAP_COMPILE_NO_FLAGS);
}
#endif
void QXcbKeyboard::updateKeymap()
{
m_config = true;
m_keymap_is_core = false;
// set xkb context object
if (!xkb_context) {
if (qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT")) {
xkb_context = xkb_context_new((xkb_context_flags)XKB_CONTEXT_NO_DEFAULT_INCLUDES);
const QList<QByteArray> xkbRootList = QByteArray(qgetenv("QT_XKB_CONFIG_ROOT")).split(':');
for (const QByteArray &xkbRoot : xkbRootList)
xkb_context_include_path_append(xkb_context, xkbRoot.constData());
} else {
xkb_context = xkb_context_new((xkb_context_flags)0);
}
if (!xkb_context) {
printKeymapError("Qt: Failed to create XKB context!");
if (!m_xkbContext) {
m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES));
if (!m_xkbContext) {
qCWarning(lcQpaKeyboard, "failed to create XKB context");
m_config = false;
return;
}
// log only critical errors, we do our own error logging from printKeymapError()
xkb_context_set_log_level(xkb_context, (xkb_log_level)XKB_LOG_LEVEL_CRITICAL);
xkb_log_level logLevel = lcQpaKeyboard().isDebugEnabled() ?
XKB_LOG_LEVEL_DEBUG : XKB_LOG_LEVEL_CRITICAL;
xkb_context_set_log_level(m_xkbContext.get(), logLevel);
}
// update xkb keymap object
xkb_keymap_unref(xkb_keymap);
xkb_keymap = 0;
struct xkb_state *new_state = 0;
#if QT_CONFIG(xkb)
if (connection()->hasXKB()) {
xkb_keymap = xkb_x11_keymap_new_from_device(xkb_context, xcb_connection(), core_device_id, (xkb_keymap_compile_flags)0);
if (xkb_keymap) {
// Create a new keyboard state object for a keymap
new_state = xkb_x11_state_new_from_device(xkb_keymap, xcb_connection(), core_device_id);
}
m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), xcb_connection(),
core_device_id, XKB_KEYMAP_COMPILE_NO_FLAGS));
if (m_xkbKeymap)
m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), xcb_connection(), core_device_id));
} else {
#endif
m_xkbKeymap.reset(keymapFromCore());
if (m_xkbKeymap)
m_xkbState.reset(xkb_state_new(m_xkbKeymap.get()));
#if QT_CONFIG(xkb)
}
#endif
if (!xkb_keymap) {
// Read xkb RMLVO (rules, models, layouts, variants and options) names
readXKBConfig();
#if QT_CONFIG(xcb_xlib)
bool rmlvo_is_incomplete = !xkb_names.rules || !(*xkb_names.rules)
|| !xkb_names.model || !(*xkb_names.model)
|| !xkb_names.layout || !(*xkb_names.layout);
if (rmlvo_is_incomplete) {
// Try to build xkb map from core mapping information
xkb_keymap = keymapFromCore();
m_keymap_is_core = xkb_keymap != 0;
}
#endif
if (!xkb_keymap) {
// Compile a keymap from RMLVO
xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names,
static_cast<xkb_keymap_compile_flags> (0));
}
if (!xkb_keymap) {
// last fallback is to used hard-coded keymap name, see DEFAULT_XKB_* in xkbcommon.pri
qWarning() << "Qt: Could not determine keyboard configuration data"
" from X server, will use hard-coded keymap configuration.";
clearXKBConfig();
xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0);
}
if (xkb_keymap) {
new_state = xkb_state_new(xkb_keymap);
} else {
printKeymapError("Qt: Failed to compile a keymap!");
m_config = false;
return;
}
}
if (!new_state) {
qWarning("Qt: Failed to create xkb state!");
if (!m_xkbKeymap) {
qCWarning(lcQpaKeyboard, "failed to compile a keymap");
m_config = false;
return;
}
// update xkb state object
xkb_state_unref(xkb_state);
xkb_state = new_state;
if (!m_xkbState) {
qCWarning(lcQpaKeyboard, "failed to create XKB state");
m_config = false;
return;
}
updateXKBMods();
checkForLatinLayout();
@ -1156,7 +1039,7 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
{
if (m_config && connection()->hasXKB()) {
const xkb_state_component newState
= xkb_state_update_mask(xkb_state,
= xkb_state_update_mask(m_xkbState.get(),
state->baseMods,
state->latchedMods,
state->lockedMods,
@ -1201,7 +1084,7 @@ void QXcbKeyboard::updateXKBStateFromState(struct xkb_state *kb_state, quint16 s
void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
{
if (m_config && !connection()->hasXKB()) {
updateXKBStateFromState(xkb_state, state);
updateXKBStateFromState(m_xkbState.get(), state);
}
}
@ -1211,7 +1094,7 @@ void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
if (m_config && !connection()->hasXKB()) {
xXIModifierInfo *mods = static_cast<xXIModifierInfo *>(modInfo);
xXIGroupInfo *group = static_cast<xXIGroupInfo *>(groupInfo);
const xkb_state_component newState = xkb_state_update_mask(xkb_state,
const xkb_state_component newState = xkb_state_update_mask(m_xkbState.get(),
mods->base_mods,
mods->latched_mods,
mods->locked_mods,
@ -1252,14 +1135,14 @@ quint32 QXcbKeyboard::xkbModMask(quint16 state)
void QXcbKeyboard::updateXKBMods()
{
xkb_mods.shift = xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_SHIFT);
xkb_mods.lock = xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_CAPS);
xkb_mods.control = xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_CTRL);
xkb_mods.mod1 = xkb_keymap_mod_get_index(xkb_keymap, "Mod1");
xkb_mods.mod2 = xkb_keymap_mod_get_index(xkb_keymap, "Mod2");
xkb_mods.mod3 = xkb_keymap_mod_get_index(xkb_keymap, "Mod3");
xkb_mods.mod4 = xkb_keymap_mod_get_index(xkb_keymap, "Mod4");
xkb_mods.mod5 = xkb_keymap_mod_get_index(xkb_keymap, "Mod5");
xkb_mods.shift = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_SHIFT);
xkb_mods.lock = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_CAPS);
xkb_mods.control = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_CTRL);
xkb_mods.mod1 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod1");
xkb_mods.mod2 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod2");
xkb_mods.mod3 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod3");
xkb_mods.mod4 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod4");
xkb_mods.mod5 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod5");
}
static bool isLatin(xkb_keysym_t sym)
@ -1269,11 +1152,11 @@ static bool isLatin(xkb_keysym_t sym)
void QXcbKeyboard::checkForLatinLayout() const
{
const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(xkb_keymap);
const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(m_xkbKeymap.get());
const xcb_keycode_t minKeycode = connection()->setup()->min_keycode;
const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode;
ScopedXKBState state(xkb_state_new(xkb_keymap));
ScopedXKBState state(xkb_state_new(m_xkbKeymap.get()));
for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) {
xkb_state_update_mask(state.get(), 0, 0, 0, 0, 0, layout);
for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
@ -1299,16 +1182,16 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const
{
xkb_layout_index_t layout;
xkb_keysym_t sym = XKB_KEY_NoSymbol;
const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(xkb_keymap, keycode);
const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(xkb_state, keycode);
const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(m_xkbKeymap.get(), keycode);
const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(m_xkbState.get(), keycode);
// Look at user layouts in the order in which they are defined in system
// settings to find a latin keysym.
for (layout = 0; layout < layoutCount; ++layout) {
if (layout == currentLayout)
continue;
const xkb_keysym_t *syms;
xkb_level_index_t level = xkb_state_key_get_level(xkb_state, keycode, layout);
if (xkb_keymap_key_get_syms_by_level(xkb_keymap, keycode, layout, level, &syms) != 1)
xkb_level_index_t level = xkb_state_key_get_level(m_xkbState.get(), keycode, layout);
if (xkb_keymap_key_get_syms_by_level(m_xkbKeymap.get(), keycode, layout, level, &syms) != 1)
continue;
if (isLatin(syms[0])) {
sym = syms[0];
@ -1319,8 +1202,8 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const
if (sym == XKB_KEY_NoSymbol)
return sym;
xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LATCHED);
xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LOCKED);
// Check for uniqueness, consider the following setup:
// setxkbmap -layout us,ru,us -variant dvorak,, -option 'grp:ctrl_alt_toggle' (set 'ru' as active).
@ -1332,7 +1215,7 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const
// generate the same shortcut event in this case.
const xcb_keycode_t minKeycode = connection()->setup()->min_keycode;
const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode;
ScopedXKBState state(xkb_state_new(xkb_keymap));
ScopedXKBState state(xkb_state_new(m_xkbKeymap.get()));
for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) {
xkb_state_update_mask(state.get(), 0, latchedMods, lockedMods, 0, 0, prevLayout);
for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
@ -1347,22 +1230,29 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const
return sym;
}
static const char *qtKeyName(int qtKey)
{
int keyEnumIndex = qt_getQtMetaObject()->indexOfEnumerator("Key");
QMetaEnum keyEnum = qt_getQtMetaObject()->enumerator(keyEnumIndex);
return keyEnum.valueToKey(qtKey);
}
QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
{
// turn off the modifier bits which doesn't participate in shortcuts
Qt::KeyboardModifiers notNeeded = Qt::KeypadModifier | Qt::GroupSwitchModifier;
Qt::KeyboardModifiers modifiers = event->modifiers() &= ~notNeeded;
// create a fresh kb state and test against the relevant modifier combinations
struct xkb_state *kb_state = xkb_state_new(xkb_keymap);
struct xkb_state *kb_state = xkb_state_new(m_xkbKeymap.get());
if (!kb_state) {
qWarning("QXcbKeyboard: failed to compile xkb keymap!");
return QList<int>();
}
// get kb state from the master xkb_state and update the temporary kb_state
xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_LOCKED);
xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
xkb_mod_mask_t depressedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED);
xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(m_xkbState.get(), XKB_STATE_LAYOUT_LOCKED);
xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LATCHED);
xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LOCKED);
xkb_mod_mask_t depressedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_DEPRESSED);
xkb_state_update_mask(kb_state, depressedMods, latchedMods, lockedMods, 0, 0, lockedLayout);
quint32 keycode = event->nativeScanCode();
@ -1384,14 +1274,14 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
}
QList<int> result;
int baseQtKey = keysymToQtKey(sym, modifiers, lookupString(kb_state, keycode));
int baseQtKey = keysymToQtKey(sym, modifiers, kb_state, keycode);
if (baseQtKey)
result += (baseQtKey + modifiers);
xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(xkb_keymap, "Shift");
xkb_mod_index_t altMod = xkb_keymap_mod_get_index(xkb_keymap, "Alt");
xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(xkb_keymap, "Control");
xkb_mod_index_t metaMod = xkb_keymap_mod_get_index(xkb_keymap, "Meta");
xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Shift");
xkb_mod_index_t altMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Alt");
xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Control");
xkb_mod_index_t metaMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Meta");
Q_ASSERT(shiftMod < 32);
Q_ASSERT(altMod < 32);
@ -1425,7 +1315,7 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
continue;
Qt::KeyboardModifiers mods = modifiers & ~neededMods;
qtKey = keysymToQtKey(sym, mods, lookupString(kb_state, keycode));
qtKey = keysymToQtKey(sym, mods, kb_state, keycode);
if (!qtKey || qtKey == baseQtKey)
continue;
@ -1446,77 +1336,88 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
}
xkb_state_unref(kb_state);
return result;
}
}
int QXcbKeyboard::keysymToQtKey(xcb_keysym_t key) const
int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modifiers,
struct xkb_state *state, xcb_keycode_t code) const
{
int code = 0;
int i = 0;
while (KeyTbl[i]) {
if (key == KeyTbl[i]) {
code = (int)KeyTbl[i+1];
break;
int qtKey = 0;
// lookup from direct mapping
if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) {
// function keys
qtKey = Qt::Key_F1 + (keysym - XKB_KEY_F1);
} else if (keysym >= XKB_KEY_KP_0 && keysym <= XKB_KEY_KP_9) {
// numeric keypad keys
qtKey = Qt::Key_0 + (keysym - XKB_KEY_KP_0);
} else if (isLatin(keysym)) {
qtKey = xkbcommon_xkb_keysym_to_upper(keysym);
} else {
// check if we have a direct mapping
int i = 0;
while (KeyTbl[i]) {
if (keysym == KeyTbl[i]) {
qtKey = KeyTbl[i + 1];
break;
}
i += 2;
}
}
QString text;
bool fromUnicode = qtKey == 0;
if (fromUnicode) { // lookup from unicode
if (modifiers & Qt::ControlModifier) {
// Control modifier changes the text to ASCII control character, therefore we
// can't use this text to map keysym to a qt key. We can use the same keysym
// (it is not affectd by transformation) to obtain untransformed text. For details
// see "Appendix A. Default Symbol Transformations" in the XKB specification.
text = lookupStringNoKeysymTransformations(keysym);
} else {
text = lookupString(state, code);
}
if (!text.isEmpty()) {
if (text.unicode()->isDigit()) {
// Ensures that also non-latin digits are mapped to corresponding qt keys,
// e.g CTRL + ۲ (arabic two), is mapped to CTRL + Qt::Key_2.
qtKey = Qt::Key_0 + text.unicode()->digitValue();
} else {
qtKey = text.unicode()->toUpper().unicode();
}
}
i += 2;
}
if (rmod_masks.meta) {
// translate Super/Hyper keys to Meta if we're using them as the MetaModifier
if (rmod_masks.meta == rmod_masks.super && (code == Qt::Key_Super_L || code == Qt::Key_Super_R)) {
code = Qt::Key_Meta;
} else if (rmod_masks.meta == rmod_masks.hyper && (code == Qt::Key_Hyper_L || code == Qt::Key_Hyper_R)) {
code = Qt::Key_Meta;
if (rmod_masks.meta == rmod_masks.super && (qtKey == Qt::Key_Super_L
|| qtKey == Qt::Key_Super_R)) {
qtKey = Qt::Key_Meta;
} else if (rmod_masks.meta == rmod_masks.hyper && (qtKey == Qt::Key_Hyper_L
|| qtKey == Qt::Key_Hyper_R)) {
qtKey = Qt::Key_Meta;
}
}
return code;
}
int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text) const
{
int code = 0;
#ifndef QT_NO_TEXTCODEC
QTextCodec *systemCodec = QTextCodec::codecForLocale();
#endif
// 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 (extended ACSII codes), but should
// rather use the QKeyEvent::text().
if (keysym < 128 || (keysym < 256
#ifndef QT_NO_TEXTCODEC
&& systemCodec->mibEnum() == 4
#endif
)) {
// upper-case key, if known
code = isprint((int)keysym) ? toupper((int)keysym) : 0;
} else if (keysym >= XK_F1 && keysym <= XK_F35) {
// function keys
code = Qt::Key_F1 + ((int)keysym - XK_F1);
} else if (keysym >= XK_KP_Space && keysym <= XK_KP_9) {
if (keysym >= XK_KP_0) {
// numeric keypad keys
code = Qt::Key_0 + ((int)keysym - XK_KP_0);
if (Q_UNLIKELY(lcQpaKeyboard().isDebugEnabled())) {
char keysymName[64];
xkb_keysym_get_name(keysym, keysymName, sizeof(keysymName));
QString keysymInHex = QString(QStringLiteral("0x%1")).arg(keysym, 0, 16);
if (qtKeyName(qtKey)) {
qCDebug(lcQpaKeyboard).nospace() << "keysym: " << keysymName << "("
<< keysymInHex << ") mapped to Qt::" << qtKeyName(qtKey) << " | text: " << text
<< " | qt key: " << qtKey << " mapped from unicode number: " << fromUnicode;
} else {
code = keysymToQtKey(keysym);
qCDebug(lcQpaKeyboard).nospace() << "no Qt::Key for keysym: " << keysymName
<< "(" << keysymInHex << ") | text: " << text << " | qt key: " << qtKey;
}
modifiers |= Qt::KeypadModifier;
} else if (text.length() == 1 && text.unicode()->unicode() > 0x1f
&& text.unicode()->unicode() != 0x7f
&& !(keysym >= XK_dead_grave && keysym <= XK_dead_longsolidusoverlay)) {
code = text.unicode()->toUpper().unicode();
} else {
// any other keys
code = keysymToQtKey(keysym);
}
return code;
return qtKey;
}
QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
: QXcbObject(connection)
{
memset(&xkb_names, 0, sizeof(xkb_names));
#if QT_CONFIG(xkb)
core_device_id = 0;
if (connection->hasXKB()) {
@ -1539,12 +1440,8 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
QXcbKeyboard::~QXcbKeyboard()
{
xkb_state_unref(xkb_state);
xkb_keymap_unref(xkb_keymap);
xkb_context_unref(xkb_context);
if (!connection()->hasXKB())
xcb_key_symbols_free(m_key_symbols);
clearXKBConfig();
}
void QXcbKeyboard::updateVModMapping()
@ -1890,24 +1787,36 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
// this way we allow for synthetic events to have different state
// from the current state i.e. you can have Alt+Ctrl pressed
// and receive a synthetic key event that has neither Alt nor Ctrl pressed
struct xkb_state *kb_state = xkb_state_new(xkb_keymap);
if (!kb_state)
ScopedXKBState xkbState(xkb_state_new(m_xkbKeymap.get()));
if (!xkbState)
return;
updateXKBStateFromState(kb_state, state);
updateXKBStateFromState(xkbState.get(), state);
xcb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, code);
QString string = lookupString(kb_state, code);
xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState.get(), code);
QString string = lookupString(xkbState.get(), code);
// Ιf control modifier is set we should prefer latin character, this is
// used for standard shortcuts in checks like "key == QKeySequence::Copy",
// users can still see the actual X11 keysym with QKeyEvent::nativeVirtualKey
Qt::KeyboardModifiers modifiers = translateModifiers(state);
xcb_keysym_t translatedSym = XKB_KEY_NoSymbol;
if (modifiers & Qt::ControlModifier && !isLatin(sym))
translatedSym = lookupLatinKeysym(code);
if (translatedSym == XKB_KEY_NoSymbol)
translatedSym = sym;
int qtcode = keysymToQtKey(translatedSym, modifiers, string);
if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9)
modifiers |= Qt::KeypadModifier;
// Note 1: All standard key sequences on linux (as defined in platform theme)
// that use a latin character also contain a control modifier, which is why
// checking for Qt::ControlModifier is sufficient here. It is possible to
// override QPlatformTheme::keyBindings() and provide custom sequences for
// QKeySequence::StandardKey. Custom sequences probably should respect this
// convention (alternatively, we could test against other modifiers here).
// Note 2: The possibleKeys() shorcut mechanism is not affected by this value
// adjustment and does its own thing.
xcb_keysym_t latinKeysym = XKB_KEY_NoSymbol;
if (modifiers & Qt::ControlModifier) {
// With standard shortcuts we should prefer a latin character, this is
// in checks like "event == QKeySequence::Copy".
if (!isLatin(sym))
latinKeysym = lookupLatinKeysym(code);
}
int qtcode = keysymToQtKey(latinKeysym != XKB_KEY_NoSymbol ? latinKeysym : sym,
modifiers, xkbState.get(), code);
bool isAutoRepeat = false;
if (type == QEvent::KeyPress) {
@ -1959,7 +1868,6 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers,
code, sym, state, string, isAutoRepeat);
}
xkb_state_unref(kb_state);
}
QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const
@ -1973,6 +1881,17 @@ QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code)
return QString::fromUtf8(chars.constData(), size);
}
QString QXcbKeyboard::lookupStringNoKeysymTransformations(xkb_keysym_t keysym) const
{
QVarLengthArray<char, 32> chars(32);
const int size = xkb_keysym_to_utf8(keysym, chars.data(), chars.size());
if (Q_UNLIKELY(size > chars.size())) {
chars.resize(size);
xkb_keysym_to_utf8(keysym, chars.data(), chars.size());
}
return QString::fromUtf8(chars.constData(), size);
}
void QXcbKeyboard::handleKeyPressEvent(const xcb_key_press_event_t *event)
{
handleKeyEvent(event->event, QEvent::KeyPress, event->detail, event->state, event->time);

View File

@ -88,15 +88,12 @@ protected:
void resolveMaskConflicts();
QString lookupString(struct xkb_state *state, xcb_keycode_t code) const;
int keysymToQtKey(xcb_keysym_t keysym) const;
int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text) const;
void printKeymapError(const char *error) const;
QString lookupStringNoKeysymTransformations(xkb_keysym_t keysym) const;
int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modifiers,
struct xkb_state *state, xcb_keycode_t code) const;
void readXKBConfig();
void clearXKBConfig();
#if QT_CONFIG(xcb_xlib)
struct xkb_keymap *keymapFromCore();
#endif
// when XKEYBOARD not present on the X server
void updateModifiers();
typedef QMap<xcb_keysym_t, int> KeysymModifierMap;
@ -112,14 +109,8 @@ private:
void updateXKBStateFromState(struct xkb_state *kb_state, quint16 state);
bool m_config = false;
bool m_keymap_is_core = false;
xcb_keycode_t m_autorepeat_code = 0;
struct xkb_context *xkb_context = nullptr;
struct xkb_keymap *xkb_keymap = nullptr;
struct xkb_state *xkb_state = nullptr;
struct xkb_rule_names xkb_names;
struct _mod_masks {
uint alt;
uint altgr;
@ -152,7 +143,19 @@ private:
struct XKBStateDeleter {
void operator()(struct xkb_state *state) const { return xkb_state_unref(state); }
};
struct XKBKeymapDeleter {
void operator()(struct xkb_keymap *keymap) const { return xkb_keymap_unref(keymap); }
};
struct XKBContextDeleter {
void operator()(struct xkb_context *context) const { return xkb_context_unref(context); }
};
using ScopedXKBState = std::unique_ptr<struct xkb_state, XKBStateDeleter>;
using ScopedXKBKeymap = std::unique_ptr<struct xkb_keymap, XKBKeymapDeleter>;
using ScopedXKBContext = std::unique_ptr<struct xkb_context, XKBContextDeleter>;
ScopedXKBState m_xkbState;
ScopedXKBKeymap m_xkbKeymap;
ScopedXKBContext m_xkbContext;
};
QT_END_NAMESPACE

View File

@ -0,0 +1,233 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
/* XConvertCase was copied from src/3rdparty/xkbcommon/src/keysym.c,
which contains the following license information:
Copyright 1985, 1987, 1990, 1998 The Open Group
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the authors or their
institutions shall not be used in advertising or otherwise to promote the
sale, use or other dealings in this Software without prior written
authorization from the authors.
Copyright © 2009 Dan Nicholson
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/*
The following code modifications were applied:
XConvertCase() was renamed to xkbcommon_XConvertCase(), to not confuse it
with Xlib's XConvertCase().
UCSConvertCase() was renamed to qt_UCSConvertCase() and function's body was
replaced to use Qt APIs for doing case conversion, which should give us better
results instead of using the less complete version from keysym.c
*/
#include <xkbcommon/xkbcommon.h>
#include <QtCore/QChar>
QT_BEGIN_NAMESPACE
static void qt_UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper)
{
*lower = QChar::toLower(code);
*upper = QChar::toUpper(code);
}
void xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper)
{
/* Latin 1 keysym */
if (sym < 0x100) {
qt_UCSConvertCase(sym, lower, upper);
return;
}
/* Unicode keysym */
if ((sym & 0xff000000) == 0x01000000) {
qt_UCSConvertCase((sym & 0x00ffffff), lower, upper);
*upper |= 0x01000000;
*lower |= 0x01000000;
return;
}
/* Legacy keysym */
*lower = sym;
*upper = sym;
switch (sym >> 8) {
case 1: /* Latin 2 */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym == XKB_KEY_Aogonek)
*lower = XKB_KEY_aogonek;
else if (sym >= XKB_KEY_Lstroke && sym <= XKB_KEY_Sacute)
*lower += (XKB_KEY_lstroke - XKB_KEY_Lstroke);
else if (sym >= XKB_KEY_Scaron && sym <= XKB_KEY_Zacute)
*lower += (XKB_KEY_scaron - XKB_KEY_Scaron);
else if (sym >= XKB_KEY_Zcaron && sym <= XKB_KEY_Zabovedot)
*lower += (XKB_KEY_zcaron - XKB_KEY_Zcaron);
else if (sym == XKB_KEY_aogonek)
*upper = XKB_KEY_Aogonek;
else if (sym >= XKB_KEY_lstroke && sym <= XKB_KEY_sacute)
*upper -= (XKB_KEY_lstroke - XKB_KEY_Lstroke);
else if (sym >= XKB_KEY_scaron && sym <= XKB_KEY_zacute)
*upper -= (XKB_KEY_scaron - XKB_KEY_Scaron);
else if (sym >= XKB_KEY_zcaron && sym <= XKB_KEY_zabovedot)
*upper -= (XKB_KEY_zcaron - XKB_KEY_Zcaron);
else if (sym >= XKB_KEY_Racute && sym <= XKB_KEY_Tcedilla)
*lower += (XKB_KEY_racute - XKB_KEY_Racute);
else if (sym >= XKB_KEY_racute && sym <= XKB_KEY_tcedilla)
*upper -= (XKB_KEY_racute - XKB_KEY_Racute);
break;
case 2: /* Latin 3 */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XKB_KEY_Hstroke && sym <= XKB_KEY_Hcircumflex)
*lower += (XKB_KEY_hstroke - XKB_KEY_Hstroke);
else if (sym >= XKB_KEY_Gbreve && sym <= XKB_KEY_Jcircumflex)
*lower += (XKB_KEY_gbreve - XKB_KEY_Gbreve);
else if (sym >= XKB_KEY_hstroke && sym <= XKB_KEY_hcircumflex)
*upper -= (XKB_KEY_hstroke - XKB_KEY_Hstroke);
else if (sym >= XKB_KEY_gbreve && sym <= XKB_KEY_jcircumflex)
*upper -= (XKB_KEY_gbreve - XKB_KEY_Gbreve);
else if (sym >= XKB_KEY_Cabovedot && sym <= XKB_KEY_Scircumflex)
*lower += (XKB_KEY_cabovedot - XKB_KEY_Cabovedot);
else if (sym >= XKB_KEY_cabovedot && sym <= XKB_KEY_scircumflex)
*upper -= (XKB_KEY_cabovedot - XKB_KEY_Cabovedot);
break;
case 3: /* Latin 4 */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XKB_KEY_Rcedilla && sym <= XKB_KEY_Tslash)
*lower += (XKB_KEY_rcedilla - XKB_KEY_Rcedilla);
else if (sym >= XKB_KEY_rcedilla && sym <= XKB_KEY_tslash)
*upper -= (XKB_KEY_rcedilla - XKB_KEY_Rcedilla);
else if (sym == XKB_KEY_ENG)
*lower = XKB_KEY_eng;
else if (sym == XKB_KEY_eng)
*upper = XKB_KEY_ENG;
else if (sym >= XKB_KEY_Amacron && sym <= XKB_KEY_Umacron)
*lower += (XKB_KEY_amacron - XKB_KEY_Amacron);
else if (sym >= XKB_KEY_amacron && sym <= XKB_KEY_umacron)
*upper -= (XKB_KEY_amacron - XKB_KEY_Amacron);
break;
case 6: /* Cyrillic */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Serbian_DZE)
*lower -= (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Serbian_dze)
*upper += (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
else if (sym >= XKB_KEY_Cyrillic_YU && sym <= XKB_KEY_Cyrillic_HARDSIGN)
*lower -= (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu);
else if (sym >= XKB_KEY_Cyrillic_yu && sym <= XKB_KEY_Cyrillic_hardsign)
*upper += (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu);
break;
case 7: /* Greek */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XKB_KEY_Greek_ALPHAaccent && sym <= XKB_KEY_Greek_OMEGAaccent)
*lower += (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent);
else if (sym >= XKB_KEY_Greek_alphaaccent && sym <= XKB_KEY_Greek_omegaaccent &&
sym != XKB_KEY_Greek_iotaaccentdieresis &&
sym != XKB_KEY_Greek_upsilonaccentdieresis)
*upper -= (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent);
else if (sym >= XKB_KEY_Greek_ALPHA && sym <= XKB_KEY_Greek_OMEGA)
*lower += (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA);
else if (sym >= XKB_KEY_Greek_alpha && sym <= XKB_KEY_Greek_omega &&
sym != XKB_KEY_Greek_finalsmallsigma)
*upper -= (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA);
break;
case 0x13: /* Latin 9 */
if (sym == XKB_KEY_OE)
*lower = XKB_KEY_oe;
else if (sym == XKB_KEY_oe)
*upper = XKB_KEY_OE;
else if (sym == XKB_KEY_Ydiaeresis)
*lower = XKB_KEY_ydiaeresis;
break;
}
}
xkb_keysym_t xkbcommon_xkb_keysym_to_upper(xkb_keysym_t ks)
{
xkb_keysym_t lower, upper;
xkbcommon_XConvertCase(ks, &lower, &upper);
return upper;
}
QT_END_NAMESPACE

View File

@ -46,7 +46,8 @@ HEADERS = \
qxcbcursor.h \
qxcbimage.h \
qxcbxsettings.h \
qxcbsystemtraytracker.h
qxcbsystemtraytracker.h \
qxcbxkbcommon.h
load(qt_build_paths)

View File

@ -110,7 +110,7 @@ Q_STATIC_ASSERT(!!1);
static thread_local int gt_var;
void thread_local_test()
{
thread_local int t_var;
static thread_local int t_var;
t_var = gt_var;
}
#endif