summaryrefslogtreecommitdiffstats
path: root/src/gui/platform/unix/qxkbcommon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/platform/unix/qxkbcommon.cpp')
-rw-r--r--src/gui/platform/unix/qxkbcommon.cpp167
1 files changed, 85 insertions, 82 deletions
diff --git a/src/gui/platform/unix/qxkbcommon.cpp b/src/gui/platform/unix/qxkbcommon.cpp
index 71f1cfd24a..ed29db3005 100644
--- a/src/gui/platform/unix/qxkbcommon.cpp
+++ b/src/gui/platform/unix/qxkbcommon.cpp
@@ -1,47 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxkbcommon_p.h"
#include <private/qmakearray_p.h>
+#include <QtCore/private/qstringiterator_p.h>
+#include <QtCore/qvarlengtharray.h>
#include <QtCore/QMetaMethod>
+
#include <QtGui/QKeyEvent>
#include <QtGui/private/qguiapplication_p.h>
@@ -50,8 +17,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcXkbcommon, "qt.xkbcommon")
-
static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers,
xkb_state *state, xkb_keycode_t code,
bool superAsMeta, bool hyperAsMeta);
@@ -93,6 +58,7 @@ static constexpr const auto KeyTbl = qMakeArray(
Xkb2Qt<XKB_KEY_Clear, Qt::Key_Delete>,
Xkb2Qt<XKB_KEY_Pause, Qt::Key_Pause>,
Xkb2Qt<XKB_KEY_Print, Qt::Key_Print>,
+ Xkb2Qt<XKB_KEY_Sys_Req, Qt::Key_SysReq>,
Xkb2Qt<0x1005FF60, Qt::Key_SysReq>, // hardcoded Sun SysReq
Xkb2Qt<0x1007ff00, Qt::Key_SysReq>, // hardcoded X386 SysReq
@@ -271,10 +237,14 @@ static constexpr const auto KeyTbl = qMakeArray(
Xkb2Qt<XKB_KEY_dead_small_schwa, Qt::Key_Dead_Small_Schwa>,
Xkb2Qt<XKB_KEY_dead_capital_schwa, Qt::Key_Dead_Capital_Schwa>,
Xkb2Qt<XKB_KEY_dead_greek, Qt::Key_Dead_Greek>,
+/* The following four XKB_KEY_dead keys got removed in libxkbcommon 1.6.0
+ The define check is kind of version check here. */
+#ifdef XKB_KEY_dead_lowline
Xkb2Qt<XKB_KEY_dead_lowline, Qt::Key_Dead_Lowline>,
Xkb2Qt<XKB_KEY_dead_aboveverticalline, Qt::Key_Dead_Aboveverticalline>,
Xkb2Qt<XKB_KEY_dead_belowverticalline, Qt::Key_Dead_Belowverticalline>,
Xkb2Qt<XKB_KEY_dead_longsolidusoverlay, Qt::Key_Dead_Longsolidusoverlay>,
+#endif
// Special keys from X.org - This include multimedia keys,
// wireless/bluetooth/uwb keys, special launcher keys, etc.
@@ -297,8 +267,7 @@ static constexpr const auto KeyTbl = qMakeArray(
Xkb2Qt<XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord>,
Xkb2Qt<XKB_KEY_XF86AudioPause, Qt::Key_MediaPause>,
Xkb2Qt<XKB_KEY_XF86Mail, Qt::Key_LaunchMail>,
- Xkb2Qt<XKB_KEY_XF86MyComputer, Qt::Key_Launch0>, // ### Qt 6: remap properly
- Xkb2Qt<XKB_KEY_XF86Calculator, Qt::Key_Launch1>,
+ Xkb2Qt<XKB_KEY_XF86MyComputer, Qt::Key_LaunchMedia>,
Xkb2Qt<XKB_KEY_XF86Memo, Qt::Key_Memo>,
Xkb2Qt<XKB_KEY_XF86ToDoList, Qt::Key_ToDoList>,
Xkb2Qt<XKB_KEY_XF86Calendar, Qt::Key_Calendar>,
@@ -331,6 +300,7 @@ static constexpr const auto KeyTbl = qMakeArray(
Xkb2Qt<XKB_KEY_XF86Book, Qt::Key_Book>,
Xkb2Qt<XKB_KEY_XF86CD, Qt::Key_CD>,
Xkb2Qt<XKB_KEY_XF86Calculater, Qt::Key_Calculator>,
+ Xkb2Qt<XKB_KEY_XF86Calculator, Qt::Key_Calculator>,
Xkb2Qt<XKB_KEY_XF86Clear, Qt::Key_Clear>,
Xkb2Qt<XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab>,
Xkb2Qt<XKB_KEY_XF86Close, Qt::Key_Close>,
@@ -406,22 +376,22 @@ static constexpr const auto KeyTbl = qMakeArray(
Xkb2Qt<XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn>,
Xkb2Qt<XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff>,
Xkb2Qt<XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute>,
- Xkb2Qt<XKB_KEY_XF86Launch0, Qt::Key_Launch2>, // ### Qt 6: remap properly
- Xkb2Qt<XKB_KEY_XF86Launch1, Qt::Key_Launch3>,
- Xkb2Qt<XKB_KEY_XF86Launch2, Qt::Key_Launch4>,
- Xkb2Qt<XKB_KEY_XF86Launch3, Qt::Key_Launch5>,
- Xkb2Qt<XKB_KEY_XF86Launch4, Qt::Key_Launch6>,
- Xkb2Qt<XKB_KEY_XF86Launch5, Qt::Key_Launch7>,
- Xkb2Qt<XKB_KEY_XF86Launch6, Qt::Key_Launch8>,
- Xkb2Qt<XKB_KEY_XF86Launch7, Qt::Key_Launch9>,
- Xkb2Qt<XKB_KEY_XF86Launch8, Qt::Key_LaunchA>,
- Xkb2Qt<XKB_KEY_XF86Launch9, Qt::Key_LaunchB>,
- Xkb2Qt<XKB_KEY_XF86LaunchA, Qt::Key_LaunchC>,
- Xkb2Qt<XKB_KEY_XF86LaunchB, Qt::Key_LaunchD>,
- Xkb2Qt<XKB_KEY_XF86LaunchC, Qt::Key_LaunchE>,
- Xkb2Qt<XKB_KEY_XF86LaunchD, Qt::Key_LaunchF>,
- Xkb2Qt<XKB_KEY_XF86LaunchE, Qt::Key_LaunchG>,
- Xkb2Qt<XKB_KEY_XF86LaunchF, Qt::Key_LaunchH>
+ Xkb2Qt<XKB_KEY_XF86Launch0, Qt::Key_Launch0>,
+ Xkb2Qt<XKB_KEY_XF86Launch1, Qt::Key_Launch1>,
+ Xkb2Qt<XKB_KEY_XF86Launch2, Qt::Key_Launch2>,
+ Xkb2Qt<XKB_KEY_XF86Launch3, Qt::Key_Launch3>,
+ Xkb2Qt<XKB_KEY_XF86Launch4, Qt::Key_Launch4>,
+ Xkb2Qt<XKB_KEY_XF86Launch5, Qt::Key_Launch5>,
+ Xkb2Qt<XKB_KEY_XF86Launch6, Qt::Key_Launch6>,
+ Xkb2Qt<XKB_KEY_XF86Launch7, Qt::Key_Launch7>,
+ Xkb2Qt<XKB_KEY_XF86Launch8, Qt::Key_Launch8>,
+ Xkb2Qt<XKB_KEY_XF86Launch9, Qt::Key_Launch9>,
+ Xkb2Qt<XKB_KEY_XF86LaunchA, Qt::Key_LaunchA>,
+ Xkb2Qt<XKB_KEY_XF86LaunchB, Qt::Key_LaunchB>,
+ Xkb2Qt<XKB_KEY_XF86LaunchC, Qt::Key_LaunchC>,
+ Xkb2Qt<XKB_KEY_XF86LaunchD, Qt::Key_LaunchD>,
+ Xkb2Qt<XKB_KEY_XF86LaunchE, Qt::Key_LaunchE>,
+ Xkb2Qt<XKB_KEY_XF86LaunchF, Qt::Key_LaunchF>
>::Data{}
);
@@ -469,7 +439,7 @@ QList<xkb_keysym_t> QXkbCommon::toKeysym(QKeyEvent *event)
} else if (event->modifiers() & Qt::KeypadModifier) {
if (qtKey >= Qt::Key_0 && qtKey <= Qt::Key_9)
keysyms.append(XKB_KEY_KP_0 + (qtKey - Qt::Key_0));
- } else if (isLatin(qtKey) && event->text().isUpper()) {
+ } else if (isLatin1(qtKey) && event->text().isUpper()) {
keysyms.append(qtKey);
}
@@ -494,7 +464,7 @@ QList<xkb_keysym_t> QXkbCommon::toKeysym(QKeyEvent *event)
// From libxkbcommon keysym-utf.c:
// "We allow to represent any UCS character in the range U-00000000 to
// U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff."
- for (uint utf32 : qAsConst(ucs4))
+ for (uint utf32 : std::as_const(ucs4))
keysyms.append(utf32 | 0x01000000);
return keysyms;
@@ -521,7 +491,7 @@ int QXkbCommon::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifie
// With standard shortcuts we should prefer a latin character, this is
// for checks like "some qkeyevent == QKeySequence::Copy" to work even
// when using for example 'russian' keyboard layout.
- if (!QXkbCommon::isLatin(keysym)) {
+ if (!QXkbCommon::isLatin1(keysym)) {
xkb_keysym_t latinKeysym = QXkbCommon::lookupLatinKeysym(state, code);
if (latinKeysym != XKB_KEY_NoSymbol)
keysym = latinKeysym;
@@ -544,14 +514,28 @@ static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers mod
} 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 (QXkbCommon::isLatin(keysym)) {
+ } else if (QXkbCommon::isLatin1(keysym)) {
+ // Most Qt::Key values are determined by their upper-case version,
+ // where this is in the Latin-1 repertoire. So start with that:
qtKey = QXkbCommon::qxkbcommon_xkb_keysym_to_upper(keysym);
+ // However, Key_mu and Key_ydiaeresis are U+00B5 MICRO SIGN and
+ // U+00FF LATIN SMALL LETTER Y WITH DIAERESIS, both lower-case,
+ // with upper-case forms outside Latin-1, so use them as they are
+ // since they're the Qt::Key values.
+ if (!QXkbCommon::isLatin1(qtKey))
+ qtKey = keysym;
} else {
// check if we have a direct mapping
xkb2qt_t searchKey{keysym, 0};
auto it = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey);
if (it != KeyTbl.end() && !(searchKey < *it))
qtKey = it->qt;
+
+ // translate Super/Hyper keys to Meta if we're using them as the MetaModifier
+ if (superAsMeta && (qtKey == Qt::Key_Super_L || qtKey == Qt::Key_Super_R))
+ qtKey = Qt::Key_Meta;
+ if (hyperAsMeta && (qtKey == Qt::Key_Hyper_L || qtKey == Qt::Key_Hyper_R))
+ qtKey = Qt::Key_Meta;
}
if (qtKey)
@@ -574,20 +558,16 @@ static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers mod
// 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();
+ text = text.toUpper();
+ QStringIterator i(text);
+ qtKey = i.next(0);
}
}
- // translate Super/Hyper keys to Meta if we're using them as the MetaModifier
- if (superAsMeta && (qtKey == Qt::Key_Super_L || qtKey == Qt::Key_Super_R))
- qtKey = Qt::Key_Meta;
- if (hyperAsMeta && (qtKey == Qt::Key_Hyper_L || qtKey == Qt::Key_Hyper_R))
- qtKey = Qt::Key_Meta;
-
return qtKey;
}
-Qt::KeyboardModifiers QXkbCommon::modifiers(struct xkb_state *state)
+Qt::KeyboardModifiers QXkbCommon::modifiers(struct xkb_state *state, xkb_keysym_t keysym)
{
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
@@ -600,6 +580,9 @@ Qt::KeyboardModifiers QXkbCommon::modifiers(struct xkb_state *state)
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_EFFECTIVE) > 0)
modifiers |= Qt::MetaModifier;
+ if (isKeypad(keysym))
+ modifiers |= Qt::KeypadModifier;
+
return modifiers;
}
@@ -616,11 +599,28 @@ static const Qt::KeyboardModifiers ModsTbl[] = {
Qt::NoModifier // Fall-back to raw Key_*, for non-latin1 kb layouts
};
+/*
+ Compatibility until all sub modules have transitioned to new API below
+*/
QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
bool superAsMeta, bool hyperAsMeta)
{
QList<int> result;
+ auto keyCombinations = possibleKeyCombinations(state, event, superAsMeta, hyperAsMeta);
+ for (auto keyCombination : keyCombinations)
+ result << keyCombination.toCombined();
+
+ return result;
+}
+
+QList<QKeyCombination> QXkbCommon::possibleKeyCombinations(xkb_state *state, const QKeyEvent *event,
+ bool superAsMeta, bool hyperAsMeta)
+{
+ QList<QKeyCombination> result;
quint32 keycode = event->nativeScanCode();
+ if (!keycode)
+ return result;
+
Qt::KeyboardModifiers modifiers = event->modifiers();
xkb_keymap *keymap = xkb_state_get_keymap(state);
// turn off the modifier bits which doesn't participate in shortcuts
@@ -630,7 +630,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
ScopedXKBState scopedXkbQueryState(xkb_state_new(keymap));
xkb_state *queryState = scopedXkbQueryState.get();
if (!queryState) {
- qCWarning(lcXkbcommon) << Q_FUNC_INFO << "failed to compile xkb keymap";
+ qCWarning(lcQpaKeyMapper) << Q_FUNC_INFO << "failed to compile xkb keymap";
return result;
}
// get kb state from the master state and update the temporary state
@@ -656,7 +656,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
int baseQtKey = keysymToQtKey_internal(sym, modifiers, queryState, keycode, superAsMeta, hyperAsMeta);
if (baseQtKey)
- result += (baseQtKey + int(modifiers));
+ result += QKeyCombination::fromCombined(baseQtKey + int(modifiers));
xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(keymap, "Shift");
xkb_mod_index_t altMod = xkb_keymap_mod_get_index(keymap, "Alt");
@@ -674,7 +674,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
Qt::KeyboardModifiers neededMods = ModsTbl[i];
if ((modifiers & neededMods) == neededMods) {
if (i == 8) {
- if (isLatin(baseQtKey))
+ if (isLatin1(baseQtKey))
continue;
// add a latin key as a fall back key
sym = lookupLatinKeysym(state, keycode);
@@ -702,8 +702,9 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
// catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +,
// but Ctrl++ is more specific than +, so we should skip the last one
bool ambiguous = false;
- for (int shortcut : qAsConst(result)) {
- if (int(shortcut & ~Qt::KeyboardModifierMask) == qtKey && (shortcut & mods) == mods) {
+ for (auto keyCombination : std::as_const(result)) {
+ if (keyCombination.key() == qtKey
+ && (keyCombination.keyboardModifiers() & mods) == mods) {
ambiguous = true;
break;
}
@@ -711,7 +712,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
if (ambiguous)
continue;
- result += (qtKey + int(mods));
+ result += QKeyCombination::fromCombined(qtKey + int(mods));
}
}
@@ -729,7 +730,7 @@ void QXkbCommon::verifyHasLatinLayout(xkb_keymap *keymap)
for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) {
for (xkb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
xkb_keymap_key_get_syms_by_level(keymap, code, layout, 0, &keysyms);
- if (keysyms && isLatin(keysyms[0]))
+ if (keysyms && isLatin1(keysyms[0]))
nrLatinKeys++;
if (nrLatinKeys > 10) // arbitrarily chosen threshold
return;
@@ -738,18 +739,20 @@ void QXkbCommon::verifyHasLatinLayout(xkb_keymap *keymap)
// This means that lookupLatinKeysym() will not find anything and latin
// key shortcuts might not work. This is a bug in the affected desktop
// environment. Usually can be solved via system settings by adding e.g. 'us'
- // layout to the list of seleced layouts, or by using command line, "setxkbmap
+ // layout to the list of selected layouts, or by using command line, "setxkbmap
// -layout rus,en". The position of latin key based layout in the list of the
// selected layouts is irrelevant. Properly functioning desktop environments
// handle this behind the scenes, even if no latin key based layout has been
// explicitly listed in the selected layouts.
- qCDebug(lcXkbcommon, "no keyboard layouts with latin keys present");
+ qCDebug(lcQpaKeyMapper, "no keyboard layouts with latin keys present");
}
xkb_keysym_t QXkbCommon::lookupLatinKeysym(xkb_state *state, xkb_keycode_t keycode)
{
xkb_layout_index_t layout;
xkb_keysym_t sym = XKB_KEY_NoSymbol;
+ if (!state)
+ return sym;
xkb_keymap *keymap = xkb_state_get_keymap(state);
const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(keymap, keycode);
const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(state, keycode);
@@ -762,7 +765,7 @@ xkb_keysym_t QXkbCommon::lookupLatinKeysym(xkb_state *state, xkb_keycode_t keyco
xkb_level_index_t level = xkb_state_key_get_level(state, keycode, layout);
if (xkb_keymap_key_get_syms_by_level(keymap, keycode, layout, level, &syms) != 1)
continue;
- if (isLatin(syms[0])) {
+ if (isLatin1(syms[0])) {
sym = syms[0];
break;
}
@@ -807,7 +810,7 @@ void QXkbCommon::setXkbContext(QPlatformInputContext *inputContext, struct xkb_c
const char *const inputContextClassName = "QComposeInputContext";
const char *const normalizedSignature = "setXkbContext(xkb_context*)";
- if (inputContext->objectName() != QLatin1String(inputContextClassName))
+ if (inputContext->objectName() != QLatin1StringView(inputContextClassName))
return;
static const QMetaMethod setXkbContext = [&]() {
@@ -815,7 +818,7 @@ void QXkbCommon::setXkbContext(QPlatformInputContext *inputContext, struct xkb_c
QMetaMethod method = inputContext->metaObject()->method(methodIndex);
Q_ASSERT(method.isValid());
if (!method.isValid())
- qCWarning(lcXkbcommon) << normalizedSignature << "not found on" << inputContextClassName;
+ qCWarning(lcQpaKeyMapper) << normalizedSignature << "not found on" << inputContextClassName;
return method;
}();