Merge remote-tracking branch 'origin/5.13' into dev
Change-Id: Ic0037eac1d85a0e60e7b1a590d49b5ee6205bfc8
This commit is contained in:
commit
84e15d6f48
@ -200,7 +200,9 @@ CMAKE_QT5_MODULE_DEPS = $$join(lib_deps, ";")
|
|||||||
CMAKE_INTERFACE_MODULE_DEPS = $$join(aux_mod_deps, ";")
|
CMAKE_INTERFACE_MODULE_DEPS = $$join(aux_mod_deps, ";")
|
||||||
CMAKE_INTERFACE_QT5_MODULE_DEPS = $$join(aux_lib_deps, ";")
|
CMAKE_INTERFACE_QT5_MODULE_DEPS = $$join(aux_lib_deps, ";")
|
||||||
|
|
||||||
CMAKE_QT_STEM = Qt$$QT_MAJOR_VERSION$${CMAKE_MODULE_NAME}$${QT_LIBINFIX}
|
# TARGET here is the one changed at the end of qt_module.prf,
|
||||||
|
# which already contains the Qt5 prefix and QT_LIBINFIX suffix
|
||||||
|
CMAKE_QT_STEM = $${TARGET}
|
||||||
|
|
||||||
mac {
|
mac {
|
||||||
!isEmpty(CMAKE_STATIC_TYPE) {
|
!isEmpty(CMAKE_STATIC_TYPE) {
|
||||||
|
@ -338,7 +338,7 @@ defineTest(qtConfParseCommandLine) {
|
|||||||
qtConfAddWarning("Command line option -skip is only effective in top-level builds.")
|
qtConfAddWarning("Command line option -skip is only effective in top-level builds.")
|
||||||
skipOptionWarningAdded = 1
|
skipOptionWarningAdded = 1
|
||||||
}
|
}
|
||||||
$$qtConfGetNextCommandlineArg()
|
val = $$qtConfGetNextCommandlineArg()
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,7 +532,7 @@ MakefileGenerator::init()
|
|||||||
QStack<int> state;
|
QStack<int> state;
|
||||||
enum { IN_CONDITION, MET_CONDITION, PENDING_CONDITION };
|
enum { IN_CONDITION, MET_CONDITION, PENDING_CONDITION };
|
||||||
for (int count = 1; !in.atEnd(); ++count) {
|
for (int count = 1; !in.atEnd(); ++count) {
|
||||||
QString line = QString::fromUtf8(in.readLine());
|
QString line = QString::fromLatin1(in.readLine());
|
||||||
if (line.startsWith("!!IF ")) {
|
if (line.startsWith("!!IF ")) {
|
||||||
if (state.isEmpty() || state.top() == IN_CONDITION) {
|
if (state.isEmpty() || state.top() == IN_CONDITION) {
|
||||||
QString test = line.mid(5, line.length()-(5+1));
|
QString test = line.mid(5, line.length()-(5+1));
|
||||||
@ -578,7 +578,7 @@ MakefileGenerator::init()
|
|||||||
contents += project->expand(line, in.fileName(), count);
|
contents += project->expand(line, in.fileName(), count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contentBytes = contents.toUtf8();
|
contentBytes = contents.toLatin1();
|
||||||
}
|
}
|
||||||
QFile out(outn);
|
QFile out(outn);
|
||||||
QFileInfo outfi(out);
|
QFileInfo outfi(out);
|
||||||
|
@ -344,7 +344,9 @@ public class QtActivityDelegate
|
|||||||
}
|
}
|
||||||
} else if ((inputHints & ImhHiddenText) != 0) {
|
} else if ((inputHints & ImhHiddenText) != 0) {
|
||||||
inputType |= android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
inputType |= android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
||||||
} else if ((inputHints & ImhSensitiveData) != 0 || (inputHints & ImhNoPredictiveText) != 0) {
|
} else if ((inputHints & ImhSensitiveData) != 0 ||
|
||||||
|
((inputHints & ImhNoPredictiveText) != 0 &&
|
||||||
|
System.getenv("QT_ANDROID_ENABLE_WORKAROUND_TO_DISABLE_PREDICTIVE_TEXT") != null)) {
|
||||||
inputType |= android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
|
inputType |= android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
src/platformsupport/input/input-support.pro
Normal file
35
src/platformsupport/input/input-support.pro
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
TARGET = QtInputSupport
|
||||||
|
MODULE = input_support
|
||||||
|
|
||||||
|
QT = core-private gui-private devicediscovery_support-private
|
||||||
|
CONFIG += static internal_module
|
||||||
|
|
||||||
|
DEFINES += QT_NO_CAST_FROM_ASCII
|
||||||
|
PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h
|
||||||
|
|
||||||
|
qtConfig(evdev) {
|
||||||
|
include($$PWD/evdevmouse/evdevmouse.pri)
|
||||||
|
include($$PWD/evdevkeyboard/evdevkeyboard.pri)
|
||||||
|
include($$PWD/evdevtouch/evdevtouch.pri)
|
||||||
|
qtConfig(tabletevent) {
|
||||||
|
include($$PWD/evdevtablet/evdevtablet.pri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qtConfig(tslib) {
|
||||||
|
include($$PWD/tslib/tslib.pri)
|
||||||
|
}
|
||||||
|
|
||||||
|
qtConfig(libinput) {
|
||||||
|
include($$PWD/libinput/libinput.pri)
|
||||||
|
}
|
||||||
|
|
||||||
|
qtConfig(evdev)|qtConfig(libinput) {
|
||||||
|
include($$PWD/shared/shared.pri)
|
||||||
|
}
|
||||||
|
|
||||||
|
qtConfig(integrityhid) {
|
||||||
|
include($$PWD/integrityhid/integrityhid.pri)
|
||||||
|
}
|
||||||
|
|
||||||
|
load(qt_module)
|
@ -1,35 +1,8 @@
|
|||||||
TARGET = QtInputSupport
|
TEMPLATE = subdirs
|
||||||
MODULE = input_support
|
QT_FOR_CONFIG += gui-private
|
||||||
|
|
||||||
QT = core-private gui-private devicediscovery_support-private
|
qtConfig(xkbcommon): SUBDIRS += xkbcommon
|
||||||
CONFIG += static internal_module
|
|
||||||
|
|
||||||
DEFINES += QT_NO_CAST_FROM_ASCII
|
SUBDIRS += input-support.pro ### FIXME - QTBUG-52657
|
||||||
PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h
|
|
||||||
|
|
||||||
qtConfig(evdev) {
|
CONFIG += ordered
|
||||||
include($$PWD/evdevmouse/evdevmouse.pri)
|
|
||||||
include($$PWD/evdevkeyboard/evdevkeyboard.pri)
|
|
||||||
include($$PWD/evdevtouch/evdevtouch.pri)
|
|
||||||
qtConfig(tabletevent) {
|
|
||||||
include($$PWD/evdevtablet/evdevtablet.pri)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qtConfig(tslib) {
|
|
||||||
include($$PWD/tslib/tslib.pri)
|
|
||||||
}
|
|
||||||
|
|
||||||
qtConfig(libinput) {
|
|
||||||
include($$PWD/libinput/libinput.pri)
|
|
||||||
}
|
|
||||||
|
|
||||||
qtConfig(evdev)|qtConfig(libinput) {
|
|
||||||
include($$PWD/shared/shared.pri)
|
|
||||||
}
|
|
||||||
|
|
||||||
qtConfig(integrityhid) {
|
|
||||||
include($$PWD/integrityhid/integrityhid.pri)
|
|
||||||
}
|
|
||||||
|
|
||||||
load(qt_module)
|
|
||||||
|
@ -14,4 +14,7 @@ QMAKE_USE_PRIVATE += libudev libinput
|
|||||||
|
|
||||||
INCLUDEPATH += $$PWD/../shared
|
INCLUDEPATH += $$PWD/../shared
|
||||||
|
|
||||||
qtConfig(xkbcommon): QMAKE_USE_PRIVATE += xkbcommon
|
qtConfig(xkbcommon): {
|
||||||
|
QMAKE_USE_PRIVATE += xkbcommon
|
||||||
|
QT += xkbcommon_support-private
|
||||||
|
}
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#if QT_CONFIG(xkbcommon)
|
#if QT_CONFIG(xkbcommon)
|
||||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||||
#include <xkbcommon/xkbcommon-names.h>
|
#include <xkbcommon/xkbcommon-names.h>
|
||||||
|
#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -56,88 +57,7 @@ Q_DECLARE_LOGGING_CATEGORY(qLcLibInput)
|
|||||||
const int REPEAT_DELAY = 500;
|
const int REPEAT_DELAY = 500;
|
||||||
const int REPEAT_RATE = 100;
|
const int REPEAT_RATE = 100;
|
||||||
|
|
||||||
#if QT_CONFIG(xkbcommon)
|
|
||||||
struct KeyTabEntry {
|
|
||||||
int xkbkey;
|
|
||||||
int qtkey;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline bool operator==(const KeyTabEntry &a, const KeyTabEntry &b)
|
|
||||||
{
|
|
||||||
return a.xkbkey == b.xkbkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const KeyTabEntry keyTab[] = {
|
|
||||||
{ XKB_KEY_Escape, Qt::Key_Escape },
|
|
||||||
{ XKB_KEY_Tab, Qt::Key_Tab },
|
|
||||||
{ XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab },
|
|
||||||
{ XKB_KEY_BackSpace, Qt::Key_Backspace },
|
|
||||||
{ XKB_KEY_Return, Qt::Key_Return },
|
|
||||||
{ XKB_KEY_Insert, Qt::Key_Insert },
|
|
||||||
{ XKB_KEY_Delete, Qt::Key_Delete },
|
|
||||||
{ XKB_KEY_Clear, Qt::Key_Delete },
|
|
||||||
{ XKB_KEY_Pause, Qt::Key_Pause },
|
|
||||||
{ XKB_KEY_Print, Qt::Key_Print },
|
|
||||||
|
|
||||||
{ XKB_KEY_Home, Qt::Key_Home },
|
|
||||||
{ XKB_KEY_End, Qt::Key_End },
|
|
||||||
{ XKB_KEY_Left, Qt::Key_Left },
|
|
||||||
{ XKB_KEY_Up, Qt::Key_Up },
|
|
||||||
{ XKB_KEY_Right, Qt::Key_Right },
|
|
||||||
{ XKB_KEY_Down, Qt::Key_Down },
|
|
||||||
{ XKB_KEY_Prior, Qt::Key_PageUp },
|
|
||||||
{ XKB_KEY_Next, Qt::Key_PageDown },
|
|
||||||
|
|
||||||
{ XKB_KEY_Shift_L, Qt::Key_Shift },
|
|
||||||
{ XKB_KEY_Shift_R, Qt::Key_Shift },
|
|
||||||
{ XKB_KEY_Shift_Lock, Qt::Key_Shift },
|
|
||||||
{ XKB_KEY_Control_L, Qt::Key_Control },
|
|
||||||
{ XKB_KEY_Control_R, Qt::Key_Control },
|
|
||||||
{ XKB_KEY_Meta_L, Qt::Key_Meta },
|
|
||||||
{ XKB_KEY_Meta_R, Qt::Key_Meta },
|
|
||||||
{ XKB_KEY_Alt_L, Qt::Key_Alt },
|
|
||||||
{ XKB_KEY_Alt_R, Qt::Key_Alt },
|
|
||||||
{ XKB_KEY_Caps_Lock, Qt::Key_CapsLock },
|
|
||||||
{ XKB_KEY_Num_Lock, Qt::Key_NumLock },
|
|
||||||
{ XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock },
|
|
||||||
{ XKB_KEY_Super_L, Qt::Key_Super_L },
|
|
||||||
{ XKB_KEY_Super_R, Qt::Key_Super_R },
|
|
||||||
{ XKB_KEY_Menu, Qt::Key_Menu },
|
|
||||||
{ XKB_KEY_Hyper_L, Qt::Key_Hyper_L },
|
|
||||||
{ XKB_KEY_Hyper_R, Qt::Key_Hyper_R },
|
|
||||||
{ XKB_KEY_Help, Qt::Key_Help },
|
|
||||||
|
|
||||||
{ XKB_KEY_KP_Space, Qt::Key_Space },
|
|
||||||
{ XKB_KEY_KP_Tab, Qt::Key_Tab },
|
|
||||||
{ XKB_KEY_KP_Enter, Qt::Key_Enter },
|
|
||||||
{ XKB_KEY_KP_Home, Qt::Key_Home },
|
|
||||||
{ XKB_KEY_KP_Left, Qt::Key_Left },
|
|
||||||
{ XKB_KEY_KP_Up, Qt::Key_Up },
|
|
||||||
{ XKB_KEY_KP_Right, Qt::Key_Right },
|
|
||||||
{ XKB_KEY_KP_Down, Qt::Key_Down },
|
|
||||||
{ XKB_KEY_KP_Prior, Qt::Key_PageUp },
|
|
||||||
{ XKB_KEY_KP_Next, Qt::Key_PageDown },
|
|
||||||
{ XKB_KEY_KP_End, Qt::Key_End },
|
|
||||||
{ XKB_KEY_KP_Begin, Qt::Key_Clear },
|
|
||||||
{ XKB_KEY_KP_Insert, Qt::Key_Insert },
|
|
||||||
{ XKB_KEY_KP_Delete, Qt::Key_Delete },
|
|
||||||
{ XKB_KEY_KP_Equal, Qt::Key_Equal },
|
|
||||||
{ XKB_KEY_KP_Multiply, Qt::Key_Asterisk },
|
|
||||||
{ XKB_KEY_KP_Add, Qt::Key_Plus },
|
|
||||||
{ XKB_KEY_KP_Separator, Qt::Key_Comma },
|
|
||||||
{ XKB_KEY_KP_Subtract, Qt::Key_Minus },
|
|
||||||
{ XKB_KEY_KP_Decimal, Qt::Key_Period },
|
|
||||||
{ XKB_KEY_KP_Divide, Qt::Key_Slash },
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QLibInputKeyboard::QLibInputKeyboard()
|
QLibInputKeyboard::QLibInputKeyboard()
|
||||||
#if QT_CONFIG(xkbcommon)
|
|
||||||
: m_ctx(0),
|
|
||||||
m_keymap(0),
|
|
||||||
m_state(0),
|
|
||||||
m_mods(Qt::NoModifier)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
#if QT_CONFIG(xkbcommon)
|
#if QT_CONFIG(xkbcommon)
|
||||||
qCDebug(qLcLibInput) << "Using xkbcommon for key mapping";
|
qCDebug(qLcLibInput) << "Using xkbcommon for key mapping";
|
||||||
@ -148,18 +68,14 @@ QLibInputKeyboard::QLibInputKeyboard()
|
|||||||
}
|
}
|
||||||
m_keymap = xkb_keymap_new_from_names(m_ctx, nullptr, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
m_keymap = xkb_keymap_new_from_names(m_ctx, nullptr, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||||
if (!m_keymap) {
|
if (!m_keymap) {
|
||||||
qWarning("Failed to compile keymap");
|
qCWarning(qLcLibInput, "Failed to compile keymap");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_state = xkb_state_new(m_keymap);
|
m_state = xkb_state_new(m_keymap);
|
||||||
if (!m_state) {
|
if (!m_state) {
|
||||||
qWarning("Failed to create xkb state");
|
qCWarning(qLcLibInput, "Failed to create xkb state");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_modindex[0] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_CTRL);
|
|
||||||
m_modindex[1] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_ALT);
|
|
||||||
m_modindex[2] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_SHIFT);
|
|
||||||
m_modindex[3] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_LOGO);
|
|
||||||
|
|
||||||
m_repeatTimer.setSingleShot(true);
|
m_repeatTimer.setSingleShot(true);
|
||||||
connect(&m_repeatTimer, &QTimer::timeout, this, &QLibInputKeyboard::handleRepeat);
|
connect(&m_repeatTimer, &QTimer::timeout, this, &QLibInputKeyboard::handleRepeat);
|
||||||
@ -186,52 +102,33 @@ void QLibInputKeyboard::processKey(libinput_event_keyboard *e)
|
|||||||
if (!m_ctx || !m_keymap || !m_state)
|
if (!m_ctx || !m_keymap || !m_state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const uint32_t k = libinput_event_keyboard_get_key(e) + 8;
|
const uint32_t keycode = libinput_event_keyboard_get_key(e) + 8;
|
||||||
|
const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_state, keycode);
|
||||||
const bool pressed = libinput_event_keyboard_get_key_state(e) == LIBINPUT_KEY_STATE_PRESSED;
|
const bool pressed = libinput_event_keyboard_get_key_state(e) == LIBINPUT_KEY_STATE_PRESSED;
|
||||||
|
|
||||||
QVarLengthArray<char, 32> chars(32);
|
// Modifiers here is the modifier state before the event, i.e. not
|
||||||
const int size = xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size());
|
// including the current key in case it is a modifier. See the XOR
|
||||||
if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL
|
// logic in QKeyEvent::modifiers(). ### QTBUG-73826
|
||||||
chars.resize(size + 1);
|
Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(m_state);
|
||||||
xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size());
|
|
||||||
}
|
|
||||||
const QString text = QString::fromUtf8(chars.constData(), size);
|
|
||||||
|
|
||||||
const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_state, k);
|
const QString text = QXkbCommon::lookupString(m_state, keycode);
|
||||||
|
const int qtkey = QXkbCommon::keysymToQtKey(sym, modifiers, m_state, keycode);
|
||||||
|
|
||||||
// mods here is the modifier state before the event, i.e. not
|
xkb_state_update_key(m_state, keycode, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
|
||||||
// including the current key in case it is a modifier.
|
|
||||||
Qt::KeyboardModifiers mods = Qt::NoModifier;
|
|
||||||
const int qtkey = keysymToQtKey(sym, &mods, text);
|
|
||||||
|
|
||||||
if (qtkey == Qt::Key_Control)
|
Qt::KeyboardModifiers modifiersAfterStateChange = QXkbCommon::modifiers(m_state);
|
||||||
mods |= Qt::ControlModifier;
|
QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(modifiersAfterStateChange);
|
||||||
if (qtkey == Qt::Key_Alt)
|
|
||||||
mods |= Qt::AltModifier;
|
|
||||||
if (qtkey == Qt::Key_Shift)
|
|
||||||
mods |= Qt::ShiftModifier;
|
|
||||||
if (qtkey == Qt::Key_Meta)
|
|
||||||
mods |= Qt::MetaModifier;
|
|
||||||
xkb_state_update_key(m_state, k, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
|
|
||||||
|
|
||||||
if (mods != Qt::NoModifier) {
|
|
||||||
if (pressed)
|
|
||||||
m_mods |= mods;
|
|
||||||
else
|
|
||||||
m_mods &= ~mods;
|
|
||||||
|
|
||||||
QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(m_mods);
|
|
||||||
}
|
|
||||||
QWindowSystemInterface::handleExtendedKeyEvent(nullptr,
|
QWindowSystemInterface::handleExtendedKeyEvent(nullptr,
|
||||||
pressed ? QEvent::KeyPress : QEvent::KeyRelease,
|
pressed ? QEvent::KeyPress : QEvent::KeyRelease,
|
||||||
qtkey, m_mods, k, sym, m_mods, text);
|
qtkey, modifiers, keycode, sym, modifiers, text);
|
||||||
|
|
||||||
if (pressed && xkb_keymap_key_repeats(m_keymap, k)) {
|
if (pressed && xkb_keymap_key_repeats(m_keymap, keycode)) {
|
||||||
m_repeatData.qtkey = qtkey;
|
m_repeatData.qtkey = qtkey;
|
||||||
m_repeatData.mods = mods;
|
m_repeatData.mods = modifiers;
|
||||||
m_repeatData.nativeScanCode = k;
|
m_repeatData.nativeScanCode = keycode;
|
||||||
m_repeatData.virtualKey = sym;
|
m_repeatData.virtualKey = sym;
|
||||||
m_repeatData.nativeMods = mods;
|
m_repeatData.nativeMods = modifiers;
|
||||||
m_repeatData.unicodeText = text;
|
m_repeatData.unicodeText = text;
|
||||||
m_repeatData.repeatCount = 1;
|
m_repeatData.repeatCount = 1;
|
||||||
m_repeatTimer.setInterval(REPEAT_DELAY);
|
m_repeatTimer.setInterval(REPEAT_DELAY);
|
||||||
@ -256,50 +153,6 @@ void QLibInputKeyboard::handleRepeat()
|
|||||||
m_repeatTimer.setInterval(REPEAT_RATE);
|
m_repeatTimer.setInterval(REPEAT_RATE);
|
||||||
m_repeatTimer.start();
|
m_repeatTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
int QLibInputKeyboard::keysymToQtKey(xkb_keysym_t key) const
|
|
||||||
{
|
|
||||||
const size_t elemCount = sizeof(keyTab) / sizeof(KeyTabEntry);
|
|
||||||
KeyTabEntry e;
|
|
||||||
e.xkbkey = key;
|
|
||||||
const KeyTabEntry *result = std::find(keyTab, keyTab + elemCount, e);
|
|
||||||
return result != keyTab + elemCount ? result->qtkey : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QLibInputKeyboard::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers *modifiers, const QString &text) const
|
|
||||||
{
|
|
||||||
int code = 0;
|
|
||||||
#if QT_CONFIG(textcodec)
|
|
||||||
QTextCodec *systemCodec = QTextCodec::codecForLocale();
|
|
||||||
#endif
|
|
||||||
if (keysym < 128 || (keysym < 256
|
|
||||||
#if QT_CONFIG(textcodec)
|
|
||||||
&& systemCodec->mibEnum() == 4
|
|
||||||
#endif
|
|
||||||
)) {
|
|
||||||
// upper-case key, if known
|
|
||||||
code = isprint((int)keysym) ? toupper((int)keysym) : 0;
|
|
||||||
} else if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) {
|
|
||||||
// function keys
|
|
||||||
code = Qt::Key_F1 + ((int)keysym - XKB_KEY_F1);
|
|
||||||
} else if (keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_9) {
|
|
||||||
if (keysym >= XKB_KEY_KP_0) {
|
|
||||||
// numeric keypad keys
|
|
||||||
code = Qt::Key_0 + ((int)keysym - XKB_KEY_KP_0);
|
|
||||||
} else {
|
|
||||||
code = keysymToQtKey(keysym);
|
|
||||||
}
|
|
||||||
*modifiers |= Qt::KeypadModifier;
|
|
||||||
} else if (text.length() == 1 && text.unicode()->unicode() > 0x1f
|
|
||||||
&& text.unicode()->unicode() != 0x7f
|
|
||||||
&& !(keysym >= XKB_KEY_dead_grave && keysym <= XKB_KEY_dead_longsolidusoverlay)) {
|
|
||||||
code = text.unicode()->toUpper().unicode();
|
|
||||||
} else {
|
|
||||||
// any other keys
|
|
||||||
code = keysymToQtKey(keysym);
|
|
||||||
}
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -79,10 +79,9 @@ private:
|
|||||||
int keysymToQtKey(xkb_keysym_t key) const;
|
int keysymToQtKey(xkb_keysym_t key) const;
|
||||||
int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers *modifiers, const QString &text) const;
|
int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers *modifiers, const QString &text) const;
|
||||||
|
|
||||||
xkb_context *m_ctx;
|
xkb_context *m_ctx = nullptr;
|
||||||
xkb_keymap *m_keymap;
|
xkb_keymap *m_keymap = nullptr;
|
||||||
xkb_state *m_state;
|
xkb_state *m_state = nullptr;
|
||||||
xkb_mod_index_t m_modindex[4];
|
|
||||||
|
|
||||||
QTimer m_repeatTimer;
|
QTimer m_repeatTimer;
|
||||||
|
|
||||||
@ -95,7 +94,6 @@ private:
|
|||||||
QString unicodeText;
|
QString unicodeText;
|
||||||
int repeatCount;
|
int repeatCount;
|
||||||
} m_repeatData;
|
} m_repeatData;
|
||||||
Qt::KeyboardModifiers m_mods;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
828
src/platformsupport/input/xkbcommon/qxkbcommon.cpp
Normal file
828
src/platformsupport/input/xkbcommon/qxkbcommon.cpp
Normal file
@ -0,0 +1,828 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "qxkbcommon_p.h"
|
||||||
|
|
||||||
|
#include <private/qmakearray_p.h>
|
||||||
|
|
||||||
|
#include <QtCore/QMetaMethod>
|
||||||
|
#include <QtGui/QKeyEvent>
|
||||||
|
#include <QtGui/private/qguiapplication_p.h>
|
||||||
|
|
||||||
|
#include <qpa/qplatforminputcontext.h>
|
||||||
|
#include <qpa/qplatformintegration.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
typedef struct xkb2qt
|
||||||
|
{
|
||||||
|
unsigned int xkb;
|
||||||
|
unsigned int qt;
|
||||||
|
|
||||||
|
constexpr bool operator <=(const xkb2qt &that) const noexcept
|
||||||
|
{
|
||||||
|
return xkb <= that.xkb;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator <(const xkb2qt &that) const noexcept
|
||||||
|
{
|
||||||
|
return xkb < that.xkb;
|
||||||
|
}
|
||||||
|
} xkb2qt_t;
|
||||||
|
|
||||||
|
template<std::size_t Xkb, std::size_t Qt>
|
||||||
|
struct Xkb2Qt
|
||||||
|
{
|
||||||
|
using Type = xkb2qt_t;
|
||||||
|
static constexpr Type data() noexcept { return Type{Xkb, Qt}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr const auto KeyTbl = qMakeArray(
|
||||||
|
QSortedData<
|
||||||
|
// misc keys
|
||||||
|
|
||||||
|
Xkb2Qt<XKB_KEY_Escape, Qt::Key_Escape>,
|
||||||
|
Xkb2Qt<XKB_KEY_Tab, Qt::Key_Tab>,
|
||||||
|
Xkb2Qt<XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab>,
|
||||||
|
Xkb2Qt<XKB_KEY_BackSpace, Qt::Key_Backspace>,
|
||||||
|
Xkb2Qt<XKB_KEY_Return, Qt::Key_Return>,
|
||||||
|
Xkb2Qt<XKB_KEY_Insert, Qt::Key_Insert>,
|
||||||
|
Xkb2Qt<XKB_KEY_Delete, Qt::Key_Delete>,
|
||||||
|
Xkb2Qt<XKB_KEY_Clear, Qt::Key_Delete>,
|
||||||
|
Xkb2Qt<XKB_KEY_Pause, Qt::Key_Pause>,
|
||||||
|
Xkb2Qt<XKB_KEY_Print, Qt::Key_Print>,
|
||||||
|
Xkb2Qt<0x1005FF60, Qt::Key_SysReq>, // hardcoded Sun SysReq
|
||||||
|
Xkb2Qt<0x1007ff00, Qt::Key_SysReq>, // hardcoded X386 SysReq
|
||||||
|
|
||||||
|
// cursor movement
|
||||||
|
|
||||||
|
Xkb2Qt<XKB_KEY_Home, Qt::Key_Home>,
|
||||||
|
Xkb2Qt<XKB_KEY_End, Qt::Key_End>,
|
||||||
|
Xkb2Qt<XKB_KEY_Left, Qt::Key_Left>,
|
||||||
|
Xkb2Qt<XKB_KEY_Up, Qt::Key_Up>,
|
||||||
|
Xkb2Qt<XKB_KEY_Right, Qt::Key_Right>,
|
||||||
|
Xkb2Qt<XKB_KEY_Down, Qt::Key_Down>,
|
||||||
|
Xkb2Qt<XKB_KEY_Prior, Qt::Key_PageUp>,
|
||||||
|
Xkb2Qt<XKB_KEY_Next, Qt::Key_PageDown>,
|
||||||
|
|
||||||
|
// modifiers
|
||||||
|
|
||||||
|
Xkb2Qt<XKB_KEY_Shift_L, Qt::Key_Shift>,
|
||||||
|
Xkb2Qt<XKB_KEY_Shift_R, Qt::Key_Shift>,
|
||||||
|
Xkb2Qt<XKB_KEY_Shift_Lock, Qt::Key_Shift>,
|
||||||
|
Xkb2Qt<XKB_KEY_Control_L, Qt::Key_Control>,
|
||||||
|
Xkb2Qt<XKB_KEY_Control_R, Qt::Key_Control>,
|
||||||
|
Xkb2Qt<XKB_KEY_Meta_L, Qt::Key_Meta>,
|
||||||
|
Xkb2Qt<XKB_KEY_Meta_R, Qt::Key_Meta>,
|
||||||
|
Xkb2Qt<XKB_KEY_Alt_L, Qt::Key_Alt>,
|
||||||
|
Xkb2Qt<XKB_KEY_Alt_R, Qt::Key_Alt>,
|
||||||
|
Xkb2Qt<XKB_KEY_Caps_Lock, Qt::Key_CapsLock>,
|
||||||
|
Xkb2Qt<XKB_KEY_Num_Lock, Qt::Key_NumLock>,
|
||||||
|
Xkb2Qt<XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock>,
|
||||||
|
Xkb2Qt<XKB_KEY_Super_L, Qt::Key_Super_L>,
|
||||||
|
Xkb2Qt<XKB_KEY_Super_R, Qt::Key_Super_R>,
|
||||||
|
Xkb2Qt<XKB_KEY_Menu, Qt::Key_Menu>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hyper_L, Qt::Key_Hyper_L>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hyper_R, Qt::Key_Hyper_R>,
|
||||||
|
Xkb2Qt<XKB_KEY_Help, Qt::Key_Help>,
|
||||||
|
Xkb2Qt<0x1000FF74, Qt::Key_Backtab>, // hardcoded HP backtab
|
||||||
|
Xkb2Qt<0x1005FF10, Qt::Key_F11>, // hardcoded Sun F36 (labeled F11)
|
||||||
|
Xkb2Qt<0x1005FF11, Qt::Key_F12>, // hardcoded Sun F37 (labeled F12)
|
||||||
|
|
||||||
|
// numeric and function keypad keys
|
||||||
|
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Space, Qt::Key_Space>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Tab, Qt::Key_Tab>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Enter, Qt::Key_Enter>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Home, Qt::Key_Home>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Left, Qt::Key_Left>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Up, Qt::Key_Up>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Right, Qt::Key_Right>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Down, Qt::Key_Down>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Prior, Qt::Key_PageUp>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Next, Qt::Key_PageDown>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_End, Qt::Key_End>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Begin, Qt::Key_Clear>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Insert, Qt::Key_Insert>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Delete, Qt::Key_Delete>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Equal, Qt::Key_Equal>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Multiply, Qt::Key_Asterisk>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Add, Qt::Key_Plus>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Separator, Qt::Key_Comma>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Subtract, Qt::Key_Minus>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Decimal, Qt::Key_Period>,
|
||||||
|
Xkb2Qt<XKB_KEY_KP_Divide, Qt::Key_Slash>,
|
||||||
|
|
||||||
|
// special non-XF86 function keys
|
||||||
|
|
||||||
|
Xkb2Qt<XKB_KEY_Undo, Qt::Key_Undo>,
|
||||||
|
Xkb2Qt<XKB_KEY_Redo, Qt::Key_Redo>,
|
||||||
|
Xkb2Qt<XKB_KEY_Find, Qt::Key_Find>,
|
||||||
|
Xkb2Qt<XKB_KEY_Cancel, Qt::Key_Cancel>,
|
||||||
|
|
||||||
|
// International input method support keys
|
||||||
|
|
||||||
|
// International & multi-key character composition
|
||||||
|
Xkb2Qt<XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr>,
|
||||||
|
Xkb2Qt<XKB_KEY_Multi_key, Qt::Key_Multi_key>,
|
||||||
|
Xkb2Qt<XKB_KEY_Codeinput, Qt::Key_Codeinput>,
|
||||||
|
Xkb2Qt<XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate>,
|
||||||
|
Xkb2Qt<XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate>,
|
||||||
|
Xkb2Qt<XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate>,
|
||||||
|
|
||||||
|
// Misc Functions
|
||||||
|
Xkb2Qt<XKB_KEY_Mode_switch, Qt::Key_Mode_switch>,
|
||||||
|
Xkb2Qt<XKB_KEY_script_switch, Qt::Key_Mode_switch>,
|
||||||
|
|
||||||
|
// Japanese keyboard support
|
||||||
|
Xkb2Qt<XKB_KEY_Kanji, Qt::Key_Kanji>,
|
||||||
|
Xkb2Qt<XKB_KEY_Muhenkan, Qt::Key_Muhenkan>,
|
||||||
|
//Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan_Mode>,
|
||||||
|
Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan>,
|
||||||
|
Xkb2Qt<XKB_KEY_Henkan, Qt::Key_Henkan>,
|
||||||
|
Xkb2Qt<XKB_KEY_Romaji, Qt::Key_Romaji>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hiragana, Qt::Key_Hiragana>,
|
||||||
|
Xkb2Qt<XKB_KEY_Katakana, Qt::Key_Katakana>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hiragana_Katakana, Qt::Key_Hiragana_Katakana>,
|
||||||
|
Xkb2Qt<XKB_KEY_Zenkaku, Qt::Key_Zenkaku>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hankaku, Qt::Key_Hankaku>,
|
||||||
|
Xkb2Qt<XKB_KEY_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku>,
|
||||||
|
Xkb2Qt<XKB_KEY_Touroku, Qt::Key_Touroku>,
|
||||||
|
Xkb2Qt<XKB_KEY_Massyo, Qt::Key_Massyo>,
|
||||||
|
Xkb2Qt<XKB_KEY_Kana_Lock, Qt::Key_Kana_Lock>,
|
||||||
|
Xkb2Qt<XKB_KEY_Kana_Shift, Qt::Key_Kana_Shift>,
|
||||||
|
Xkb2Qt<XKB_KEY_Eisu_Shift, Qt::Key_Eisu_Shift>,
|
||||||
|
Xkb2Qt<XKB_KEY_Eisu_toggle, Qt::Key_Eisu_toggle>,
|
||||||
|
//Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Kanji_Bangou>,
|
||||||
|
//Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_Zen_Koho>,
|
||||||
|
//Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_Mae_Koho>,
|
||||||
|
Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Codeinput>,
|
||||||
|
Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_MultipleCandidate>,
|
||||||
|
Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_PreviousCandidate>,
|
||||||
|
|
||||||
|
// Korean keyboard support
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul, Qt::Key_Hangul>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_Start, Qt::Key_Hangul_Start>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_End, Qt::Key_Hangul_End>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_Hanja, Qt::Key_Hangul_Hanja>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_Jamo, Qt::Key_Hangul_Jamo>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_Romaja, Qt::Key_Hangul_Romaja>,
|
||||||
|
//Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Hangul_Codeinput>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Codeinput>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_Jeonja, Qt::Key_Hangul_Jeonja>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_Banja, Qt::Key_Hangul_Banja>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_PreHanja, Qt::Key_Hangul_PreHanja>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_PostHanja, Qt::Key_Hangul_PostHanja>,
|
||||||
|
//Xkb2Qt<XKB_KEY_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate>,
|
||||||
|
//Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate>,
|
||||||
|
//Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_SingleCandidate, Qt::Key_SingleCandidate>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_Special, Qt::Key_Hangul_Special>,
|
||||||
|
//Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Hangul_switch>,
|
||||||
|
Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Mode_switch>,
|
||||||
|
|
||||||
|
// dead keys
|
||||||
|
Xkb2Qt<XKB_KEY_dead_grave, Qt::Key_Dead_Grave>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_acute, Qt::Key_Dead_Acute>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_macron, Qt::Key_Dead_Macron>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_breve, Qt::Key_Dead_Breve>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_caron, Qt::Key_Dead_Caron>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_iota, Qt::Key_Dead_Iota>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_hook, Qt::Key_Dead_Hook>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_horn, Qt::Key_Dead_Horn>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_stroke, Qt::Key_Dead_Stroke>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_abovecomma, Qt::Key_Dead_Abovecomma>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_abovereversedcomma, Qt::Key_Dead_Abovereversedcomma>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_doublegrave, Qt::Key_Dead_Doublegrave>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_belowring, Qt::Key_Dead_Belowring>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_belowmacron, Qt::Key_Dead_Belowmacron>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_belowcircumflex, Qt::Key_Dead_Belowcircumflex>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_belowtilde, Qt::Key_Dead_Belowtilde>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_belowbreve, Qt::Key_Dead_Belowbreve>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_belowdiaeresis, Qt::Key_Dead_Belowdiaeresis>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_invertedbreve, Qt::Key_Dead_Invertedbreve>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_belowcomma, Qt::Key_Dead_Belowcomma>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_currency, Qt::Key_Dead_Currency>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_a, Qt::Key_Dead_a>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_A, Qt::Key_Dead_A>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_e, Qt::Key_Dead_e>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_E, Qt::Key_Dead_E>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_i, Qt::Key_Dead_i>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_I, Qt::Key_Dead_I>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_o, Qt::Key_Dead_o>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_O, Qt::Key_Dead_O>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_u, Qt::Key_Dead_u>,
|
||||||
|
Xkb2Qt<XKB_KEY_dead_U, Qt::Key_Dead_U>,
|
||||||
|
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>,
|
||||||
|
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>,
|
||||||
|
|
||||||
|
// Special keys from X.org - This include multimedia keys,
|
||||||
|
// wireless/bluetooth/uwb keys, special launcher keys, etc.
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Back, Qt::Key_Back>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Forward, Qt::Key_Forward>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Stop, Qt::Key_Stop>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Refresh, Qt::Key_Refresh>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Favorites, Qt::Key_Favorites>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86HomePage, Qt::Key_HomePage>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Search, Qt::Key_Search>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioStop, Qt::Key_MediaStop>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioNext, Qt::Key_MediaNext>,
|
||||||
|
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_XF86Memo, Qt::Key_Memo>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86ToDoList, Qt::Key_ToDoList>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Calendar, Qt::Key_Calendar>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86PowerDown, Qt::Key_PowerDown>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Standby, Qt::Key_Standby>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86PowerOff, Qt::Key_PowerOff>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86WakeUp, Qt::Key_WakeUp>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Eject, Qt::Key_Eject>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86WWW, Qt::Key_WWW>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Sleep, Qt::Key_Sleep>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86LightBulb, Qt::Key_LightBulb>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Shop, Qt::Key_Shop>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86History, Qt::Key_History>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86HotLinks, Qt::Key_HotLinks>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Finance, Qt::Key_Finance>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Community, Qt::Key_Community>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86BackForward, Qt::Key_BackForward>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Book, Qt::Key_Book>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86CD, Qt::Key_CD>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Calculater, Qt::Key_Calculator>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Clear, Qt::Key_Clear>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Close, Qt::Key_Close>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Copy, Qt::Key_Copy>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Cut, Qt::Key_Cut>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Display, Qt::Key_Display>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86DOS, Qt::Key_DOS>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Documents, Qt::Key_Documents>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Excel, Qt::Key_Excel>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Explorer, Qt::Key_Explorer>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Game, Qt::Key_Game>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Go, Qt::Key_Go>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86iTouch, Qt::Key_iTouch>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86LogOff, Qt::Key_LogOff>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Market, Qt::Key_Market>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Meeting, Qt::Key_Meeting>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86MenuKB, Qt::Key_MenuKB>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86MenuPB, Qt::Key_MenuPB>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86MySites, Qt::Key_MySites>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86New, Qt::Key_New>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86News, Qt::Key_News>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Open, Qt::Key_Open>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Option, Qt::Key_Option>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Paste, Qt::Key_Paste>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Phone, Qt::Key_Phone>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Reply, Qt::Key_Reply>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Reload, Qt::Key_Reload>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86RotationPB, Qt::Key_RotationPB>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86RotationKB, Qt::Key_RotationKB>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Save, Qt::Key_Save>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Send, Qt::Key_Send>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Spell, Qt::Key_Spell>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Support, Qt::Key_Support>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86TaskPane, Qt::Key_TaskPane>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Terminal, Qt::Key_Terminal>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Tools, Qt::Key_Tools>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Travel, Qt::Key_Travel>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Video, Qt::Key_Video>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Word, Qt::Key_Word>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Xfer, Qt::Key_Xfer>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Away, Qt::Key_Away>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Messenger, Qt::Key_Messenger>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86WebCam, Qt::Key_WebCam>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86MailForward, Qt::Key_MailForward>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Pictures, Qt::Key_Pictures>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Music, Qt::Key_Music>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Battery, Qt::Key_Battery>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86WLAN, Qt::Key_WLAN>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86UWB, Qt::Key_UWB>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioForward, Qt::Key_AudioForward>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Subtitle, Qt::Key_Subtitle>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Time, Qt::Key_Time>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Select, Qt::Key_Select>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86View, Qt::Key_View>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86TopMenu, Qt::Key_TopMenu>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Red, Qt::Key_Red>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Green, Qt::Key_Green>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Yellow, Qt::Key_Yellow>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Blue, Qt::Key_Blue>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Suspend, Qt::Key_Suspend>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86Hibernate, Qt::Key_Hibernate>,
|
||||||
|
Xkb2Qt<XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle>,
|
||||||
|
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>
|
||||||
|
>::Data{}
|
||||||
|
);
|
||||||
|
|
||||||
|
xkb_keysym_t QXkbCommon::qxkbcommon_xkb_keysym_to_upper(xkb_keysym_t ks)
|
||||||
|
{
|
||||||
|
xkb_keysym_t lower, upper;
|
||||||
|
|
||||||
|
xkbcommon_XConvertCase(ks, &lower, &upper);
|
||||||
|
|
||||||
|
return upper;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QXkbCommon::lookupString(struct xkb_state *state, xkb_keycode_t code)
|
||||||
|
{
|
||||||
|
QVarLengthArray<char, 32> chars(32);
|
||||||
|
const int size = xkb_state_key_get_utf8(state, code, chars.data(), chars.size());
|
||||||
|
if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL
|
||||||
|
chars.resize(size + 1);
|
||||||
|
xkb_state_key_get_utf8(state, code, chars.data(), chars.size());
|
||||||
|
}
|
||||||
|
return QString::fromUtf8(chars.constData(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QXkbCommon::lookupStringNoKeysymTransformations(xkb_keysym_t keysym)
|
||||||
|
{
|
||||||
|
QVarLengthArray<char, 32> chars(32);
|
||||||
|
const int size = xkb_keysym_to_utf8(keysym, chars.data(), chars.size());
|
||||||
|
if (size == 0)
|
||||||
|
return QString(); // the keysym does not have a Unicode representation
|
||||||
|
|
||||||
|
if (Q_UNLIKELY(size > chars.size())) {
|
||||||
|
chars.resize(size);
|
||||||
|
xkb_keysym_to_utf8(keysym, chars.data(), chars.size());
|
||||||
|
}
|
||||||
|
return QString::fromUtf8(chars.constData(), size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<xkb_keysym_t> QXkbCommon::toKeysym(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
QVector<xkb_keysym_t> keysyms;
|
||||||
|
int qtKey = event->key();
|
||||||
|
|
||||||
|
if (qtKey >= Qt::Key_F1 && qtKey <= Qt::Key_F35) {
|
||||||
|
keysyms.append(XKB_KEY_F1 + (qtKey - Qt::Key_F1));
|
||||||
|
} 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()) {
|
||||||
|
keysyms.append(qtKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keysyms.isEmpty())
|
||||||
|
return keysyms;
|
||||||
|
|
||||||
|
// check if we have a direct mapping
|
||||||
|
auto it = std::find_if(KeyTbl.cbegin(), KeyTbl.cend(), [&qtKey](xkb2qt_t elem) {
|
||||||
|
return elem.qt == static_cast<uint>(qtKey);
|
||||||
|
});
|
||||||
|
if (it != KeyTbl.end()) {
|
||||||
|
keysyms.append(it->xkb);
|
||||||
|
return keysyms;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<uint> ucs4;
|
||||||
|
if (event->text().isEmpty())
|
||||||
|
ucs4.append(qtKey);
|
||||||
|
else
|
||||||
|
ucs4 = event->text().toUcs4();
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
keysyms.append(utf32 | 0x01000000);
|
||||||
|
|
||||||
|
return keysyms;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QXkbCommon::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers)
|
||||||
|
{
|
||||||
|
return keysymToQtKey(keysym, modifiers, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int QXkbCommon::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers,
|
||||||
|
xkb_state *state, xkb_keycode_t code,
|
||||||
|
bool superAsMeta, bool hyperAsMeta)
|
||||||
|
{
|
||||||
|
// 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.
|
||||||
|
if (modifiers & Qt::ControlModifier) {
|
||||||
|
// 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)) {
|
||||||
|
xkb_keysym_t latinKeysym = QXkbCommon::lookupLatinKeysym(state, code);
|
||||||
|
if (latinKeysym != XKB_KEY_NoSymbol)
|
||||||
|
keysym = latinKeysym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keysymToQtKey_internal(keysym, modifiers, state, code, superAsMeta, hyperAsMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers,
|
||||||
|
xkb_state *state, xkb_keycode_t code,
|
||||||
|
bool superAsMeta, bool hyperAsMeta)
|
||||||
|
{
|
||||||
|
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 (QXkbCommon::isLatin(keysym)) {
|
||||||
|
qtKey = QXkbCommon::qxkbcommon_xkb_keysym_to_upper(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qtKey)
|
||||||
|
return qtKey;
|
||||||
|
|
||||||
|
// lookup from unicode
|
||||||
|
QString text;
|
||||||
|
if (!state || 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 = QXkbCommon::lookupStringNoKeysymTransformations(keysym);
|
||||||
|
} else {
|
||||||
|
text = QXkbCommon::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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 modifiers = Qt::NoModifier;
|
||||||
|
|
||||||
|
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE) > 0)
|
||||||
|
modifiers |= Qt::ControlModifier;
|
||||||
|
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_EFFECTIVE) > 0)
|
||||||
|
modifiers |= Qt::AltModifier;
|
||||||
|
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_EFFECTIVE) > 0)
|
||||||
|
modifiers |= Qt::ShiftModifier;
|
||||||
|
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_EFFECTIVE) > 0)
|
||||||
|
modifiers |= Qt::MetaModifier;
|
||||||
|
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possible modifier states.
|
||||||
|
static const Qt::KeyboardModifiers ModsTbl[] = {
|
||||||
|
Qt::NoModifier, // 0
|
||||||
|
Qt::ShiftModifier, // 1
|
||||||
|
Qt::ControlModifier, // 2
|
||||||
|
Qt::ControlModifier | Qt::ShiftModifier, // 3
|
||||||
|
Qt::AltModifier, // 4
|
||||||
|
Qt::AltModifier | Qt::ShiftModifier, // 5
|
||||||
|
Qt::AltModifier | Qt::ControlModifier, // 6
|
||||||
|
Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7
|
||||||
|
Qt::NoModifier // Fall-back to raw Key_*, for non-latin1 kb layouts
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
|
||||||
|
bool superAsMeta, bool hyperAsMeta)
|
||||||
|
{
|
||||||
|
QList<int> result;
|
||||||
|
quint32 keycode = event->nativeScanCode();
|
||||||
|
Qt::KeyboardModifiers modifiers = event->modifiers();
|
||||||
|
xkb_keymap *keymap = xkb_state_get_keymap(state);
|
||||||
|
// turn off the modifier bits which doesn't participate in shortcuts
|
||||||
|
Qt::KeyboardModifiers notNeeded = Qt::KeypadModifier | Qt::GroupSwitchModifier;
|
||||||
|
modifiers &= ~notNeeded;
|
||||||
|
// create a fresh kb state and test against the relevant modifier combinations
|
||||||
|
ScopedXKBState scopedXkbQueryState(xkb_state_new(keymap));
|
||||||
|
xkb_state *queryState = scopedXkbQueryState.get();
|
||||||
|
if (!queryState) {
|
||||||
|
qCWarning(lcXkbcommon) << Q_FUNC_INFO << "failed to compile xkb keymap";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// get kb state from the master state and update the temporary state
|
||||||
|
xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LOCKED);
|
||||||
|
xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED);
|
||||||
|
xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED);
|
||||||
|
xkb_mod_mask_t depressedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED);
|
||||||
|
xkb_state_update_mask(queryState, depressedMods, latchedMods, lockedMods, 0, 0, lockedLayout);
|
||||||
|
// handle shortcuts for level three and above
|
||||||
|
xkb_layout_index_t layoutIndex = xkb_state_key_get_layout(queryState, keycode);
|
||||||
|
xkb_level_index_t levelIndex = 0;
|
||||||
|
if (layoutIndex != XKB_LAYOUT_INVALID) {
|
||||||
|
levelIndex = xkb_state_key_get_level(queryState, keycode, layoutIndex);
|
||||||
|
if (levelIndex == XKB_LEVEL_INVALID)
|
||||||
|
levelIndex = 0;
|
||||||
|
}
|
||||||
|
if (levelIndex <= 1)
|
||||||
|
xkb_state_update_mask(queryState, 0, latchedMods, lockedMods, 0, 0, lockedLayout);
|
||||||
|
|
||||||
|
xkb_keysym_t sym = xkb_state_key_get_one_sym(queryState, keycode);
|
||||||
|
if (sym == XKB_KEY_NoSymbol)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
int baseQtKey = keysymToQtKey_internal(sym, modifiers, queryState, keycode, superAsMeta, hyperAsMeta);
|
||||||
|
if (baseQtKey)
|
||||||
|
result += (baseQtKey + 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");
|
||||||
|
xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(keymap, "Control");
|
||||||
|
xkb_mod_index_t metaMod = xkb_keymap_mod_get_index(keymap, "Meta");
|
||||||
|
|
||||||
|
Q_ASSERT(shiftMod < 32);
|
||||||
|
Q_ASSERT(altMod < 32);
|
||||||
|
Q_ASSERT(controlMod < 32);
|
||||||
|
|
||||||
|
xkb_mod_mask_t depressed;
|
||||||
|
int qtKey = 0;
|
||||||
|
// obtain a list of possible shortcuts for the given key event
|
||||||
|
for (uint i = 1; i < sizeof(ModsTbl) / sizeof(*ModsTbl) ; ++i) {
|
||||||
|
Qt::KeyboardModifiers neededMods = ModsTbl[i];
|
||||||
|
if ((modifiers & neededMods) == neededMods) {
|
||||||
|
if (i == 8) {
|
||||||
|
if (isLatin(baseQtKey))
|
||||||
|
continue;
|
||||||
|
// add a latin key as a fall back key
|
||||||
|
sym = lookupLatinKeysym(state, keycode);
|
||||||
|
} else {
|
||||||
|
depressed = 0;
|
||||||
|
if (neededMods & Qt::AltModifier)
|
||||||
|
depressed |= (1 << altMod);
|
||||||
|
if (neededMods & Qt::ShiftModifier)
|
||||||
|
depressed |= (1 << shiftMod);
|
||||||
|
if (neededMods & Qt::ControlModifier)
|
||||||
|
depressed |= (1 << controlMod);
|
||||||
|
if (metaMod < 32 && neededMods & Qt::MetaModifier)
|
||||||
|
depressed |= (1 << metaMod);
|
||||||
|
xkb_state_update_mask(queryState, depressed, latchedMods, lockedMods, 0, 0, lockedLayout);
|
||||||
|
sym = xkb_state_key_get_one_sym(queryState, keycode);
|
||||||
|
}
|
||||||
|
if (sym == XKB_KEY_NoSymbol)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Qt::KeyboardModifiers mods = modifiers & ~neededMods;
|
||||||
|
qtKey = keysymToQtKey_internal(sym, mods, queryState, keycode, superAsMeta, hyperAsMeta);
|
||||||
|
if (!qtKey || qtKey == baseQtKey)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
ambiguous = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ambiguous)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
result += (qtKey + mods);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QXkbCommon::verifyHasLatinLayout(xkb_keymap *keymap)
|
||||||
|
{
|
||||||
|
const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(keymap);
|
||||||
|
const xkb_keycode_t minKeycode = xkb_keymap_min_keycode(keymap);
|
||||||
|
const xkb_keycode_t maxKeycode = xkb_keymap_max_keycode(keymap);
|
||||||
|
|
||||||
|
const xkb_keysym_t *keysyms = nullptr;
|
||||||
|
int nrLatinKeys = 0;
|
||||||
|
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]))
|
||||||
|
nrLatinKeys++;
|
||||||
|
if (nrLatinKeys > 10) // arbitrarily chosen threshold
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
xkb_keysym_t QXkbCommon::lookupLatinKeysym(xkb_state *state, xkb_keycode_t keycode)
|
||||||
|
{
|
||||||
|
xkb_layout_index_t layout;
|
||||||
|
xkb_keysym_t sym = XKB_KEY_NoSymbol;
|
||||||
|
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);
|
||||||
|
// 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 = nullptr;
|
||||||
|
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])) {
|
||||||
|
sym = syms[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sym == XKB_KEY_NoSymbol)
|
||||||
|
return sym;
|
||||||
|
|
||||||
|
xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED);
|
||||||
|
xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(state, 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).
|
||||||
|
// In this setup, the user would expect to trigger a ctrl+q shortcut by pressing ctrl+<physical x key>,
|
||||||
|
// because "US dvorak" is higher up in the layout settings list. This check verifies that an obtained
|
||||||
|
// 'sym' can not be acquired by any other layout higher up in the user's layout list. If it can be acquired
|
||||||
|
// then the obtained key is not unique. This prevents ctrl+<physical q key> from generating a ctrl+q
|
||||||
|
// shortcut in the above described setup. We don't want ctrl+<physical x key> and ctrl+<physical q key> to
|
||||||
|
// generate the same shortcut event in this case.
|
||||||
|
const xkb_keycode_t minKeycode = xkb_keymap_min_keycode(keymap);
|
||||||
|
const xkb_keycode_t maxKeycode = xkb_keymap_max_keycode(keymap);
|
||||||
|
ScopedXKBState queryState(xkb_state_new(keymap));
|
||||||
|
for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) {
|
||||||
|
xkb_state_update_mask(queryState.get(), 0, latchedMods, lockedMods, 0, 0, prevLayout);
|
||||||
|
for (xkb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
|
||||||
|
xkb_keysym_t prevSym = xkb_state_key_get_one_sym(queryState.get(), code);
|
||||||
|
if (prevSym == sym) {
|
||||||
|
sym = XKB_KEY_NoSymbol;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QXkbCommon::setXkbContext(QPlatformInputContext *inputContext, struct xkb_context *context)
|
||||||
|
{
|
||||||
|
if (!inputContext || !context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char *const inputContextClassName = "QComposeInputContext";
|
||||||
|
const char *const normalizedSignature = "setXkbContext(xkb_context*)";
|
||||||
|
|
||||||
|
if (inputContext->objectName() != QLatin1String(inputContextClassName))
|
||||||
|
return;
|
||||||
|
|
||||||
|
static const QMetaMethod setXkbContext = [&]() {
|
||||||
|
int methodIndex = inputContext->metaObject()->indexOfMethod(normalizedSignature);
|
||||||
|
QMetaMethod method = inputContext->metaObject()->method(methodIndex);
|
||||||
|
Q_ASSERT(method.isValid());
|
||||||
|
if (!method.isValid())
|
||||||
|
qCWarning(lcXkbcommon) << normalizedSignature << "not found on" << inputContextClassName;
|
||||||
|
return method;
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (!setXkbContext.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
setXkbContext.invoke(inputContext, Qt::DirectConnection, Q_ARG(struct xkb_context*, context));
|
||||||
|
}
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
@ -1,9 +1,9 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2018 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the plugins of the Qt Toolkit.
|
** This file is part of the QtGui module of the Qt Toolkit.
|
||||||
**
|
**
|
||||||
** $QT_BEGIN_LICENSE:LGPL$
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
** Commercial License Usage
|
** Commercial License Usage
|
||||||
@ -37,10 +37,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* XConvertCase was copied from src/3rdparty/xkbcommon/src/keysym.c,
|
/* Copyright 1985, 1987, 1990, 1998 The Open Group
|
||||||
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
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
@ -89,6 +86,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
XConvertCase was copied from src/3rdparty/xkbcommon/src/keysym.c
|
||||||
The following code modifications were applied:
|
The following code modifications were applied:
|
||||||
|
|
||||||
XConvertCase() was renamed to xkbcommon_XConvertCase(), to not confuse it
|
XConvertCase() was renamed to xkbcommon_XConvertCase(), to not confuse it
|
||||||
@ -99,10 +97,9 @@
|
|||||||
results instead of using the less complete version from keysym.c
|
results instead of using the less complete version from keysym.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include "qxkbcommon_p.h"
|
||||||
#include <QtCore/QChar>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
#include <QtCore/QChar>
|
||||||
|
|
||||||
static void qt_UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper)
|
static void qt_UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper)
|
||||||
{
|
{
|
||||||
@ -110,7 +107,7 @@ static void qt_UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *
|
|||||||
*upper = QChar::toUpper(code);
|
*upper = QChar::toUpper(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper)
|
void QXkbCommon::xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper)
|
||||||
{
|
{
|
||||||
/* Latin 1 keysym */
|
/* Latin 1 keysym */
|
||||||
if (sym < 0x100) {
|
if (sym < 0x100) {
|
||||||
@ -220,14 +217,3 @@ void xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t
|
|||||||
break;
|
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
|
|
122
src/platformsupport/input/xkbcommon/qxkbcommon_p.h
Normal file
122
src/platformsupport/input/xkbcommon/qxkbcommon_p.h
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2018 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$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QXKBCOMMON_P_H
|
||||||
|
#define QXKBCOMMON_P_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G
|
||||||
|
// -------------
|
||||||
|
//
|
||||||
|
// This file is not part of the Qt API. It exists purely as an
|
||||||
|
// implementation detail. This header file may change from version to
|
||||||
|
// version without notice, or even be removed.
|
||||||
|
//
|
||||||
|
// We mean it.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QtCore/QString>
|
||||||
|
#include <QtCore/QVector>
|
||||||
|
#include <QtCore/QLoggingCategory>
|
||||||
|
#include <QtCore/QList>
|
||||||
|
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(lcXkbcommon)
|
||||||
|
|
||||||
|
class QEvent;
|
||||||
|
class QKeyEvent;
|
||||||
|
class QPlatformInputContext;
|
||||||
|
|
||||||
|
class QXkbCommon
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QString lookupString(struct xkb_state *state, xkb_keycode_t code);
|
||||||
|
static QString lookupStringNoKeysymTransformations(xkb_keysym_t keysym);
|
||||||
|
|
||||||
|
static QVector<xkb_keysym_t> toKeysym(QKeyEvent *event);
|
||||||
|
|
||||||
|
static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers);
|
||||||
|
static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers,
|
||||||
|
xkb_state *state, xkb_keycode_t code,
|
||||||
|
bool superAsMeta = false, bool hyperAsMeta = false);
|
||||||
|
|
||||||
|
// xkbcommon_* API is part of libxkbcommon internals, with modifications as
|
||||||
|
// desribed in the header of the implementation file.
|
||||||
|
static void xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper);
|
||||||
|
static xkb_keysym_t qxkbcommon_xkb_keysym_to_upper(xkb_keysym_t ks);
|
||||||
|
|
||||||
|
static Qt::KeyboardModifiers modifiers(struct xkb_state *state);
|
||||||
|
|
||||||
|
static QList<int> possibleKeys(xkb_state *state, const QKeyEvent *event,
|
||||||
|
bool superAsMeta = false, bool hyperAsMeta = false);
|
||||||
|
|
||||||
|
static void verifyHasLatinLayout(xkb_keymap *keymap);
|
||||||
|
static xkb_keysym_t lookupLatinKeysym(xkb_state *state, xkb_keycode_t keycode);
|
||||||
|
|
||||||
|
static bool isLatin(xkb_keysym_t sym) {
|
||||||
|
return ((sym >= 'a' && sym <= 'z') || (sym >= 'A' && sym <= 'Z'));
|
||||||
|
}
|
||||||
|
static bool isKeypad(xkb_keysym_t sym) {
|
||||||
|
return sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setXkbContext(QPlatformInputContext *inputContext, struct xkb_context *context);
|
||||||
|
|
||||||
|
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>;
|
||||||
|
};
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // QXKBCOMMON_P_H
|
23
src/platformsupport/input/xkbcommon/xkbcommon.pro
Normal file
23
src/platformsupport/input/xkbcommon/xkbcommon.pro
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
TARGET = QtXkbCommonSupport
|
||||||
|
MODULE = xkbcommon_support
|
||||||
|
|
||||||
|
QT = core-private gui-private
|
||||||
|
CONFIG += static internal_module
|
||||||
|
|
||||||
|
DEFINES += QT_NO_CAST_FROM_ASCII
|
||||||
|
PRECOMPILED_HEADER = ../../../corelib/global/qt_pch.h
|
||||||
|
|
||||||
|
QMAKE_USE_PRIVATE += xkbcommon
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
qxkbcommon_p.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
qxkbcommon.cpp \
|
||||||
|
qxkbcommon_3rdparty.cpp
|
||||||
|
|
||||||
|
# qxkbcommon.cpp::KeyTbl has more than 256 levels of expansion and older
|
||||||
|
# Clang uses that as a limit (it's 1024 in current versions).
|
||||||
|
clang:!intel_icc: QMAKE_CXXFLAGS += -ftemplate-depth=1024
|
||||||
|
|
||||||
|
load(qt_module)
|
@ -3,18 +3,14 @@ TARGET = composeplatforminputcontextplugin
|
|||||||
QT += core-private gui-private
|
QT += core-private gui-private
|
||||||
|
|
||||||
SOURCES += $$PWD/qcomposeplatforminputcontextmain.cpp \
|
SOURCES += $$PWD/qcomposeplatforminputcontextmain.cpp \
|
||||||
$$PWD/qcomposeplatforminputcontext.cpp \
|
$$PWD/qcomposeplatforminputcontext.cpp
|
||||||
$$PWD/generator/qtablegenerator.cpp \
|
|
||||||
|
|
||||||
HEADERS += $$PWD/qcomposeplatforminputcontext.h \
|
HEADERS += $$PWD/qcomposeplatforminputcontext.h
|
||||||
$$PWD/generator/qtablegenerator.h \
|
|
||||||
|
|
||||||
QMAKE_USE_PRIVATE += xkbcommon
|
QMAKE_USE_PRIVATE += xkbcommon
|
||||||
|
|
||||||
include($$OUT_PWD/../../../gui/qtgui-config.pri)
|
include($$OUT_PWD/../../../gui/qtgui-config.pri)
|
||||||
|
|
||||||
DEFINES += X11_PREFIX='\\"$$QMAKE_X11_PREFIX\\"'
|
|
||||||
|
|
||||||
OTHER_FILES += $$PWD/compose.json
|
OTHER_FILES += $$PWD/compose.json
|
||||||
|
|
||||||
PLUGIN_TYPE = platforminputcontexts
|
PLUGIN_TYPE = platforminputcontexts
|
||||||
|
@ -1,658 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2016 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$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "qtablegenerator.h"
|
|
||||||
|
|
||||||
#include <QtCore/QByteArray>
|
|
||||||
#include <QtCore/QTextCodec>
|
|
||||||
#include <QtCore/QDebug>
|
|
||||||
#include <QtCore/QDir>
|
|
||||||
#include <QtCore/QStringList>
|
|
||||||
#include <QtCore/QString>
|
|
||||||
#include <QtCore/QSaveFile>
|
|
||||||
#include <QtCore/QStandardPaths>
|
|
||||||
#include <private/qcore_unix_p.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
|
||||||
|
|
||||||
#include <locale.h> // LC_CTYPE
|
|
||||||
#include <string.h> // strchr, strncmp, etc.
|
|
||||||
#include <strings.h> // strncasecmp
|
|
||||||
#include <clocale> // LC_CTYPE
|
|
||||||
|
|
||||||
static const quint32 SupportedCacheVersion = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
In short on how and why the "Compose" file is cached:
|
|
||||||
|
|
||||||
The "Compose" file is large, for en_US it's likely located at:
|
|
||||||
/usr/share/X11/locale/en_US.UTF-8/Compose
|
|
||||||
and it has about 6000 string lines.
|
|
||||||
Q(Gui)Applications parse this file each time they're created. On modern CPUs
|
|
||||||
it incurs a 4-10 ms startup penalty of each Qt gui app, on older CPUs -
|
|
||||||
tens of ms or more.
|
|
||||||
Since the "Compose" file (almost) never changes using a pre-parsed
|
|
||||||
cache file instead of the "Compose" file is a good idea to improve Qt5
|
|
||||||
application startup time by about 5+ ms (or tens of ms on older CPUs).
|
|
||||||
|
|
||||||
The cache file contains the contents of the QComposeCacheFileHeader struct at the
|
|
||||||
beginning followed by the pre-parsed contents of the "Compose" file.
|
|
||||||
|
|
||||||
struct QComposeCacheFileHeader stores
|
|
||||||
(a) The cache version - in the unlikely event that some day one might need
|
|
||||||
to break compatibility.
|
|
||||||
(b) The (cache) file size.
|
|
||||||
(c) The lastModified field tracks if anything changed since the last time
|
|
||||||
the cache file was saved.
|
|
||||||
If anything did change then we read the compose file and save (cache) it
|
|
||||||
in binary/pre-parsed format, which should happen extremely rarely if at all.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct QComposeCacheFileHeader
|
|
||||||
{
|
|
||||||
quint32 cacheVersion;
|
|
||||||
// The compiler will add 4 padding bytes anyway.
|
|
||||||
// Reserve them explicitly to possibly use in the future.
|
|
||||||
quint32 reserved;
|
|
||||||
quint64 fileSize;
|
|
||||||
qint64 lastModified;
|
|
||||||
};
|
|
||||||
|
|
||||||
// localHostName() copied from qtbase/src/corelib/io/qlockfile_unix.cpp
|
|
||||||
static QByteArray localHostName()
|
|
||||||
{
|
|
||||||
QByteArray hostName(512, Qt::Uninitialized);
|
|
||||||
if (gethostname(hostName.data(), hostName.size()) == -1)
|
|
||||||
return QByteArray();
|
|
||||||
hostName.truncate(strlen(hostName.data()));
|
|
||||||
return hostName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Reads metadata about the Compose file. Later used to determine if the
|
|
||||||
compose cache should be updated. The fileSize field will be zero on failure.
|
|
||||||
*/
|
|
||||||
static QComposeCacheFileHeader readFileMetadata(const QString &path)
|
|
||||||
{
|
|
||||||
quint64 fileSize = 0;
|
|
||||||
qint64 lastModified = 0;
|
|
||||||
const QByteArray pathBytes = QFile::encodeName(path);
|
|
||||||
QT_STATBUF st;
|
|
||||||
if (QT_STAT(pathBytes.data(), &st) == 0) {
|
|
||||||
lastModified = st.st_mtime;
|
|
||||||
fileSize = st.st_size;
|
|
||||||
}
|
|
||||||
QComposeCacheFileHeader info = { 0, 0, fileSize, lastModified };
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const QString getCacheFilePath()
|
|
||||||
{
|
|
||||||
QFile machineIdFile("/var/lib/dbus/machine-id");
|
|
||||||
QString machineId;
|
|
||||||
if (machineIdFile.exists()) {
|
|
||||||
if (machineIdFile.open(QIODevice::ReadOnly))
|
|
||||||
machineId = QString::fromLatin1(machineIdFile.readAll().trimmed());
|
|
||||||
}
|
|
||||||
if (machineId.isEmpty())
|
|
||||||
machineId = localHostName();
|
|
||||||
const QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
|
|
||||||
|
|
||||||
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
|
|
||||||
return dirPath + QLatin1String("/qt_compose_cache_big_endian_") + machineId;
|
|
||||||
return dirPath + QLatin1String("/qt_compose_cache_little_endian_") + machineId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns empty vector on failure
|
|
||||||
static QVector<QComposeTableElement> loadCache(const QComposeCacheFileHeader &composeInfo)
|
|
||||||
{
|
|
||||||
QVector<QComposeTableElement> vec;
|
|
||||||
const QString cacheFilePath = getCacheFilePath();
|
|
||||||
QFile inputFile(cacheFilePath);
|
|
||||||
|
|
||||||
if (!inputFile.open(QIODevice::ReadOnly))
|
|
||||||
return vec;
|
|
||||||
QComposeCacheFileHeader cacheInfo;
|
|
||||||
// use a "buffer" variable to make the line after this one more readable.
|
|
||||||
char *buffer = reinterpret_cast<char*>(&cacheInfo);
|
|
||||||
|
|
||||||
if (inputFile.read(buffer, sizeof cacheInfo) != sizeof cacheInfo)
|
|
||||||
return vec;
|
|
||||||
if (cacheInfo.fileSize == 0)
|
|
||||||
return vec;
|
|
||||||
// using "!=" just in case someone replaced with a backup that existed before
|
|
||||||
if (cacheInfo.lastModified != composeInfo.lastModified)
|
|
||||||
return vec;
|
|
||||||
if (cacheInfo.cacheVersion != SupportedCacheVersion)
|
|
||||||
return vec;
|
|
||||||
const QByteArray pathBytes = QFile::encodeName(cacheFilePath);
|
|
||||||
QT_STATBUF st;
|
|
||||||
if (QT_STAT(pathBytes.data(), &st) != 0)
|
|
||||||
return vec;
|
|
||||||
const off_t fileSize = st.st_size;
|
|
||||||
if (fileSize > 1024 * 1024 * 5) {
|
|
||||||
// The cache file size is usually about 150KB, so if its size is over
|
|
||||||
// say 5MB then somebody inflated the file, abort.
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
const off_t bufferSize = fileSize - (sizeof cacheInfo);
|
|
||||||
const size_t elemSize = sizeof (struct QComposeTableElement);
|
|
||||||
const int elemCount = bufferSize / elemSize;
|
|
||||||
const QByteArray ba = inputFile.read(bufferSize);
|
|
||||||
const char *data = ba.data();
|
|
||||||
// Since we know the number of the (many) elements and their size in
|
|
||||||
// advance calling vector.reserve(..) seems reasonable.
|
|
||||||
vec.reserve(elemCount);
|
|
||||||
|
|
||||||
for (int i = 0; i < elemCount; i++) {
|
|
||||||
const QComposeTableElement *elem =
|
|
||||||
reinterpret_cast<const QComposeTableElement*>(data + (i * elemSize));
|
|
||||||
vec.push_back(*elem);
|
|
||||||
}
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true on success, false otherwise.
|
|
||||||
static bool saveCache(const QComposeCacheFileHeader &info, const QVector<QComposeTableElement> &vec)
|
|
||||||
{
|
|
||||||
const QString filePath = getCacheFilePath();
|
|
||||||
#if QT_CONFIG(temporaryfile)
|
|
||||||
QSaveFile outputFile(filePath);
|
|
||||||
#else
|
|
||||||
QFile outputFile(filePath);
|
|
||||||
#endif
|
|
||||||
if (!outputFile.open(QIODevice::WriteOnly))
|
|
||||||
return false;
|
|
||||||
const char *data = reinterpret_cast<const char*>(&info);
|
|
||||||
|
|
||||||
if (outputFile.write(data, sizeof info) != sizeof info)
|
|
||||||
return false;
|
|
||||||
data = reinterpret_cast<const char*>(vec.constData());
|
|
||||||
const qint64 size = vec.size() * (sizeof (struct QComposeTableElement));
|
|
||||||
|
|
||||||
if (outputFile.write(data, size) != size)
|
|
||||||
return false;
|
|
||||||
#if QT_CONFIG(temporaryfile)
|
|
||||||
return outputFile.commit();
|
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
TableGenerator::TableGenerator() : m_state(NoErrors),
|
|
||||||
m_systemComposeDir(QString())
|
|
||||||
{
|
|
||||||
initPossibleLocations();
|
|
||||||
QString composeFilePath = findComposeFile();
|
|
||||||
#ifdef DEBUG_GENERATOR
|
|
||||||
// don't use cache when in debug mode.
|
|
||||||
if (!composeFilePath.isEmpty())
|
|
||||||
qDebug() << "Using Compose file from: " << composeFilePath;
|
|
||||||
#else
|
|
||||||
QComposeCacheFileHeader fileInfo = readFileMetadata(composeFilePath);
|
|
||||||
if (fileInfo.fileSize != 0)
|
|
||||||
m_composeTable = loadCache(fileInfo);
|
|
||||||
#endif
|
|
||||||
if (m_composeTable.isEmpty() && cleanState()) {
|
|
||||||
if (composeFilePath.isEmpty()) {
|
|
||||||
m_state = MissingComposeFile;
|
|
||||||
} else {
|
|
||||||
QFile composeFile(composeFilePath);
|
|
||||||
composeFile.open(QIODevice::ReadOnly);
|
|
||||||
parseComposeFile(&composeFile);
|
|
||||||
orderComposeTable();
|
|
||||||
if (m_composeTable.isEmpty()) {
|
|
||||||
m_state = EmptyTable;
|
|
||||||
#ifndef DEBUG_GENERATOR
|
|
||||||
// don't save cache when in debug mode
|
|
||||||
} else {
|
|
||||||
fileInfo.cacheVersion = SupportedCacheVersion;
|
|
||||||
saveCache(fileInfo, m_composeTable);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_GENERATOR
|
|
||||||
printComposeTable();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void TableGenerator::initPossibleLocations()
|
|
||||||
{
|
|
||||||
// Compose files come as a part of Xlib library. Xlib doesn't provide
|
|
||||||
// a mechanism how to retrieve the location of these files reliably, since it was
|
|
||||||
// never meant for external software to parse compose tables directly. Best we
|
|
||||||
// can do is to hardcode search paths. To add an extra system path use
|
|
||||||
// the QTCOMPOSE environment variable
|
|
||||||
m_possibleLocations.reserve(7);
|
|
||||||
if (qEnvironmentVariableIsSet("QTCOMPOSE"))
|
|
||||||
m_possibleLocations.append(QString::fromLocal8Bit(qgetenv("QTCOMPOSE")));
|
|
||||||
m_possibleLocations.append(QStringLiteral("/usr/share/X11/locale"));
|
|
||||||
m_possibleLocations.append(QStringLiteral("/usr/local/share/X11/locale"));
|
|
||||||
m_possibleLocations.append(QStringLiteral("/usr/lib/X11/locale"));
|
|
||||||
m_possibleLocations.append(QStringLiteral("/usr/local/lib/X11/locale"));
|
|
||||||
m_possibleLocations.append(QStringLiteral(X11_PREFIX "/share/X11/locale"));
|
|
||||||
m_possibleLocations.append(QStringLiteral(X11_PREFIX "/lib/X11/locale"));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TableGenerator::findComposeFile()
|
|
||||||
{
|
|
||||||
// check if XCOMPOSEFILE points to a Compose file
|
|
||||||
if (qEnvironmentVariableIsSet("XCOMPOSEFILE")) {
|
|
||||||
const QString path = QFile::decodeName(qgetenv("XCOMPOSEFILE"));
|
|
||||||
if (QFile::exists(path))
|
|
||||||
return path;
|
|
||||||
else
|
|
||||||
qWarning("$XCOMPOSEFILE doesn't point to an existing file");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if user’s home directory has a file named .XCompose
|
|
||||||
if (cleanState()) {
|
|
||||||
QString path = qgetenv("HOME") + QLatin1String("/.XCompose");
|
|
||||||
if (QFile::exists(path))
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for the system provided compose files
|
|
||||||
if (cleanState()) {
|
|
||||||
QString table = composeTableForLocale();
|
|
||||||
if (cleanState()) {
|
|
||||||
if (table.isEmpty())
|
|
||||||
// no table mappings for the system's locale in the compose.dir
|
|
||||||
m_state = UnsupportedLocale;
|
|
||||||
else {
|
|
||||||
QString path = QDir(systemComposeDir()).filePath(table);
|
|
||||||
if (QFile::exists(path))
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TableGenerator::composeTableForLocale()
|
|
||||||
{
|
|
||||||
QByteArray loc = locale().toUpper().toUtf8();
|
|
||||||
QString table = readLocaleMappings(loc);
|
|
||||||
if (table.isEmpty())
|
|
||||||
table = readLocaleMappings(readLocaleAliases(loc));
|
|
||||||
return table;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TableGenerator::findSystemComposeDir()
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (int i = 0; i < m_possibleLocations.size(); ++i) {
|
|
||||||
QString path = m_possibleLocations.at(i);
|
|
||||||
if (QFile::exists(path + QLatin1String("/compose.dir"))) {
|
|
||||||
m_systemComposeDir = path;
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
// should we ask to report this in the qt bug tracker?
|
|
||||||
m_state = UnknownSystemComposeDir;
|
|
||||||
qWarning("Qt Warning: Could not find a location of the system's Compose files. "
|
|
||||||
"Consider setting the QTCOMPOSE environment variable.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TableGenerator::systemComposeDir()
|
|
||||||
{
|
|
||||||
if (m_systemComposeDir.isNull()
|
|
||||||
&& !findSystemComposeDir()) {
|
|
||||||
return QLatin1String("$QTCOMPOSE");
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_systemComposeDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TableGenerator::locale() const
|
|
||||||
{
|
|
||||||
char *name = setlocale(LC_CTYPE, (char *)0);
|
|
||||||
return QLatin1String(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TableGenerator::readLocaleMappings(const QByteArray &locale)
|
|
||||||
{
|
|
||||||
QString file;
|
|
||||||
if (locale.isEmpty())
|
|
||||||
return file;
|
|
||||||
|
|
||||||
QFile mappings(systemComposeDir() + QLatin1String("/compose.dir"));
|
|
||||||
if (mappings.open(QIODevice::ReadOnly)) {
|
|
||||||
const int localeNameLength = locale.size();
|
|
||||||
const char * const localeData = locale.constData();
|
|
||||||
|
|
||||||
char l[1024];
|
|
||||||
// formating of compose.dir has some inconsistencies
|
|
||||||
while (!mappings.atEnd()) {
|
|
||||||
int read = mappings.readLine(l, sizeof(l));
|
|
||||||
if (read <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
char *line = l;
|
|
||||||
if (*line >= 'a' && *line <= 'z') {
|
|
||||||
// file name
|
|
||||||
while (*line && *line != ':' && *line != ' ' && *line != '\t')
|
|
||||||
++line;
|
|
||||||
if (!*line)
|
|
||||||
continue;
|
|
||||||
const char * const composeFileNameEnd = line;
|
|
||||||
*line = '\0';
|
|
||||||
++line;
|
|
||||||
|
|
||||||
// locale name
|
|
||||||
while (*line && (*line == ' ' || *line == '\t'))
|
|
||||||
++line;
|
|
||||||
const char * const lc = line;
|
|
||||||
while (*line && *line != ' ' && *line != '\t' && *line != '\n')
|
|
||||||
++line;
|
|
||||||
*line = '\0';
|
|
||||||
if (localeNameLength == (line - lc) && !strncasecmp(lc, localeData, line - lc)) {
|
|
||||||
file = QString::fromLocal8Bit(l, composeFileNameEnd - l);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mappings.close();
|
|
||||||
}
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray TableGenerator::readLocaleAliases(const QByteArray &locale)
|
|
||||||
{
|
|
||||||
QFile aliases(systemComposeDir() + QLatin1String("/locale.alias"));
|
|
||||||
QByteArray fullLocaleName;
|
|
||||||
if (aliases.open(QIODevice::ReadOnly)) {
|
|
||||||
while (!aliases.atEnd()) {
|
|
||||||
char l[1024];
|
|
||||||
int read = aliases.readLine(l, sizeof(l));
|
|
||||||
char *line = l;
|
|
||||||
if (read && ((*line >= 'a' && *line <= 'z') ||
|
|
||||||
(*line >= 'A' && *line <= 'Z'))) {
|
|
||||||
const char *alias = line;
|
|
||||||
while (*line && *line != ':' && *line != ' ' && *line != '\t')
|
|
||||||
++line;
|
|
||||||
if (!*line)
|
|
||||||
continue;
|
|
||||||
*line = 0;
|
|
||||||
if (locale.size() == (line - alias)
|
|
||||||
&& !strncasecmp(alias, locale.constData(), line - alias)) {
|
|
||||||
// found a match for alias, read the real locale name
|
|
||||||
++line;
|
|
||||||
while (*line && (*line == ' ' || *line == '\t'))
|
|
||||||
++line;
|
|
||||||
const char *fullName = line;
|
|
||||||
while (*line && *line != ' ' && *line != '\t' && *line != '\n')
|
|
||||||
++line;
|
|
||||||
*line = 0;
|
|
||||||
fullLocaleName = fullName;
|
|
||||||
#ifdef DEBUG_GENERATOR
|
|
||||||
qDebug() << "Alias for: " << alias << "is: " << fullLocaleName;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
aliases.close();
|
|
||||||
}
|
|
||||||
return fullLocaleName;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TableGenerator::processFile(const QString &composeFileName)
|
|
||||||
{
|
|
||||||
QFile composeFile(composeFileName);
|
|
||||||
if (composeFile.open(QIODevice::ReadOnly)) {
|
|
||||||
parseComposeFile(&composeFile);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
qWarning() << QString(QLatin1String("Qt Warning: Compose file: \"%1\" can't be found"))
|
|
||||||
.arg(composeFile.fileName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
TableGenerator::~TableGenerator()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<QComposeTableElement> TableGenerator::composeTable() const
|
|
||||||
{
|
|
||||||
return m_composeTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TableGenerator::parseComposeFile(QFile *composeFile)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_GENERATOR
|
|
||||||
qDebug() << "TableGenerator::parseComposeFile: " << composeFile->fileName();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char line[1024];
|
|
||||||
while (!composeFile->atEnd()) {
|
|
||||||
composeFile->readLine(line, sizeof(line));
|
|
||||||
if (*line == '<')
|
|
||||||
parseKeySequence(line);
|
|
||||||
else if (!strncmp(line, "include", 7))
|
|
||||||
parseIncludeInstruction(QString::fromLocal8Bit(line));
|
|
||||||
}
|
|
||||||
|
|
||||||
composeFile->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TableGenerator::parseIncludeInstruction(QString line)
|
|
||||||
{
|
|
||||||
// Parse something that looks like:
|
|
||||||
// include "/usr/share/X11/locale/en_US.UTF-8/Compose"
|
|
||||||
QString quote = QStringLiteral("\"");
|
|
||||||
line.remove(0, line.indexOf(quote) + 1);
|
|
||||||
line.chop(line.length() - line.indexOf(quote));
|
|
||||||
|
|
||||||
// expand substitutions if present
|
|
||||||
line.replace(QLatin1String("%H"), QString(qgetenv("HOME")));
|
|
||||||
line.replace(QLatin1String("%L"), systemComposeDir() + QLatin1Char('/') + composeTableForLocale());
|
|
||||||
line.replace(QLatin1String("%S"), systemComposeDir());
|
|
||||||
|
|
||||||
processFile(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
ushort TableGenerator::keysymToUtf8(quint32 sym)
|
|
||||||
{
|
|
||||||
QByteArray chars;
|
|
||||||
int bytes;
|
|
||||||
chars.resize(8);
|
|
||||||
bytes = xkb_keysym_to_utf8(sym, chars.data(), chars.size());
|
|
||||||
if (bytes == -1)
|
|
||||||
qWarning("TableGenerator::keysymToUtf8 - buffer too small");
|
|
||||||
|
|
||||||
chars.resize(bytes-1);
|
|
||||||
|
|
||||||
#ifdef DEBUG_GENERATOR
|
|
||||||
QTextCodec *codec = QTextCodec::codecForLocale();
|
|
||||||
qDebug() << QString("keysym - 0x%1 : utf8 - %2").arg(QString::number(sym, 16))
|
|
||||||
.arg(codec->toUnicode(chars));
|
|
||||||
#endif
|
|
||||||
return QString::fromUtf8(chars).at(0).unicode();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fromBase8(const char *s, const char *end)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
while (*s && s != end) {
|
|
||||||
if (*s < '0' || *s > '7')
|
|
||||||
return 0;
|
|
||||||
result *= 8;
|
|
||||||
result += *s - '0';
|
|
||||||
++s;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fromBase16(const char *s, const char *end)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
while (*s && s != end) {
|
|
||||||
result *= 16;
|
|
||||||
if (*s >= '0' && *s <= '9')
|
|
||||||
result += *s - '0';
|
|
||||||
else if (*s >= 'a' && *s <= 'f')
|
|
||||||
result += *s - 'a' + 10;
|
|
||||||
else if (*s >= 'A' && *s <= 'F')
|
|
||||||
result += *s - 'A' + 10;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
++s;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TableGenerator::parseKeySequence(char *line)
|
|
||||||
{
|
|
||||||
// we are interested in the lines with the following format:
|
|
||||||
// <Multi_key> <numbersign> <S> : "♬" U266c # BEAMED SIXTEENTH NOTE
|
|
||||||
char *keysEnd = strchr(line, ':');
|
|
||||||
if (!keysEnd)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QComposeTableElement elem;
|
|
||||||
// find the composed value - strings may be direct text encoded in the locale
|
|
||||||
// for which the compose file is to be used, or an escaped octal or hexadecimal
|
|
||||||
// character code. Octal codes are specified as "\123" and hexadecimal codes as "\0x123a".
|
|
||||||
char *composeValue = strchr(keysEnd, '"');
|
|
||||||
if (!composeValue)
|
|
||||||
return;
|
|
||||||
++composeValue;
|
|
||||||
|
|
||||||
char *composeValueEnd = strchr(composeValue, '"');
|
|
||||||
if (!composeValueEnd)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if composed value is a quotation mark adjust the end pointer
|
|
||||||
if (composeValueEnd[1] == '"')
|
|
||||||
++composeValueEnd;
|
|
||||||
|
|
||||||
if (*composeValue == '\\' && composeValue[1] >= '0' && composeValue[1] <= '9') {
|
|
||||||
// handle octal and hex code values
|
|
||||||
char detectBase = composeValue[2];
|
|
||||||
if (detectBase == 'x') {
|
|
||||||
// hexadecimal character code
|
|
||||||
elem.value = keysymToUtf8(fromBase16(composeValue + 3, composeValueEnd));
|
|
||||||
} else {
|
|
||||||
// octal character code
|
|
||||||
elem.value = keysymToUtf8(fromBase8(composeValue + 1, composeValueEnd));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// handle direct text encoded in the locale
|
|
||||||
if (*composeValue == '\\')
|
|
||||||
++composeValue;
|
|
||||||
elem.value = QString::fromLocal8Bit(composeValue, composeValueEnd - composeValue).at(0).unicode();
|
|
||||||
++composeValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_GENERATOR
|
|
||||||
// find the comment
|
|
||||||
elem.comment = QString::fromLocal8Bit(composeValueEnd + 1).trimmed();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// find the key sequence and convert to X11 keysym
|
|
||||||
char *k = line;
|
|
||||||
const char *kend = keysEnd;
|
|
||||||
|
|
||||||
for (int i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) {
|
|
||||||
// find the next pair of angle brackets and get the contents within
|
|
||||||
while (k < kend && *k != '<')
|
|
||||||
++k;
|
|
||||||
char *sym = ++k;
|
|
||||||
while (k < kend && *k != '>')
|
|
||||||
++k;
|
|
||||||
*k = '\0';
|
|
||||||
if (k < kend) {
|
|
||||||
elem.keys[i] = xkb_keysym_from_name(sym, (xkb_keysym_flags)0);
|
|
||||||
if (elem.keys[i] == XKB_KEY_NoSymbol) {
|
|
||||||
if (!strcmp(sym, "dead_inverted_breve"))
|
|
||||||
elem.keys[i] = XKB_KEY_dead_invertedbreve;
|
|
||||||
else if (!strcmp(sym, "dead_double_grave"))
|
|
||||||
elem.keys[i] = XKB_KEY_dead_doublegrave;
|
|
||||||
#ifdef DEBUG_GENERATOR
|
|
||||||
else
|
|
||||||
qWarning() << QString("Qt Warning - invalid keysym: %1").arg(sym);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
elem.keys[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_composeTable.append(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TableGenerator::printComposeTable() const
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_GENERATOR
|
|
||||||
# ifndef QT_NO_DEBUG_STREAM
|
|
||||||
if (m_composeTable.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QDebug ds = qDebug() << "output:\n";
|
|
||||||
ds.nospace();
|
|
||||||
const int tableSize = m_composeTable.size();
|
|
||||||
for (int i = 0; i < tableSize; ++i) {
|
|
||||||
const QComposeTableElement &elem = m_composeTable.at(i);
|
|
||||||
ds << "{ {";
|
|
||||||
for (int j = 0; j < QT_KEYSEQUENCE_MAX_LEN; j++) {
|
|
||||||
ds << hex << showbase << elem.keys[j] << ", ";
|
|
||||||
}
|
|
||||||
ds << "}, " << hex << showbase << elem.value << ", \"\" }, // " << elem.comment << " \n";
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void TableGenerator::orderComposeTable()
|
|
||||||
{
|
|
||||||
// Stable-sorting to ensure that the item that appeared before the other in the
|
|
||||||
// original container will still appear first after the sort. This property is
|
|
||||||
// needed to handle the cases when user re-defines already defined key sequence
|
|
||||||
std::stable_sort(m_composeTable.begin(), m_composeTable.end(), ByKeys());
|
|
||||||
}
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2016 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$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QTABLEGENERATOR_H
|
|
||||||
#define QTABLEGENERATOR_H
|
|
||||||
|
|
||||||
#include <QtCore/QVector>
|
|
||||||
#include <QtCore/QFile>
|
|
||||||
#include <QtCore/QMap>
|
|
||||||
#include <QtCore/QString>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
static Q_CONSTEXPR int QT_KEYSEQUENCE_MAX_LEN = 6;
|
|
||||||
|
|
||||||
//#define DEBUG_GENERATOR
|
|
||||||
|
|
||||||
/* Whenever QComposeTableElement gets modified supportedCacheVersion
|
|
||||||
from qtablegenerator.cpp must be bumped. */
|
|
||||||
struct QComposeTableElement {
|
|
||||||
uint keys[QT_KEYSEQUENCE_MAX_LEN];
|
|
||||||
uint value;
|
|
||||||
#ifdef DEBUG_GENERATOR
|
|
||||||
QString comment;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef DEBUG_GENERATOR
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
Q_DECLARE_TYPEINFO(QComposeTableElement, Q_PRIMITIVE_TYPE);
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ByKeys
|
|
||||||
{
|
|
||||||
using uint_array = uint[QT_KEYSEQUENCE_MAX_LEN];
|
|
||||||
using result_type = bool;
|
|
||||||
|
|
||||||
bool operator()(const uint_array &lhs, const uint_array &rhs) const Q_DECL_NOTHROW
|
|
||||||
{
|
|
||||||
return std::lexicographical_compare(lhs, lhs + QT_KEYSEQUENCE_MAX_LEN,
|
|
||||||
rhs, rhs + QT_KEYSEQUENCE_MAX_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(const uint_array &lhs, const QComposeTableElement &rhs) const Q_DECL_NOTHROW
|
|
||||||
{
|
|
||||||
return operator()(lhs, rhs.keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(const QComposeTableElement &lhs, const uint_array &rhs) const Q_DECL_NOTHROW
|
|
||||||
{
|
|
||||||
return operator()(lhs.keys, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(const QComposeTableElement &lhs, const QComposeTableElement &rhs) const Q_DECL_NOTHROW
|
|
||||||
{
|
|
||||||
return operator()(lhs.keys, rhs.keys);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class TableGenerator
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum TableState
|
|
||||||
{
|
|
||||||
UnsupportedLocale,
|
|
||||||
EmptyTable,
|
|
||||||
UnknownSystemComposeDir,
|
|
||||||
MissingComposeFile,
|
|
||||||
NoErrors
|
|
||||||
};
|
|
||||||
|
|
||||||
TableGenerator();
|
|
||||||
~TableGenerator();
|
|
||||||
|
|
||||||
void parseComposeFile(QFile *composeFile);
|
|
||||||
void printComposeTable() const;
|
|
||||||
void orderComposeTable();
|
|
||||||
|
|
||||||
QVector<QComposeTableElement> composeTable() const;
|
|
||||||
TableState tableState() const { return m_state; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool processFile(const QString &composeFileName);
|
|
||||||
void parseKeySequence(char *line);
|
|
||||||
void parseIncludeInstruction(QString line);
|
|
||||||
|
|
||||||
QString findComposeFile();
|
|
||||||
bool findSystemComposeDir();
|
|
||||||
QString systemComposeDir();
|
|
||||||
QString composeTableForLocale();
|
|
||||||
|
|
||||||
ushort keysymToUtf8(quint32 sym);
|
|
||||||
|
|
||||||
QString readLocaleMappings(const QByteArray &locale);
|
|
||||||
QByteArray readLocaleAliases(const QByteArray &locale);
|
|
||||||
void initPossibleLocations();
|
|
||||||
bool cleanState() const { return m_state == NoErrors; }
|
|
||||||
QString locale() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QVector<QComposeTableElement> m_composeTable;
|
|
||||||
TableState m_state;
|
|
||||||
QString m_systemComposeDir;
|
|
||||||
QList<QString> m_possibleLocations;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QTABLEGENERATOR_H
|
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the plugins of the Qt Toolkit.
|
** This file is part of the plugins of the Qt Toolkit.
|
||||||
@ -36,131 +36,100 @@
|
|||||||
** $QT_END_LICENSE$
|
** $QT_END_LICENSE$
|
||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "qcomposeplatforminputcontext.h"
|
#include "qcomposeplatforminputcontext.h"
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtGui/QKeyEvent>
|
#include <QtGui/QKeyEvent>
|
||||||
#include <QtCore/QDebug>
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <locale.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
//#define DEBUG_COMPOSING
|
Q_LOGGING_CATEGORY(lcXkbCompose, "qt.xkb.compose")
|
||||||
|
|
||||||
static const int ignoreKeys[] = {
|
|
||||||
Qt::Key_Shift,
|
|
||||||
Qt::Key_Control,
|
|
||||||
Qt::Key_Meta,
|
|
||||||
Qt::Key_Alt,
|
|
||||||
Qt::Key_CapsLock,
|
|
||||||
Qt::Key_Super_L,
|
|
||||||
Qt::Key_Super_R,
|
|
||||||
Qt::Key_Hyper_L,
|
|
||||||
Qt::Key_Hyper_R,
|
|
||||||
Qt::Key_Mode_switch
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int composingKeys[] = {
|
|
||||||
Qt::Key_Multi_key,
|
|
||||||
Qt::Key_Dead_Grave,
|
|
||||||
Qt::Key_Dead_Acute,
|
|
||||||
Qt::Key_Dead_Circumflex,
|
|
||||||
Qt::Key_Dead_Tilde,
|
|
||||||
Qt::Key_Dead_Macron,
|
|
||||||
Qt::Key_Dead_Breve,
|
|
||||||
Qt::Key_Dead_Abovedot,
|
|
||||||
Qt::Key_Dead_Diaeresis,
|
|
||||||
Qt::Key_Dead_Abovering,
|
|
||||||
Qt::Key_Dead_Doubleacute,
|
|
||||||
Qt::Key_Dead_Caron,
|
|
||||||
Qt::Key_Dead_Cedilla,
|
|
||||||
Qt::Key_Dead_Ogonek,
|
|
||||||
Qt::Key_Dead_Iota,
|
|
||||||
Qt::Key_Dead_Voiced_Sound,
|
|
||||||
Qt::Key_Dead_Semivoiced_Sound,
|
|
||||||
Qt::Key_Dead_Belowdot,
|
|
||||||
Qt::Key_Dead_Hook,
|
|
||||||
Qt::Key_Dead_Horn,
|
|
||||||
Qt::Key_Dead_Stroke,
|
|
||||||
Qt::Key_Dead_Abovecomma,
|
|
||||||
Qt::Key_Dead_Abovereversedcomma,
|
|
||||||
Qt::Key_Dead_Doublegrave,
|
|
||||||
Qt::Key_Dead_Belowring,
|
|
||||||
Qt::Key_Dead_Belowmacron,
|
|
||||||
Qt::Key_Dead_Belowcircumflex,
|
|
||||||
Qt::Key_Dead_Belowtilde,
|
|
||||||
Qt::Key_Dead_Belowbreve,
|
|
||||||
Qt::Key_Dead_Belowdiaeresis,
|
|
||||||
Qt::Key_Dead_Invertedbreve,
|
|
||||||
Qt::Key_Dead_Belowcomma,
|
|
||||||
Qt::Key_Dead_Currency,
|
|
||||||
Qt::Key_Dead_a,
|
|
||||||
Qt::Key_Dead_A,
|
|
||||||
Qt::Key_Dead_e,
|
|
||||||
Qt::Key_Dead_E,
|
|
||||||
Qt::Key_Dead_i,
|
|
||||||
Qt::Key_Dead_I,
|
|
||||||
Qt::Key_Dead_o,
|
|
||||||
Qt::Key_Dead_O,
|
|
||||||
Qt::Key_Dead_u,
|
|
||||||
Qt::Key_Dead_U,
|
|
||||||
Qt::Key_Dead_Small_Schwa,
|
|
||||||
Qt::Key_Dead_Capital_Schwa,
|
|
||||||
Qt::Key_Dead_Greek,
|
|
||||||
Qt::Key_Dead_Lowline,
|
|
||||||
Qt::Key_Dead_Aboveverticalline,
|
|
||||||
Qt::Key_Dead_Belowverticalline,
|
|
||||||
Qt::Key_Dead_Longsolidusoverlay
|
|
||||||
};
|
|
||||||
|
|
||||||
QComposeInputContext::QComposeInputContext()
|
QComposeInputContext::QComposeInputContext()
|
||||||
: m_tableState(TableGenerator::EmptyTable)
|
|
||||||
, m_compositionTableInitialized(false)
|
|
||||||
{
|
{
|
||||||
clearComposeBuffer();
|
setObjectName(QStringLiteral("QComposeInputContext"));
|
||||||
|
qCDebug(lcXkbCompose, "using xkb compose input context");
|
||||||
|
}
|
||||||
|
|
||||||
|
QComposeInputContext::~QComposeInputContext()
|
||||||
|
{
|
||||||
|
xkb_compose_state_unref(m_composeState);
|
||||||
|
xkb_compose_table_unref(m_composeTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QComposeInputContext::ensureInitialized()
|
||||||
|
{
|
||||||
|
if (m_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_XkbContext) {
|
||||||
|
qCWarning(lcXkbCompose) << "error: xkb context has not been set on" << metaObject()->className();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_initialized = true;
|
||||||
|
const char *const locale = setlocale(LC_CTYPE, "");
|
||||||
|
qCDebug(lcXkbCompose) << "detected locale (LC_CTYPE):" << locale;
|
||||||
|
|
||||||
|
m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||||
|
if (m_composeTable)
|
||||||
|
m_composeState = xkb_compose_state_new(m_composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||||
|
|
||||||
|
if (!m_composeTable) {
|
||||||
|
qCWarning(lcXkbCompose, "failed to create compose table");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!m_composeState) {
|
||||||
|
qCWarning(lcXkbCompose, "failed to create compose state");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QComposeInputContext::filterEvent(const QEvent *event)
|
bool QComposeInputContext::filterEvent(const QEvent *event)
|
||||||
{
|
{
|
||||||
const QKeyEvent *keyEvent = (const QKeyEvent *)event;
|
auto keyEvent = static_cast<const QKeyEvent *>(event);
|
||||||
// should pass only the key presses
|
if (keyEvent->type() != QEvent::KeyPress)
|
||||||
if (keyEvent->type() != QEvent::KeyPress) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there were errors when generating the compose table input
|
|
||||||
// context should not try to filter anything, simply return false
|
|
||||||
if (m_compositionTableInitialized && (m_tableState & TableGenerator::NoErrors) != TableGenerator::NoErrors)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int keyval = keyEvent->key();
|
if (!inputMethodAccepted())
|
||||||
int keysym = 0;
|
|
||||||
|
|
||||||
if (ignoreKey(keyval))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!composeKey(keyval) && keyEvent->text().isEmpty())
|
// lazy initialization - we don't want to do this on an app startup
|
||||||
|
ensureInitialized();
|
||||||
|
|
||||||
|
if (!m_composeTable || !m_composeState)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
keysym = keyEvent->nativeVirtualKey();
|
xkb_compose_state_feed(m_composeState, keyEvent->nativeVirtualKey());
|
||||||
|
|
||||||
int nCompose = 0;
|
switch (xkb_compose_state_get_status(m_composeState)) {
|
||||||
while (nCompose < QT_KEYSEQUENCE_MAX_LEN && m_composeBuffer[nCompose] != 0)
|
case XKB_COMPOSE_COMPOSING:
|
||||||
nCompose++;
|
|
||||||
|
|
||||||
if (nCompose == QT_KEYSEQUENCE_MAX_LEN) {
|
|
||||||
reset();
|
|
||||||
nCompose = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_composeBuffer[nCompose] = keysym;
|
|
||||||
// check sequence
|
|
||||||
if (checkComposeTable())
|
|
||||||
return true;
|
return true;
|
||||||
|
case XKB_COMPOSE_CANCELLED:
|
||||||
|
reset();
|
||||||
|
return false;
|
||||||
|
case XKB_COMPOSE_COMPOSED:
|
||||||
|
{
|
||||||
|
const int size = xkb_compose_state_get_utf8(m_composeState, nullptr, 0);
|
||||||
|
QVarLengthArray<char, 32> buffer(size + 1);
|
||||||
|
xkb_compose_state_get_utf8(m_composeState, buffer.data(), buffer.size());
|
||||||
|
QString composedText = QString::fromUtf8(buffer.constData());
|
||||||
|
|
||||||
return false;
|
QInputMethodEvent event;
|
||||||
|
event.setCommitString(composedText);
|
||||||
|
QCoreApplication::sendEvent(m_focusObject, &event);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case XKB_COMPOSE_NOTHING:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QComposeInputContext::isValid() const
|
bool QComposeInputContext::isValid() const
|
||||||
@ -175,7 +144,8 @@ void QComposeInputContext::setFocusObject(QObject *object)
|
|||||||
|
|
||||||
void QComposeInputContext::reset()
|
void QComposeInputContext::reset()
|
||||||
{
|
{
|
||||||
clearComposeBuffer();
|
if (m_composeState)
|
||||||
|
xkb_compose_state_reset(m_composeState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QComposeInputContext::update(Qt::InputMethodQueries q)
|
void QComposeInputContext::update(Qt::InputMethodQueries q)
|
||||||
@ -183,125 +153,4 @@ void QComposeInputContext::update(Qt::InputMethodQueries q)
|
|||||||
QPlatformInputContext::update(q);
|
QPlatformInputContext::update(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isDuplicate(const QComposeTableElement &lhs, const QComposeTableElement &rhs)
|
|
||||||
{
|
|
||||||
return std::equal(lhs.keys, lhs.keys + QT_KEYSEQUENCE_MAX_LEN,
|
|
||||||
QT_MAKE_CHECKED_ARRAY_ITERATOR(rhs.keys, QT_KEYSEQUENCE_MAX_LEN));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QComposeInputContext::checkComposeTable()
|
|
||||||
{
|
|
||||||
if (!m_compositionTableInitialized) {
|
|
||||||
TableGenerator reader;
|
|
||||||
m_tableState = reader.tableState();
|
|
||||||
|
|
||||||
m_compositionTableInitialized = true;
|
|
||||||
if ((m_tableState & TableGenerator::NoErrors) == TableGenerator::NoErrors) {
|
|
||||||
m_composeTable = reader.composeTable();
|
|
||||||
} else {
|
|
||||||
#ifdef DEBUG_COMPOSING
|
|
||||||
qDebug( "### FAILED_PARSING ###" );
|
|
||||||
#endif
|
|
||||||
// if we have errors, don' try to look things up anyways.
|
|
||||||
reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Q_ASSERT(!m_composeTable.isEmpty());
|
|
||||||
QVector<QComposeTableElement>::const_iterator it =
|
|
||||||
std::lower_bound(m_composeTable.constBegin(), m_composeTable.constEnd(), m_composeBuffer, ByKeys());
|
|
||||||
|
|
||||||
// prevent dereferencing an 'end' iterator, which would result in a crash
|
|
||||||
if (it == m_composeTable.constEnd())
|
|
||||||
it -= 1;
|
|
||||||
|
|
||||||
QComposeTableElement elem = *it;
|
|
||||||
// would be nicer if qLowerBound had API that tells if the item was actually found
|
|
||||||
if (m_composeBuffer[0] != elem.keys[0]) {
|
|
||||||
#ifdef DEBUG_COMPOSING
|
|
||||||
qDebug( "### no match ###" );
|
|
||||||
#endif
|
|
||||||
reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// check if compose buffer is matched
|
|
||||||
for (int i=0; i < QT_KEYSEQUENCE_MAX_LEN; i++) {
|
|
||||||
|
|
||||||
// check if partial match
|
|
||||||
if (m_composeBuffer[i] == 0 && elem.keys[i]) {
|
|
||||||
#ifdef DEBUG_COMPOSING
|
|
||||||
qDebug("### partial match ###");
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_composeBuffer[i] != elem.keys[i]) {
|
|
||||||
#ifdef DEBUG_COMPOSING
|
|
||||||
qDebug("### different entry ###");
|
|
||||||
#endif
|
|
||||||
reset();
|
|
||||||
return i != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_COMPOSING
|
|
||||||
qDebug("### match exactly ###");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// check if the key sequence is overwriten - see the comment in
|
|
||||||
// TableGenerator::orderComposeTable()
|
|
||||||
int next = 1;
|
|
||||||
do {
|
|
||||||
// if we are at the end of the table, then we have nothing to do here
|
|
||||||
if (it + next != m_composeTable.constEnd()) {
|
|
||||||
QComposeTableElement nextElem = *(it + next);
|
|
||||||
if (isDuplicate(elem, nextElem)) {
|
|
||||||
elem = nextElem;
|
|
||||||
next++;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} while (true);
|
|
||||||
|
|
||||||
commitText(elem.value);
|
|
||||||
reset();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QComposeInputContext::commitText(uint character) const
|
|
||||||
{
|
|
||||||
QInputMethodEvent event;
|
|
||||||
event.setCommitString(QChar(character));
|
|
||||||
QCoreApplication::sendEvent(m_focusObject, &event);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QComposeInputContext::ignoreKey(int keyval) const
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < (sizeof(ignoreKeys) / sizeof(ignoreKeys[0])); i++)
|
|
||||||
if (keyval == ignoreKeys[i])
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QComposeInputContext::composeKey(int keyval) const
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < (sizeof(composingKeys) / sizeof(composingKeys[0])); i++)
|
|
||||||
if (keyval == composingKeys[i])
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QComposeInputContext::clearComposeBuffer()
|
|
||||||
{
|
|
||||||
for (uint i=0; i < (sizeof(m_composeBuffer) / sizeof(int)); i++)
|
|
||||||
m_composeBuffer[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QComposeInputContext::~QComposeInputContext() {}
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the plugins of the Qt Toolkit.
|
** This file is part of the plugins of the Qt Toolkit.
|
||||||
@ -36,24 +36,24 @@
|
|||||||
** $QT_END_LICENSE$
|
** $QT_END_LICENSE$
|
||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef QCOMPOSEPLATFORMINPUTCONTEXT_H
|
#ifndef QCOMPOSEPLATFORMINPUTCONTEXT_H
|
||||||
#define QCOMPOSEPLATFORMINPUTCONTEXT_H
|
#define QCOMPOSEPLATFORMINPUTCONTEXT_H
|
||||||
|
|
||||||
|
#include <QtCore/QLoggingCategory>
|
||||||
|
|
||||||
#include <qpa/qplatforminputcontext.h>
|
#include <qpa/qplatforminputcontext.h>
|
||||||
|
|
||||||
#include <QtCore/QList>
|
#include <xkbcommon/xkbcommon-compose.h>
|
||||||
|
|
||||||
#include "generator/qtablegenerator.h"
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(lcXkbCompose)
|
||||||
|
|
||||||
class QEvent;
|
class QEvent;
|
||||||
|
|
||||||
class QComposeInputContext : public QPlatformInputContext
|
class QComposeInputContext : public QPlatformInputContext
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QComposeInputContext();
|
QComposeInputContext();
|
||||||
~QComposeInputContext();
|
~QComposeInputContext();
|
||||||
@ -62,21 +62,22 @@ public:
|
|||||||
void setFocusObject(QObject *object) override;
|
void setFocusObject(QObject *object) override;
|
||||||
void reset() override;
|
void reset() override;
|
||||||
void update(Qt::InputMethodQueries) override;
|
void update(Qt::InputMethodQueries) override;
|
||||||
|
|
||||||
bool filterEvent(const QEvent *event) override;
|
bool filterEvent(const QEvent *event) override;
|
||||||
|
|
||||||
|
// This invokable is called from QXkbCommon::setXkbContext().
|
||||||
|
Q_INVOKABLE void setXkbContext(struct xkb_context *context) { m_XkbContext = context; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void clearComposeBuffer();
|
void ensureInitialized();
|
||||||
bool ignoreKey(int keyval) const;
|
|
||||||
bool composeKey(int keyval) const;
|
|
||||||
bool checkComposeTable();
|
|
||||||
void commitText(uint character) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QObject *m_focusObject;
|
bool m_initialized = false;
|
||||||
QVector<QComposeTableElement> m_composeTable;
|
xkb_context *m_context = nullptr;
|
||||||
uint m_composeBuffer[QT_KEYSEQUENCE_MAX_LEN];
|
xkb_compose_table *m_composeTable = nullptr;
|
||||||
TableGenerator::TableState m_tableState;
|
xkb_compose_state *m_composeState = nullptr;
|
||||||
bool m_compositionTableInitialized;
|
QObject *m_focusObject = nullptr;
|
||||||
|
struct xkb_context *m_XkbContext = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the plugins of the Qt Toolkit.
|
** This file is part of the plugins of the Qt Toolkit.
|
||||||
@ -61,7 +61,7 @@ QComposeInputContext *QComposePlatformInputContextPlugin::create(const QString &
|
|||||||
if (system.compare(system, QLatin1String("compose"), Qt::CaseInsensitive) == 0
|
if (system.compare(system, QLatin1String("compose"), Qt::CaseInsensitive) == 0
|
||||||
|| system.compare(system, QLatin1String("xim"), Qt::CaseInsensitive) == 0)
|
|| system.compare(system, QLatin1String("xim"), Qt::CaseInsensitive) == 0)
|
||||||
return new QComposeInputContext;
|
return new QComposeInputContext;
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -565,10 +565,15 @@ static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/)
|
|||||||
static void terminateQt(JNIEnv *env, jclass /*clazz*/)
|
static void terminateQt(JNIEnv *env, jclass /*clazz*/)
|
||||||
{
|
{
|
||||||
// QAndroidEventDispatcherStopper is stopped when the user uses the task manager to kill the application
|
// QAndroidEventDispatcherStopper is stopped when the user uses the task manager to kill the application
|
||||||
if (!QAndroidEventDispatcherStopper::instance()->stopped()) {
|
if (QAndroidEventDispatcherStopper::instance()->stopped()) {
|
||||||
sem_wait(&m_terminateSemaphore);
|
QAndroidEventDispatcherStopper::instance()->startAll();
|
||||||
sem_destroy(&m_terminateSemaphore);
|
QCoreApplication::quit();
|
||||||
|
QAndroidEventDispatcherStopper::instance()->goingToStop(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sem_wait(&m_terminateSemaphore);
|
||||||
|
sem_destroy(&m_terminateSemaphore);
|
||||||
|
|
||||||
env->DeleteGlobalRef(m_applicationClass);
|
env->DeleteGlobalRef(m_applicationClass);
|
||||||
env->DeleteGlobalRef(m_classLoaderObject);
|
env->DeleteGlobalRef(m_classLoaderObject);
|
||||||
if (m_resourcesObj)
|
if (m_resourcesObj)
|
||||||
@ -588,10 +593,7 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/)
|
|||||||
m_androidPlatformIntegration = nullptr;
|
m_androidPlatformIntegration = nullptr;
|
||||||
delete m_androidAssetsFileEngineHandler;
|
delete m_androidAssetsFileEngineHandler;
|
||||||
m_androidAssetsFileEngineHandler = nullptr;
|
m_androidAssetsFileEngineHandler = nullptr;
|
||||||
|
sem_post(&m_exitSemaphore);
|
||||||
if (!QAndroidEventDispatcherStopper::instance()->stopped()) {
|
|
||||||
sem_post(&m_exitSemaphore);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h)
|
static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h)
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
#include <QSurfaceFormat>
|
#include <QSurfaceFormat>
|
||||||
#include <QtGui/private/qwindow_p.h>
|
#include <QtGui/private/qwindow_p.h>
|
||||||
|
#include <QtGui/qguiapplication.h>
|
||||||
|
|
||||||
#include <qpa/qwindowsysteminterface.h>
|
#include <qpa/qwindowsysteminterface.h>
|
||||||
#include <qpa/qplatformscreen.h>
|
#include <qpa/qplatformscreen.h>
|
||||||
@ -121,7 +122,7 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
|
|||||||
|
|
||||||
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
|
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
|
||||||
{
|
{
|
||||||
if (QAndroidEventDispatcherStopper::stopped())
|
if (QAndroidEventDispatcherStopper::stopped() || QGuiApplication::applicationState() == Qt::ApplicationSuspended)
|
||||||
return m_eglSurface;
|
return m_eglSurface;
|
||||||
|
|
||||||
QMutexLocker lock(&m_surfaceMutex);
|
QMutexLocker lock(&m_surfaceMutex);
|
||||||
|
@ -357,6 +357,8 @@ void QXcbIntegration::initialize()
|
|||||||
m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
|
m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
|
||||||
if (!m_inputContext && icStr != defaultInputContext && icStr != QLatin1String("none"))
|
if (!m_inputContext && icStr != defaultInputContext && icStr != QLatin1String("none"))
|
||||||
m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
|
m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
|
||||||
|
|
||||||
|
defaultConnection()->keyboard()->initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QXcbIntegration::moveToScreen(QWindow *window, int screen)
|
void QXcbIntegration::moveToScreen(QWindow *window, int screen)
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
#include "qxcbkeyboard.h"
|
#include "qxcbkeyboard.h"
|
||||||
#include "qxcbwindow.h"
|
#include "qxcbwindow.h"
|
||||||
#include "qxcbscreen.h"
|
#include "qxcbscreen.h"
|
||||||
#include "qxcbxkbcommon.h"
|
|
||||||
|
|
||||||
#include <qpa/qwindowsysteminterface.h>
|
#include <qpa/qwindowsysteminterface.h>
|
||||||
#include <qpa/qplatforminputcontext.h>
|
#include <qpa/qplatforminputcontext.h>
|
||||||
@ -49,404 +48,20 @@
|
|||||||
#include <QtCore/QMetaEnum>
|
#include <QtCore/QMetaEnum>
|
||||||
|
|
||||||
#include <private/qguiapplication_p.h>
|
#include <private/qguiapplication_p.h>
|
||||||
#include <private/qmakearray_p.h>
|
|
||||||
|
|
||||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
#if QT_CONFIG(xkb)
|
||||||
|
#include <xkbcommon/xkbcommon-x11.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if QT_CONFIG(xcb_xinput)
|
#if QT_CONFIG(xcb_xinput)
|
||||||
#include <xcb/xinput.h>
|
#include <xcb/xinput.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
typedef struct xkb2qt
|
|
||||||
{
|
|
||||||
unsigned int xkb;
|
|
||||||
unsigned int qt;
|
|
||||||
|
|
||||||
constexpr bool operator <=(const xkb2qt &that) const noexcept
|
|
||||||
{
|
|
||||||
return xkb <= that.xkb;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator <(const xkb2qt &that) const noexcept
|
|
||||||
{
|
|
||||||
return xkb < that.xkb;
|
|
||||||
}
|
|
||||||
} xkb2qt_t;
|
|
||||||
|
|
||||||
template<std::size_t Xkb, std::size_t Qt>
|
|
||||||
struct Xkb2Qt
|
|
||||||
{
|
|
||||||
using Type = xkb2qt_t;
|
|
||||||
static constexpr Type data() noexcept { return Type{Xkb, Qt}; }
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr const auto KeyTbl = qMakeArray(
|
|
||||||
QSortedData<
|
|
||||||
// misc keys
|
|
||||||
|
|
||||||
Xkb2Qt<XKB_KEY_Escape, Qt::Key_Escape>,
|
|
||||||
Xkb2Qt<XKB_KEY_Tab, Qt::Key_Tab>,
|
|
||||||
Xkb2Qt<XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab>,
|
|
||||||
Xkb2Qt<XKB_KEY_BackSpace, Qt::Key_Backspace>,
|
|
||||||
Xkb2Qt<XKB_KEY_Return, Qt::Key_Return>,
|
|
||||||
Xkb2Qt<XKB_KEY_Insert, Qt::Key_Insert>,
|
|
||||||
Xkb2Qt<XKB_KEY_Delete, Qt::Key_Delete>,
|
|
||||||
Xkb2Qt<XKB_KEY_Clear, Qt::Key_Delete>,
|
|
||||||
Xkb2Qt<XKB_KEY_Pause, Qt::Key_Pause>,
|
|
||||||
Xkb2Qt<XKB_KEY_Print, Qt::Key_Print>,
|
|
||||||
Xkb2Qt<0x1005FF60, Qt::Key_SysReq>, // hardcoded Sun SysReq
|
|
||||||
Xkb2Qt<0x1007ff00, Qt::Key_SysReq>, // hardcoded X386 SysReq
|
|
||||||
|
|
||||||
// cursor movement
|
|
||||||
|
|
||||||
Xkb2Qt<XKB_KEY_Home, Qt::Key_Home>,
|
|
||||||
Xkb2Qt<XKB_KEY_End, Qt::Key_End>,
|
|
||||||
Xkb2Qt<XKB_KEY_Left, Qt::Key_Left>,
|
|
||||||
Xkb2Qt<XKB_KEY_Up, Qt::Key_Up>,
|
|
||||||
Xkb2Qt<XKB_KEY_Right, Qt::Key_Right>,
|
|
||||||
Xkb2Qt<XKB_KEY_Down, Qt::Key_Down>,
|
|
||||||
Xkb2Qt<XKB_KEY_Prior, Qt::Key_PageUp>,
|
|
||||||
Xkb2Qt<XKB_KEY_Next, Qt::Key_PageDown>,
|
|
||||||
|
|
||||||
// modifiers
|
|
||||||
|
|
||||||
Xkb2Qt<XKB_KEY_Shift_L, Qt::Key_Shift>,
|
|
||||||
Xkb2Qt<XKB_KEY_Shift_R, Qt::Key_Shift>,
|
|
||||||
Xkb2Qt<XKB_KEY_Shift_Lock, Qt::Key_Shift>,
|
|
||||||
Xkb2Qt<XKB_KEY_Control_L, Qt::Key_Control>,
|
|
||||||
Xkb2Qt<XKB_KEY_Control_R, Qt::Key_Control>,
|
|
||||||
Xkb2Qt<XKB_KEY_Meta_L, Qt::Key_Meta>,
|
|
||||||
Xkb2Qt<XKB_KEY_Meta_R, Qt::Key_Meta>,
|
|
||||||
Xkb2Qt<XKB_KEY_Alt_L, Qt::Key_Alt>,
|
|
||||||
Xkb2Qt<XKB_KEY_Alt_R, Qt::Key_Alt>,
|
|
||||||
Xkb2Qt<XKB_KEY_Caps_Lock, Qt::Key_CapsLock>,
|
|
||||||
Xkb2Qt<XKB_KEY_Num_Lock, Qt::Key_NumLock>,
|
|
||||||
Xkb2Qt<XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock>,
|
|
||||||
Xkb2Qt<XKB_KEY_Super_L, Qt::Key_Super_L>,
|
|
||||||
Xkb2Qt<XKB_KEY_Super_R, Qt::Key_Super_R>,
|
|
||||||
Xkb2Qt<XKB_KEY_Menu, Qt::Key_Menu>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hyper_L, Qt::Key_Hyper_L>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hyper_R, Qt::Key_Hyper_R>,
|
|
||||||
Xkb2Qt<XKB_KEY_Help, Qt::Key_Help>,
|
|
||||||
Xkb2Qt<0x1000FF74, Qt::Key_Backtab>, // hardcoded HP backtab
|
|
||||||
Xkb2Qt<0x1005FF10, Qt::Key_F11>, // hardcoded Sun F36 (labeled F11)
|
|
||||||
Xkb2Qt<0x1005FF11, Qt::Key_F12>, // hardcoded Sun F37 (labeled F12)
|
|
||||||
|
|
||||||
// numeric and function keypad keys
|
|
||||||
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Space, Qt::Key_Space>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Tab, Qt::Key_Tab>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Enter, Qt::Key_Enter>,
|
|
||||||
//Xkb2Qt<XKB_KEY_KP_F1, Qt::Key_F1>,
|
|
||||||
//Xkb2Qt<XKB_KEY_KP_F2, Qt::Key_F2>,
|
|
||||||
//Xkb2Qt<XKB_KEY_KP_F3, Qt::Key_F3>,
|
|
||||||
//Xkb2Qt<XKB_KEY_KP_F4, Qt::Key_F4>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Home, Qt::Key_Home>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Left, Qt::Key_Left>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Up, Qt::Key_Up>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Right, Qt::Key_Right>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Down, Qt::Key_Down>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Prior, Qt::Key_PageUp>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Next, Qt::Key_PageDown>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_End, Qt::Key_End>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Begin, Qt::Key_Clear>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Insert, Qt::Key_Insert>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Delete, Qt::Key_Delete>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Equal, Qt::Key_Equal>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Multiply, Qt::Key_Asterisk>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Add, Qt::Key_Plus>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Separator, Qt::Key_Comma>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Subtract, Qt::Key_Minus>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Decimal, Qt::Key_Period>,
|
|
||||||
Xkb2Qt<XKB_KEY_KP_Divide, Qt::Key_Slash>,
|
|
||||||
|
|
||||||
// special non-XF86 function keys
|
|
||||||
|
|
||||||
Xkb2Qt<XKB_KEY_Undo, Qt::Key_Undo>,
|
|
||||||
Xkb2Qt<XKB_KEY_Redo, Qt::Key_Redo>,
|
|
||||||
Xkb2Qt<XKB_KEY_Find, Qt::Key_Find>,
|
|
||||||
Xkb2Qt<XKB_KEY_Cancel, Qt::Key_Cancel>,
|
|
||||||
|
|
||||||
// International input method support keys
|
|
||||||
|
|
||||||
// International & multi-key character composition
|
|
||||||
Xkb2Qt<XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr>,
|
|
||||||
Xkb2Qt<XKB_KEY_Multi_key, Qt::Key_Multi_key>,
|
|
||||||
Xkb2Qt<XKB_KEY_Codeinput, Qt::Key_Codeinput>,
|
|
||||||
Xkb2Qt<XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate>,
|
|
||||||
Xkb2Qt<XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate>,
|
|
||||||
Xkb2Qt<XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate>,
|
|
||||||
|
|
||||||
// Misc Functions
|
|
||||||
Xkb2Qt<XKB_KEY_Mode_switch, Qt::Key_Mode_switch>,
|
|
||||||
Xkb2Qt<XKB_KEY_script_switch, Qt::Key_Mode_switch>,
|
|
||||||
|
|
||||||
// Japanese keyboard support
|
|
||||||
Xkb2Qt<XKB_KEY_Kanji, Qt::Key_Kanji>,
|
|
||||||
Xkb2Qt<XKB_KEY_Muhenkan, Qt::Key_Muhenkan>,
|
|
||||||
//Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan_Mode>,
|
|
||||||
Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan>,
|
|
||||||
Xkb2Qt<XKB_KEY_Henkan, Qt::Key_Henkan>,
|
|
||||||
Xkb2Qt<XKB_KEY_Romaji, Qt::Key_Romaji>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hiragana, Qt::Key_Hiragana>,
|
|
||||||
Xkb2Qt<XKB_KEY_Katakana, Qt::Key_Katakana>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hiragana_Katakana, Qt::Key_Hiragana_Katakana>,
|
|
||||||
Xkb2Qt<XKB_KEY_Zenkaku, Qt::Key_Zenkaku>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hankaku, Qt::Key_Hankaku>,
|
|
||||||
Xkb2Qt<XKB_KEY_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku>,
|
|
||||||
Xkb2Qt<XKB_KEY_Touroku, Qt::Key_Touroku>,
|
|
||||||
Xkb2Qt<XKB_KEY_Massyo, Qt::Key_Massyo>,
|
|
||||||
Xkb2Qt<XKB_KEY_Kana_Lock, Qt::Key_Kana_Lock>,
|
|
||||||
Xkb2Qt<XKB_KEY_Kana_Shift, Qt::Key_Kana_Shift>,
|
|
||||||
Xkb2Qt<XKB_KEY_Eisu_Shift, Qt::Key_Eisu_Shift>,
|
|
||||||
Xkb2Qt<XKB_KEY_Eisu_toggle, Qt::Key_Eisu_toggle>,
|
|
||||||
//Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Kanji_Bangou>,
|
|
||||||
//Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_Zen_Koho>,
|
|
||||||
//Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_Mae_Koho>,
|
|
||||||
Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Codeinput>,
|
|
||||||
Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_MultipleCandidate>,
|
|
||||||
Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_PreviousCandidate>,
|
|
||||||
|
|
||||||
// Korean keyboard support
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul, Qt::Key_Hangul>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_Start, Qt::Key_Hangul_Start>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_End, Qt::Key_Hangul_End>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_Hanja, Qt::Key_Hangul_Hanja>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_Jamo, Qt::Key_Hangul_Jamo>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_Romaja, Qt::Key_Hangul_Romaja>,
|
|
||||||
//Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Hangul_Codeinput>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Codeinput>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_Jeonja, Qt::Key_Hangul_Jeonja>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_Banja, Qt::Key_Hangul_Banja>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_PreHanja, Qt::Key_Hangul_PreHanja>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_PostHanja, Qt::Key_Hangul_PostHanja>,
|
|
||||||
//Xkb2Qt<XKB_KEY_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate>,
|
|
||||||
//Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate>,
|
|
||||||
//Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_SingleCandidate, Qt::Key_SingleCandidate>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_Special, Qt::Key_Hangul_Special>,
|
|
||||||
//Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Hangul_switch>,
|
|
||||||
Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Mode_switch>,
|
|
||||||
|
|
||||||
// dead keys
|
|
||||||
Xkb2Qt<XKB_KEY_dead_grave, Qt::Key_Dead_Grave>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_acute, Qt::Key_Dead_Acute>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_macron, Qt::Key_Dead_Macron>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_breve, Qt::Key_Dead_Breve>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_caron, Qt::Key_Dead_Caron>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_iota, Qt::Key_Dead_Iota>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_hook, Qt::Key_Dead_Hook>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_horn, Qt::Key_Dead_Horn>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_stroke, Qt::Key_Dead_Stroke>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_abovecomma, Qt::Key_Dead_Abovecomma>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_abovereversedcomma, Qt::Key_Dead_Abovereversedcomma>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_doublegrave, Qt::Key_Dead_Doublegrave>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_belowring, Qt::Key_Dead_Belowring>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_belowmacron, Qt::Key_Dead_Belowmacron>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_belowcircumflex, Qt::Key_Dead_Belowcircumflex>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_belowtilde, Qt::Key_Dead_Belowtilde>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_belowbreve, Qt::Key_Dead_Belowbreve>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_belowdiaeresis, Qt::Key_Dead_Belowdiaeresis>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_invertedbreve, Qt::Key_Dead_Invertedbreve>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_belowcomma, Qt::Key_Dead_Belowcomma>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_currency, Qt::Key_Dead_Currency>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_a, Qt::Key_Dead_a>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_A, Qt::Key_Dead_A>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_e, Qt::Key_Dead_e>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_E, Qt::Key_Dead_E>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_i, Qt::Key_Dead_i>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_I, Qt::Key_Dead_I>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_o, Qt::Key_Dead_o>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_O, Qt::Key_Dead_O>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_u, Qt::Key_Dead_u>,
|
|
||||||
Xkb2Qt<XKB_KEY_dead_U, Qt::Key_Dead_U>,
|
|
||||||
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>,
|
|
||||||
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>,
|
|
||||||
|
|
||||||
// Special keys from X.org - This include multimedia keys,
|
|
||||||
// wireless/bluetooth/uwb keys, special launcher keys, etc.
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Back, Qt::Key_Back>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Forward, Qt::Key_Forward>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Stop, Qt::Key_Stop>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Refresh, Qt::Key_Refresh>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Favorites, Qt::Key_Favorites>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86HomePage, Qt::Key_HomePage>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Search, Qt::Key_Search>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioStop, Qt::Key_MediaStop>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioNext, Qt::Key_MediaNext>,
|
|
||||||
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_XF86Memo, Qt::Key_Memo>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86ToDoList, Qt::Key_ToDoList>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Calendar, Qt::Key_Calendar>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86PowerDown, Qt::Key_PowerDown>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Standby, Qt::Key_Standby>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86PowerOff, Qt::Key_PowerOff>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86WakeUp, Qt::Key_WakeUp>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Eject, Qt::Key_Eject>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86WWW, Qt::Key_WWW>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Sleep, Qt::Key_Sleep>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86LightBulb, Qt::Key_LightBulb>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Shop, Qt::Key_Shop>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86History, Qt::Key_History>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86HotLinks, Qt::Key_HotLinks>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Finance, Qt::Key_Finance>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Community, Qt::Key_Community>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86BackForward, Qt::Key_BackForward>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Book, Qt::Key_Book>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86CD, Qt::Key_CD>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Calculater, Qt::Key_Calculator>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Clear, Qt::Key_Clear>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Close, Qt::Key_Close>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Copy, Qt::Key_Copy>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Cut, Qt::Key_Cut>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Display, Qt::Key_Display>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86DOS, Qt::Key_DOS>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Documents, Qt::Key_Documents>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Excel, Qt::Key_Excel>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Explorer, Qt::Key_Explorer>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Game, Qt::Key_Game>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Go, Qt::Key_Go>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86iTouch, Qt::Key_iTouch>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86LogOff, Qt::Key_LogOff>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Market, Qt::Key_Market>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Meeting, Qt::Key_Meeting>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86MenuKB, Qt::Key_MenuKB>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86MenuPB, Qt::Key_MenuPB>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86MySites, Qt::Key_MySites>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86New, Qt::Key_New>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86News, Qt::Key_News>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Open, Qt::Key_Open>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Option, Qt::Key_Option>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Paste, Qt::Key_Paste>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Phone, Qt::Key_Phone>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Reply, Qt::Key_Reply>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Reload, Qt::Key_Reload>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86RotationPB, Qt::Key_RotationPB>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86RotationKB, Qt::Key_RotationKB>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Save, Qt::Key_Save>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Send, Qt::Key_Send>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Spell, Qt::Key_Spell>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Support, Qt::Key_Support>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86TaskPane, Qt::Key_TaskPane>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Terminal, Qt::Key_Terminal>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Tools, Qt::Key_Tools>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Travel, Qt::Key_Travel>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Video, Qt::Key_Video>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Word, Qt::Key_Word>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Xfer, Qt::Key_Xfer>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Away, Qt::Key_Away>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Messenger, Qt::Key_Messenger>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86WebCam, Qt::Key_WebCam>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86MailForward, Qt::Key_MailForward>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Pictures, Qt::Key_Pictures>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Music, Qt::Key_Music>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Battery, Qt::Key_Battery>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86WLAN, Qt::Key_WLAN>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86UWB, Qt::Key_UWB>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioForward, Qt::Key_AudioForward>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Subtitle, Qt::Key_Subtitle>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Time, Qt::Key_Time>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Select, Qt::Key_Select>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86View, Qt::Key_View>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86TopMenu, Qt::Key_TopMenu>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Red, Qt::Key_Red>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Green, Qt::Key_Green>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Yellow, Qt::Key_Yellow>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Blue, Qt::Key_Blue>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Suspend, Qt::Key_Suspend>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86Hibernate, Qt::Key_Hibernate>,
|
|
||||||
Xkb2Qt<XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle>,
|
|
||||||
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>
|
|
||||||
>::Data{}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Possible modifier states.
|
|
||||||
static const Qt::KeyboardModifiers ModsTbl[] = {
|
|
||||||
Qt::NoModifier, // 0
|
|
||||||
Qt::ShiftModifier, // 1
|
|
||||||
Qt::ControlModifier, // 2
|
|
||||||
Qt::ControlModifier | Qt::ShiftModifier, // 3
|
|
||||||
Qt::AltModifier, // 4
|
|
||||||
Qt::AltModifier | Qt::ShiftModifier, // 5
|
|
||||||
Qt::AltModifier | Qt::ControlModifier, // 6
|
|
||||||
Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7
|
|
||||||
Qt::NoModifier // Fall-back to raw Key_*, for non-latin1 kb layouts
|
|
||||||
};
|
|
||||||
|
|
||||||
Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const
|
Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const
|
||||||
{
|
{
|
||||||
Qt::KeyboardModifiers ret = 0;
|
Qt::KeyboardModifiers ret = Qt::NoModifier;
|
||||||
if (s & XCB_MOD_MASK_SHIFT)
|
if (s & XCB_MOD_MASK_SHIFT)
|
||||||
ret |= Qt::ShiftModifier;
|
ret |= Qt::ShiftModifier;
|
||||||
if (s & XCB_MOD_MASK_CONTROL)
|
if (s & XCB_MOD_MASK_CONTROL)
|
||||||
@ -473,7 +88,7 @@ static xcb_keysym_t getUnshiftedXKey(xcb_keysym_t unshifted, xcb_keysym_t shifte
|
|||||||
|
|
||||||
xcb_keysym_t xlower;
|
xcb_keysym_t xlower;
|
||||||
xcb_keysym_t xupper;
|
xcb_keysym_t xupper;
|
||||||
xkbcommon_XConvertCase(unshifted, &xlower, &xupper);
|
QXkbCommon::xkbcommon_XConvertCase(unshifted, &xlower, &xupper);
|
||||||
|
|
||||||
if (xlower != xupper // Check if symbol is cased
|
if (xlower != xupper // Check if symbol is cased
|
||||||
&& unshifted == xupper) { // Unshifted must be upper case
|
&& unshifted == xupper) { // Unshifted must be upper case
|
||||||
@ -805,7 +420,12 @@ void QXcbKeyboard::updateKeymap()
|
|||||||
|
|
||||||
updateXKBMods();
|
updateXKBMods();
|
||||||
|
|
||||||
checkForLatinLayout();
|
QXkbCommon::verifyHasLatinLayout(m_xkbKeymap.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
|
||||||
|
{
|
||||||
|
return QXkbCommon::possibleKeys(m_xkbState.get(), event, m_superAsMeta, m_hyperAsMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_CONFIG(xkb)
|
#if QT_CONFIG(xkb)
|
||||||
@ -918,272 +538,6 @@ void QXcbKeyboard::updateXKBMods()
|
|||||||
xkb_mods.mod5 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod5");
|
xkb_mods.mod5 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod5");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isLatin(xkb_keysym_t sym)
|
|
||||||
{
|
|
||||||
return ((sym >= 'a' && sym <= 'z') || (sym >= 'A' && sym <= 'Z'));
|
|
||||||
}
|
|
||||||
|
|
||||||
void QXcbKeyboard::checkForLatinLayout() const
|
|
||||||
{
|
|
||||||
const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(m_xkbKeymap.get());
|
|
||||||
const xcb_keycode_t minKeycode = xkb_keymap_min_keycode(m_xkbKeymap.get());
|
|
||||||
const xcb_keycode_t maxKeycode = xkb_keymap_max_keycode(m_xkbKeymap.get());
|
|
||||||
|
|
||||||
const xkb_keysym_t *keysyms = nullptr;
|
|
||||||
int nrLatinKeys = 0;
|
|
||||||
for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) {
|
|
||||||
for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
|
|
||||||
xkb_keymap_key_get_syms_by_level(m_xkbKeymap.get(), code, layout, 0, &keysyms);
|
|
||||||
if (keysyms && isLatin(keysyms[0]))
|
|
||||||
nrLatinKeys++;
|
|
||||||
if (nrLatinKeys > 10) // arbitrarily chosen threshold
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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 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.
|
|
||||||
qCWarning(lcQpaKeyboard, "no keyboard layouts with latin keys present");
|
|
||||||
}
|
|
||||||
|
|
||||||
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(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(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];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sym == XKB_KEY_NoSymbol)
|
|
||||||
return sym;
|
|
||||||
|
|
||||||
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).
|
|
||||||
// In this setup, the user would expect to trigger a ctrl+q shortcut by pressing ctrl+<physical x key>,
|
|
||||||
// because "US dvorak" is higher up in the layout settings list. This check verifies that an obtained
|
|
||||||
// 'sym' can not be acquired by any other layout higher up in the user's layout list. If it can be acquired
|
|
||||||
// then the obtained key is not unique. This prevents ctrl+<physical q key> from generating a ctrl+q
|
|
||||||
// shortcut in the above described setup. We don't want ctrl+<physical x key> and ctrl+<physical q key> to
|
|
||||||
// generate the same shortcut event in this case.
|
|
||||||
const xcb_keycode_t minKeycode = xkb_keymap_min_keycode(m_xkbKeymap.get());
|
|
||||||
const xcb_keycode_t maxKeycode = xkb_keymap_max_keycode(m_xkbKeymap.get());
|
|
||||||
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) {
|
|
||||||
xkb_keysym_t prevSym = xkb_state_key_get_one_sym(state.get(), code);
|
|
||||||
if (prevSym == sym) {
|
|
||||||
sym = XKB_KEY_NoSymbol;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(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(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();
|
|
||||||
// handle shortcuts for level three and above
|
|
||||||
xkb_layout_index_t layoutIndex = xkb_state_key_get_layout(kb_state, keycode);
|
|
||||||
xkb_level_index_t levelIndex = 0;
|
|
||||||
if (layoutIndex != XKB_LAYOUT_INVALID) {
|
|
||||||
levelIndex = xkb_state_key_get_level(kb_state, keycode, layoutIndex);
|
|
||||||
if (levelIndex == XKB_LEVEL_INVALID)
|
|
||||||
levelIndex = 0;
|
|
||||||
}
|
|
||||||
if (levelIndex <= 1)
|
|
||||||
xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, 0, 0, lockedLayout);
|
|
||||||
|
|
||||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, keycode);
|
|
||||||
if (sym == XKB_KEY_NoSymbol) {
|
|
||||||
xkb_state_unref(kb_state);
|
|
||||||
return QList<int>();
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<int> result;
|
|
||||||
int baseQtKey = keysymToQtKey(sym, modifiers, kb_state, keycode);
|
|
||||||
if (baseQtKey)
|
|
||||||
result += (baseQtKey + modifiers);
|
|
||||||
|
|
||||||
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);
|
|
||||||
Q_ASSERT(controlMod < 32);
|
|
||||||
|
|
||||||
xkb_mod_mask_t depressed;
|
|
||||||
int qtKey = 0;
|
|
||||||
// obtain a list of possible shortcuts for the given key event
|
|
||||||
for (uint i = 1; i < sizeof(ModsTbl) / sizeof(*ModsTbl) ; ++i) {
|
|
||||||
Qt::KeyboardModifiers neededMods = ModsTbl[i];
|
|
||||||
if ((modifiers & neededMods) == neededMods) {
|
|
||||||
if (i == 8) {
|
|
||||||
if (isLatin(baseQtKey))
|
|
||||||
continue;
|
|
||||||
// add a latin key as a fall back key
|
|
||||||
sym = lookupLatinKeysym(keycode);
|
|
||||||
} else {
|
|
||||||
depressed = 0;
|
|
||||||
if (neededMods & Qt::AltModifier)
|
|
||||||
depressed |= (1 << altMod);
|
|
||||||
if (neededMods & Qt::ShiftModifier)
|
|
||||||
depressed |= (1 << shiftMod);
|
|
||||||
if (neededMods & Qt::ControlModifier)
|
|
||||||
depressed |= (1 << controlMod);
|
|
||||||
if (metaMod < 32 && neededMods & Qt::MetaModifier)
|
|
||||||
depressed |= (1 << metaMod);
|
|
||||||
xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, 0, 0, lockedLayout);
|
|
||||||
sym = xkb_state_key_get_one_sym(kb_state, keycode);
|
|
||||||
}
|
|
||||||
if (sym == XKB_KEY_NoSymbol)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Qt::KeyboardModifiers mods = modifiers & ~neededMods;
|
|
||||||
qtKey = keysymToQtKey(sym, mods, kb_state, keycode);
|
|
||||||
if (!qtKey || qtKey == baseQtKey)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
ambiguous = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ambiguous)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
result += (qtKey + mods);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xkb_state_unref(kb_state);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modifiers,
|
|
||||||
struct xkb_state *state, xcb_keycode_t code) const
|
|
||||||
{
|
|
||||||
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
|
|
||||||
xkb2qt_t searchKey{keysym, 0};
|
|
||||||
auto it = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey);
|
|
||||||
if (it != KeyTbl.end() && !(searchKey < *it))
|
|
||||||
qtKey = it->qt;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 && (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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
qCDebug(lcQpaKeyboard).nospace() << "no Qt::Key for keysym: " << keysymName
|
|
||||||
<< "(" << keysymInHex << ") | text: " << text << " | qt key: " << qtKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return qtKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
|
QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
|
||||||
: QXcbObject(connection)
|
: QXcbObject(connection)
|
||||||
{
|
{
|
||||||
@ -1211,6 +565,12 @@ QXcbKeyboard::~QXcbKeyboard()
|
|||||||
xcb_key_symbols_free(m_key_symbols);
|
xcb_key_symbols_free(m_key_symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QXcbKeyboard::initialize()
|
||||||
|
{
|
||||||
|
auto inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
|
||||||
|
QXkbCommon::setXkbContext(inputContext, m_xkbContext.get());
|
||||||
|
}
|
||||||
|
|
||||||
void QXcbKeyboard::selectEvents()
|
void QXcbKeyboard::selectEvents()
|
||||||
{
|
{
|
||||||
#if QT_CONFIG(xkb)
|
#if QT_CONFIG(xkb)
|
||||||
@ -1514,6 +874,12 @@ void QXcbKeyboard::resolveMaskConflicts()
|
|||||||
rmod_masks.meta = rmod_masks.hyper;
|
rmod_masks.meta = rmod_masks.hyper;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// translate Super/Hyper keys to Meta if we're using them as the MetaModifier
|
||||||
|
if (rmod_masks.meta && rmod_masks.meta == rmod_masks.super)
|
||||||
|
m_superAsMeta = true;
|
||||||
|
if (rmod_masks.meta && rmod_masks.meta == rmod_masks.hyper)
|
||||||
|
m_hyperAsMeta = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, xcb_keycode_t code,
|
void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, xcb_keycode_t code,
|
||||||
@ -1529,7 +895,7 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
|
|||||||
if (type == QEvent::KeyPress)
|
if (type == QEvent::KeyPress)
|
||||||
targetWindow->updateNetWmUserTime(time);
|
targetWindow->updateNetWmUserTime(time);
|
||||||
|
|
||||||
ScopedXKBState sendEventState;
|
QXkbCommon::ScopedXKBState sendEventState;
|
||||||
if (fromSendEvent) {
|
if (fromSendEvent) {
|
||||||
// Have a temporary keyboard state filled in from state
|
// Have a temporary keyboard state filled in from state
|
||||||
// this way we allow for synthetic events to have different state
|
// this way we allow for synthetic events to have different state
|
||||||
@ -1546,30 +912,13 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
|
|||||||
struct xkb_state *xkbState = fromSendEvent ? sendEventState.get() : m_xkbState.get();
|
struct xkb_state *xkbState = fromSendEvent ? sendEventState.get() : m_xkbState.get();
|
||||||
|
|
||||||
xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code);
|
xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code);
|
||||||
QString text = lookupString(xkbState, code);
|
QString text = QXkbCommon::lookupString(xkbState, code);
|
||||||
|
|
||||||
Qt::KeyboardModifiers modifiers = translateModifiers(state);
|
Qt::KeyboardModifiers modifiers = translateModifiers(state);
|
||||||
if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9)
|
if (QXkbCommon::isKeypad(sym))
|
||||||
modifiers |= Qt::KeypadModifier;
|
modifiers |= Qt::KeypadModifier;
|
||||||
|
|
||||||
// Note 1: All standard key sequences on linux (as defined in platform theme)
|
int qtcode = QXkbCommon::keysymToQtKey(sym, modifiers, xkbState, code, m_superAsMeta, m_hyperAsMeta);
|
||||||
// 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, code);
|
|
||||||
|
|
||||||
if (type == QEvent::KeyPress) {
|
if (type == QEvent::KeyPress) {
|
||||||
if (m_isAutoRepeat && m_autoRepeatCode != code)
|
if (m_isAutoRepeat && m_autoRepeatCode != code)
|
||||||
@ -1611,28 +960,6 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const
|
|
||||||
{
|
|
||||||
QVarLengthArray<char, 32> chars(32);
|
|
||||||
const int size = xkb_state_key_get_utf8(state, code, chars.data(), chars.size());
|
|
||||||
if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL
|
|
||||||
chars.resize(size + 1);
|
|
||||||
xkb_state_key_get_utf8(state, code, chars.data(), chars.size());
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool fromSendEvent(const void *event)
|
static bool fromSendEvent(const void *event)
|
||||||
{
|
{
|
||||||
// From X11 protocol: Every event contains an 8-bit type code. The most
|
// From X11 protocol: Every event contains an 8-bit type code. The most
|
||||||
|
@ -50,16 +50,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#if QT_CONFIG(xkb)
|
#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
|
||||||
#include <xkbcommon/xkbcommon-x11.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QWindow;
|
|
||||||
|
|
||||||
class QXcbKeyboard : public QXcbObject
|
class QXcbKeyboard : public QXcbObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -67,6 +63,7 @@ public:
|
|||||||
|
|
||||||
~QXcbKeyboard();
|
~QXcbKeyboard();
|
||||||
|
|
||||||
|
void initialize();
|
||||||
void selectEvents();
|
void selectEvents();
|
||||||
|
|
||||||
void handleKeyPressEvent(const xcb_key_press_event_t *event);
|
void handleKeyPressEvent(const xcb_key_press_event_t *event);
|
||||||
@ -75,7 +72,7 @@ public:
|
|||||||
Qt::KeyboardModifiers translateModifiers(int s) const;
|
Qt::KeyboardModifiers translateModifiers(int s) const;
|
||||||
void updateKeymap(xcb_mapping_notify_event_t *event);
|
void updateKeymap(xcb_mapping_notify_event_t *event);
|
||||||
void updateKeymap();
|
void updateKeymap();
|
||||||
QList<int> possibleKeys(const QKeyEvent *e) const;
|
QList<int> possibleKeys(const QKeyEvent *event) const;
|
||||||
|
|
||||||
// when XKEYBOARD not present on the X server
|
// when XKEYBOARD not present on the X server
|
||||||
void updateXKBMods();
|
void updateXKBMods();
|
||||||
@ -96,10 +93,6 @@ protected:
|
|||||||
quint16 state, xcb_timestamp_t time, bool fromSendEvent);
|
quint16 state, xcb_timestamp_t time, bool fromSendEvent);
|
||||||
|
|
||||||
void resolveMaskConflicts();
|
void resolveMaskConflicts();
|
||||||
QString lookupString(struct xkb_state *state, xcb_keycode_t code) 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;
|
|
||||||
|
|
||||||
typedef QMap<xcb_keysym_t, int> KeysymModifierMap;
|
typedef QMap<xcb_keysym_t, int> KeysymModifierMap;
|
||||||
struct xkb_keymap *keymapFromCore(const KeysymModifierMap &keysymMods);
|
struct xkb_keymap *keymapFromCore(const KeysymModifierMap &keysymMods);
|
||||||
@ -111,9 +104,6 @@ protected:
|
|||||||
void updateVModMapping();
|
void updateVModMapping();
|
||||||
void updateVModToRModMapping();
|
void updateVModToRModMapping();
|
||||||
|
|
||||||
xkb_keysym_t lookupLatinKeysym(xkb_keycode_t keycode) const;
|
|
||||||
void checkForLatinLayout() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_config = false;
|
bool m_config = false;
|
||||||
bool m_isAutoRepeat = false;
|
bool m_isAutoRepeat = false;
|
||||||
@ -148,22 +138,12 @@ private:
|
|||||||
int core_device_id;
|
int core_device_id;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct XKBStateDeleter {
|
QXkbCommon::ScopedXKBState m_xkbState;
|
||||||
void operator()(struct xkb_state *state) const { return xkb_state_unref(state); }
|
QXkbCommon::ScopedXKBKeymap m_xkbKeymap;
|
||||||
};
|
QXkbCommon::ScopedXKBContext m_xkbContext;
|
||||||
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;
|
bool m_superAsMeta = false;
|
||||||
ScopedXKBKeymap m_xkbKeymap;
|
bool m_hyperAsMeta = false;
|
||||||
ScopedXKBContext m_xkbContext;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -6,7 +6,8 @@ QT += \
|
|||||||
core-private gui-private \
|
core-private gui-private \
|
||||||
service_support-private theme_support-private \
|
service_support-private theme_support-private \
|
||||||
fontdatabase_support-private \
|
fontdatabase_support-private \
|
||||||
edid_support-private
|
edid_support-private \
|
||||||
|
xkbcommon_support-private
|
||||||
|
|
||||||
qtHaveModule(linuxaccessibility_support-private): \
|
qtHaveModule(linuxaccessibility_support-private): \
|
||||||
QT += linuxaccessibility_support-private
|
QT += linuxaccessibility_support-private
|
||||||
@ -52,7 +53,6 @@ HEADERS = \
|
|||||||
qxcbimage.h \
|
qxcbimage.h \
|
||||||
qxcbxsettings.h \
|
qxcbxsettings.h \
|
||||||
qxcbsystemtraytracker.h \
|
qxcbsystemtraytracker.h \
|
||||||
qxcbxkbcommon.h \
|
|
||||||
qxcbeventqueue.h \
|
qxcbeventqueue.h \
|
||||||
qxcbeventdispatcher.h \
|
qxcbeventdispatcher.h \
|
||||||
qxcbconnection_basic.h \
|
qxcbconnection_basic.h \
|
||||||
|
@ -780,7 +780,10 @@ void QDialog::setVisible(bool visible)
|
|||||||
|
|
||||||
QWidget::setVisible(visible);
|
QWidget::setVisible(visible);
|
||||||
#if QT_DEPRECATED_SINCE(5, 13)
|
#if QT_DEPRECATED_SINCE(5, 13)
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
showExtension(d->doShowExtension);
|
showExtension(d->doShowExtension);
|
||||||
|
QT_WARNING_POP
|
||||||
#endif
|
#endif
|
||||||
QWidget *fw = window()->focusWidget();
|
QWidget *fw = window()->focusWidget();
|
||||||
if (!fw)
|
if (!fw)
|
||||||
|
@ -587,10 +587,13 @@ void QFileDialogPrivate::retranslateWindowTitle()
|
|||||||
return;
|
return;
|
||||||
if (q->acceptMode() == QFileDialog::AcceptOpen) {
|
if (q->acceptMode() == QFileDialog::AcceptOpen) {
|
||||||
const QFileDialog::FileMode fileMode = q->fileMode();
|
const QFileDialog::FileMode fileMode = q->fileMode();
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory)
|
if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory)
|
||||||
q->setWindowTitle(QFileDialog::tr("Find Directory"));
|
q->setWindowTitle(QFileDialog::tr("Find Directory"));
|
||||||
else
|
else
|
||||||
q->setWindowTitle(QFileDialog::tr("Open"));
|
q->setWindowTitle(QFileDialog::tr("Open"));
|
||||||
|
QT_WARNING_POP
|
||||||
} else
|
} else
|
||||||
q->setWindowTitle(QFileDialog::tr("Save As"));
|
q->setWindowTitle(QFileDialog::tr("Save As"));
|
||||||
|
|
||||||
@ -614,7 +617,10 @@ void QFileDialogPrivate::updateFileNameLabel()
|
|||||||
setLabelTextControl(QFileDialog::FileName, options->labelText(QFileDialogOptions::FileName));
|
setLabelTextControl(QFileDialog::FileName, options->labelText(QFileDialogOptions::FileName));
|
||||||
} else {
|
} else {
|
||||||
switch (q_func()->fileMode()) {
|
switch (q_func()->fileMode()) {
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
case QFileDialog::DirectoryOnly:
|
case QFileDialog::DirectoryOnly:
|
||||||
|
QT_WARNING_POP
|
||||||
case QFileDialog::Directory:
|
case QFileDialog::Directory:
|
||||||
setLabelTextControl(QFileDialog::FileName, QFileDialog::tr("Directory:"));
|
setLabelTextControl(QFileDialog::FileName, QFileDialog::tr("Directory:"));
|
||||||
break;
|
break;
|
||||||
@ -642,7 +648,10 @@ void QFileDialogPrivate::updateOkButtonText(bool saveAsOnFolder)
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
switch (q->fileMode()) {
|
switch (q->fileMode()) {
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
case QFileDialog::DirectoryOnly:
|
case QFileDialog::DirectoryOnly:
|
||||||
|
QT_WARNING_POP
|
||||||
case QFileDialog::Directory:
|
case QFileDialog::Directory:
|
||||||
setLabelTextControl(QFileDialog::Accept, QFileDialog::tr("&Choose"));
|
setLabelTextControl(QFileDialog::Accept, QFileDialog::tr("&Choose"));
|
||||||
break;
|
break;
|
||||||
@ -1709,7 +1718,10 @@ void QFileDialog::setFileMode(QFileDialog::FileMode mode)
|
|||||||
d->options->setFileMode(static_cast<QFileDialogOptions::FileMode>(mode));
|
d->options->setFileMode(static_cast<QFileDialogOptions::FileMode>(mode));
|
||||||
|
|
||||||
// keep ShowDirsOnly option in sync with fileMode (BTW, DirectoryOnly is obsolete)
|
// keep ShowDirsOnly option in sync with fileMode (BTW, DirectoryOnly is obsolete)
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
setOption(ShowDirsOnly, mode == DirectoryOnly);
|
setOption(ShowDirsOnly, mode == DirectoryOnly);
|
||||||
|
QT_WARNING_POP
|
||||||
|
|
||||||
if (!d->usingWidgets())
|
if (!d->usingWidgets())
|
||||||
return;
|
return;
|
||||||
@ -1727,11 +1739,14 @@ void QFileDialog::setFileMode(QFileDialog::FileMode mode)
|
|||||||
// set filter
|
// set filter
|
||||||
d->model->setFilter(d->filterForMode(filter()));
|
d->model->setFilter(d->filterForMode(filter()));
|
||||||
// setup file type for directory
|
// setup file type for directory
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
if (mode == DirectoryOnly || mode == Directory) {
|
if (mode == DirectoryOnly || mode == Directory) {
|
||||||
d->qFileDialogUi->fileTypeCombo->clear();
|
d->qFileDialogUi->fileTypeCombo->clear();
|
||||||
d->qFileDialogUi->fileTypeCombo->addItem(tr("Directories"));
|
d->qFileDialogUi->fileTypeCombo->addItem(tr("Directories"));
|
||||||
d->qFileDialogUi->fileTypeCombo->setEnabled(false);
|
d->qFileDialogUi->fileTypeCombo->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
QT_WARNING_POP
|
||||||
d->updateFileNameLabel();
|
d->updateFileNameLabel();
|
||||||
d->updateOkButtonText();
|
d->updateOkButtonText();
|
||||||
d->qFileDialogUi->fileTypeCombo->setEnabled(!testOption(ShowDirsOnly));
|
d->qFileDialogUi->fileTypeCombo->setEnabled(!testOption(ShowDirsOnly));
|
||||||
@ -2634,7 +2649,10 @@ QUrl QFileDialog::getExistingDirectoryUrl(QWidget *parent,
|
|||||||
args.parent = parent;
|
args.parent = parent;
|
||||||
args.caption = caption;
|
args.caption = caption;
|
||||||
args.directory = QFileDialogPrivate::workingDirectory(dir);
|
args.directory = QFileDialogPrivate::workingDirectory(dir);
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
args.mode = (options & ShowDirsOnly ? DirectoryOnly : Directory);
|
args.mode = (options & ShowDirsOnly ? DirectoryOnly : Directory);
|
||||||
|
QT_WARNING_POP
|
||||||
args.options = options;
|
args.options = options;
|
||||||
|
|
||||||
QFileDialog dialog(args);
|
QFileDialog dialog(args);
|
||||||
@ -2747,7 +2765,10 @@ void QFileDialog::accept()
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (fileMode()) {
|
switch (fileMode()) {
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
case DirectoryOnly:
|
case DirectoryOnly:
|
||||||
|
QT_WARNING_POP
|
||||||
case Directory: {
|
case Directory: {
|
||||||
QString fn = files.first();
|
QString fn = files.first();
|
||||||
QFileInfo info(fn);
|
QFileInfo info(fn);
|
||||||
@ -2783,7 +2804,7 @@ void QFileDialog::accept()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if we have to ask for permission to overwrite the file
|
// check if we have to ask for permission to overwrite the file
|
||||||
if (!info.exists() || !confirmOverwrite() || acceptMode() == AcceptOpen) {
|
if (!info.exists() || testOption(DontConfirmOverwrite) || acceptMode() == AcceptOpen) {
|
||||||
d->emitFilesSelected(QStringList(fn));
|
d->emitFilesSelected(QStringList(fn));
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
#if QT_CONFIG(messagebox)
|
#if QT_CONFIG(messagebox)
|
||||||
@ -3651,7 +3672,10 @@ void QFileDialogPrivate::_q_updateOkButton()
|
|||||||
isOpenDirectory = true;
|
isOpenDirectory = true;
|
||||||
} else {
|
} else {
|
||||||
switch (fileMode) {
|
switch (fileMode) {
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
case QFileDialog::DirectoryOnly:
|
case QFileDialog::DirectoryOnly:
|
||||||
|
QT_WARNING_POP
|
||||||
case QFileDialog::Directory: {
|
case QFileDialog::Directory: {
|
||||||
QString fn = files.first();
|
QString fn = files.first();
|
||||||
QModelIndex idx = model->index(fn);
|
QModelIndex idx = model->index(fn);
|
||||||
@ -3743,12 +3767,15 @@ void QFileDialogPrivate::_q_enterDirectory(const QModelIndex &index)
|
|||||||
const QFileDialog::FileMode fileMode = q->fileMode();
|
const QFileDialog::FileMode fileMode = q->fileMode();
|
||||||
q->setDirectory(path);
|
q->setDirectory(path);
|
||||||
emit q->directoryEntered(path);
|
emit q->directoryEntered(path);
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
if (fileMode == QFileDialog::Directory
|
if (fileMode == QFileDialog::Directory
|
||||||
|| fileMode == QFileDialog::DirectoryOnly) {
|
|| fileMode == QFileDialog::DirectoryOnly) {
|
||||||
// ### find out why you have to do both of these.
|
// ### find out why you have to do both of these.
|
||||||
lineEdit()->setText(QString());
|
lineEdit()->setText(QString());
|
||||||
lineEdit()->clear();
|
lineEdit()->clear();
|
||||||
}
|
}
|
||||||
|
QT_WARNING_POP
|
||||||
} else {
|
} else {
|
||||||
// Do not accept when shift-clicking to multi-select a file in environments with single-click-activation (KDE)
|
// Do not accept when shift-clicking to multi-select a file in environments with single-click-activation (KDE)
|
||||||
if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, qFileDialogUi->treeView)
|
if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, qFileDialogUi->treeView)
|
||||||
@ -3840,7 +3867,10 @@ void QFileDialogPrivate::_q_selectionChanged()
|
|||||||
{
|
{
|
||||||
const QFileDialog::FileMode fileMode = q_func()->fileMode();
|
const QFileDialog::FileMode fileMode = q_func()->fileMode();
|
||||||
const QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows();
|
const QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows();
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
bool stripDirs = (fileMode != QFileDialog::DirectoryOnly && fileMode != QFileDialog::Directory);
|
bool stripDirs = (fileMode != QFileDialog::DirectoryOnly && fileMode != QFileDialog::Directory);
|
||||||
|
QT_WARNING_POP
|
||||||
|
|
||||||
QStringList allFiles;
|
QStringList allFiles;
|
||||||
for (const auto &index : indexes) {
|
for (const auto &index : indexes) {
|
||||||
@ -3892,10 +3922,13 @@ void QFileDialogPrivate::_q_rowsInserted(const QModelIndex &parent)
|
|||||||
void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString &oldName, const QString &newName)
|
void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString &oldName, const QString &newName)
|
||||||
{
|
{
|
||||||
const QFileDialog::FileMode fileMode = q_func()->fileMode();
|
const QFileDialog::FileMode fileMode = q_func()->fileMode();
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
if (fileMode == QFileDialog::Directory || fileMode == QFileDialog::DirectoryOnly) {
|
if (fileMode == QFileDialog::Directory || fileMode == QFileDialog::DirectoryOnly) {
|
||||||
if (path == rootPath() && lineEdit()->text() == oldName)
|
if (path == rootPath() && lineEdit()->text() == oldName)
|
||||||
lineEdit()->setText(newName);
|
lineEdit()->setText(newName);
|
||||||
}
|
}
|
||||||
|
QT_WARNING_POP
|
||||||
}
|
}
|
||||||
|
|
||||||
void QFileDialogPrivate::_q_emitUrlSelected(const QUrl &file)
|
void QFileDialogPrivate::_q_emitUrlSelected(const QUrl &file)
|
||||||
|
@ -164,13 +164,9 @@ public:
|
|||||||
|
|
||||||
QDir::Filters filterForMode(QDir::Filters filters) const
|
QDir::Filters filterForMode(QDir::Filters filters) const
|
||||||
{
|
{
|
||||||
const QFileDialog::FileMode fileMode = q_func()->fileMode();
|
filters |= QDir::Drives | QDir::AllDirs | QDir::Dirs | QDir::Files;
|
||||||
if (fileMode == QFileDialog::DirectoryOnly) {
|
if (q_func()->testOption(QFileDialog::ShowDirsOnly))
|
||||||
filters |= QDir::Drives | QDir::AllDirs | QDir::Dirs;
|
|
||||||
filters &= ~QDir::Files;
|
filters &= ~QDir::Files;
|
||||||
} else {
|
|
||||||
filters |= QDir::Drives | QDir::AllDirs | QDir::Files | QDir::Dirs;
|
|
||||||
}
|
|
||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2306,7 +2306,7 @@ void QGraphicsWidget::paintWindowFrame(QPainter *painter, const QStyleOptionGrap
|
|||||||
QStyleHintReturnMask mask;
|
QStyleHintReturnMask mask;
|
||||||
bool setMask = style()->styleHint(QStyle::SH_WindowFrame_Mask, &bar, widget, &mask) && !mask.region.isEmpty();
|
bool setMask = style()->styleHint(QStyle::SH_WindowFrame_Mask, &bar, widget, &mask) && !mask.region.isEmpty();
|
||||||
bool hasBorder = !style()->styleHint(QStyle::SH_TitleBar_NoBorder, &bar, widget);
|
bool hasBorder = !style()->styleHint(QStyle::SH_TitleBar_NoBorder, &bar, widget);
|
||||||
int frameWidth = style()->pixelMetric(QStyle::PM_MDIFrameWidth, &bar, widget);
|
int frameWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, &bar, widget);
|
||||||
if (setMask) {
|
if (setMask) {
|
||||||
painter->save();
|
painter->save();
|
||||||
painter->setClipRegion(mask.region, Qt::IntersectClip);
|
painter->setClipRegion(mask.region, Qt::IntersectClip);
|
||||||
|
@ -789,7 +789,7 @@ void QItemDelegate::drawCheck(QPainter *painter,
|
|||||||
|
|
||||||
const QWidget *widget = d->widget(option);
|
const QWidget *widget = d->widget(option);
|
||||||
QStyle *style = widget ? widget->style() : QApplication::style();
|
QStyle *style = widget ? widget->style() : QApplication::style();
|
||||||
style->drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &opt, painter, widget);
|
style->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &opt, painter, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -194,7 +194,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
|
|||||||
opt->state & (State_Sunken | State_On), 1,
|
opt->state & (State_Sunken | State_On), 1,
|
||||||
&opt->palette.brush(QPalette::Button));
|
&opt->palette.brush(QPalette::Button));
|
||||||
break;
|
break;
|
||||||
case PE_IndicatorViewItemCheck:
|
case PE_IndicatorItemViewItemCheck:
|
||||||
proxy()->drawPrimitive(PE_IndicatorCheckBox, opt, p, widget);
|
proxy()->drawPrimitive(PE_IndicatorCheckBox, opt, p, widget);
|
||||||
break;
|
break;
|
||||||
case PE_IndicatorCheckBox:
|
case PE_IndicatorCheckBox:
|
||||||
@ -2283,7 +2283,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
|
|||||||
option.state |= QStyle::State_On;
|
option.state |= QStyle::State_On;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
proxy()->drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &option, p, widget);
|
proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, p, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw the icon
|
// draw the icon
|
||||||
|
@ -558,7 +558,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
|
|||||||
qt_fusion_draw_arrow(arrow, painter, option, option->rect, arrowColor);
|
qt_fusion_draw_arrow(arrow, painter, option, option->rect, arrowColor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PE_IndicatorViewItemCheck:
|
case PE_IndicatorItemViewItemCheck:
|
||||||
{
|
{
|
||||||
QStyleOptionButton button;
|
QStyleOptionButton button;
|
||||||
button.QStyleOption::operator=(*option);
|
button.QStyleOption::operator=(*option);
|
||||||
@ -3673,7 +3673,7 @@ int QFusionStyle::styleHint(StyleHint hint, const QStyleOption *option, const QW
|
|||||||
case SH_FontDialog_SelectAssociatedText:
|
case SH_FontDialog_SelectAssociatedText:
|
||||||
case SH_MenuBar_AltKeyNavigation:
|
case SH_MenuBar_AltKeyNavigation:
|
||||||
case SH_ComboBox_ListMouseTracking:
|
case SH_ComboBox_ListMouseTracking:
|
||||||
case SH_ScrollBar_StopMouseOverSlider:
|
case SH_Slider_StopMouseOverSlider:
|
||||||
case SH_ScrollBar_MiddleClickAbsolutePosition:
|
case SH_ScrollBar_MiddleClickAbsolutePosition:
|
||||||
case SH_EtchDisabledText:
|
case SH_EtchDisabledText:
|
||||||
case SH_TitleBar_AutoRaise:
|
case SH_TitleBar_AutoRaise:
|
||||||
|
@ -4304,7 +4304,7 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op
|
|||||||
|
|
||||||
switch (pe) {
|
switch (pe) {
|
||||||
|
|
||||||
case PE_FrameStatusBar: {
|
case PE_FrameStatusBarItem: {
|
||||||
QRenderRule subRule = renderRule(w ? w->parentWidget() : nullptr, opt, PseudoElement_Item);
|
QRenderRule subRule = renderRule(w ? w->parentWidget() : nullptr, opt, PseudoElement_Item);
|
||||||
if (subRule.hasDrawable()) {
|
if (subRule.hasDrawable()) {
|
||||||
subRule.drawRule(p, opt->rect);
|
subRule.drawRule(p, opt->rect);
|
||||||
@ -4325,7 +4325,7 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op
|
|||||||
pseudoElement = PseudoElement_ExclusiveIndicator;
|
pseudoElement = PseudoElement_ExclusiveIndicator;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PE_IndicatorViewItemCheck:
|
case PE_IndicatorItemViewItemCheck:
|
||||||
pseudoElement = PseudoElement_ViewItemIndicator;
|
pseudoElement = PseudoElement_ViewItemIndicator;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -554,7 +554,7 @@ int QWindowsStyle::styleHint(StyleHint hint, const QStyleOption *opt, const QWid
|
|||||||
case SH_MenuBar_MouseTracking:
|
case SH_MenuBar_MouseTracking:
|
||||||
case SH_Menu_MouseTracking:
|
case SH_Menu_MouseTracking:
|
||||||
case SH_ComboBox_ListMouseTracking:
|
case SH_ComboBox_ListMouseTracking:
|
||||||
case SH_ScrollBar_StopMouseOverSlider:
|
case SH_Slider_StopMouseOverSlider:
|
||||||
case SH_MainWindow_SpaceBelowMenuBar:
|
case SH_MainWindow_SpaceBelowMenuBar:
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
@ -827,13 +827,13 @@ void QWindowsStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt,
|
|||||||
p->setPen(opt->palette.text().color());
|
p->setPen(opt->palette.text().color());
|
||||||
}
|
}
|
||||||
Q_FALLTHROUGH();
|
Q_FALLTHROUGH();
|
||||||
case PE_IndicatorViewItemCheck:
|
case PE_IndicatorItemViewItemCheck:
|
||||||
if (!doRestore) {
|
if (!doRestore) {
|
||||||
p->save();
|
p->save();
|
||||||
doRestore = true;
|
doRestore = true;
|
||||||
}
|
}
|
||||||
#if QT_CONFIG(itemviews)
|
#if QT_CONFIG(itemviews)
|
||||||
if (pe == PE_IndicatorViewItemCheck) {
|
if (pe == PE_IndicatorItemViewItemCheck) {
|
||||||
const QStyleOptionViewItem *itemViewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt);
|
const QStyleOptionViewItem *itemViewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt);
|
||||||
p->setPen(itemViewOpt
|
p->setPen(itemViewOpt
|
||||||
&& itemViewOpt->showDecorationSelected
|
&& itemViewOpt->showDecorationSelected
|
||||||
|
@ -1389,7 +1389,10 @@ void QComboBoxPrivate::_q_emitCurrentIndexChanged(const QModelIndex &index)
|
|||||||
const QString text = itemText(index);
|
const QString text = itemText(index);
|
||||||
emit q->currentIndexChanged(index.row());
|
emit q->currentIndexChanged(index.row());
|
||||||
#if QT_DEPRECATED_SINCE(5, 13)
|
#if QT_DEPRECATED_SINCE(5, 13)
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
emit q->currentIndexChanged(text);
|
emit q->currentIndexChanged(text);
|
||||||
|
QT_WARNING_POP
|
||||||
#endif
|
#endif
|
||||||
// signal lineEdit.textChanged already connected to signal currentTextChanged, so don't emit double here
|
// signal lineEdit.textChanged already connected to signal currentTextChanged, so don't emit double here
|
||||||
if (!lineEdit)
|
if (!lineEdit)
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"QtEventDispatcherSupport" => "$basedir/src/platformsupport/eventdispatchers",
|
"QtEventDispatcherSupport" => "$basedir/src/platformsupport/eventdispatchers",
|
||||||
"QtFontDatabaseSupport" => "$basedir/src/platformsupport/fontdatabases",
|
"QtFontDatabaseSupport" => "$basedir/src/platformsupport/fontdatabases",
|
||||||
"QtInputSupport" => "$basedir/src/platformsupport/input",
|
"QtInputSupport" => "$basedir/src/platformsupport/input",
|
||||||
|
"QtXkbCommonSupport" => "$basedir/src/platformsupport/input/xkbcommon",
|
||||||
"QtPlatformCompositorSupport" => "$basedir/src/platformsupport/platformcompositor",
|
"QtPlatformCompositorSupport" => "$basedir/src/platformsupport/platformcompositor",
|
||||||
"QtServiceSupport" => "$basedir/src/platformsupport/services",
|
"QtServiceSupport" => "$basedir/src/platformsupport/services",
|
||||||
"QtThemeSupport" => "$basedir/src/platformsupport/themes",
|
"QtThemeSupport" => "$basedir/src/platformsupport/themes",
|
||||||
|
@ -67,3 +67,8 @@ winrt|!qtHaveModule(gui)|!qtConfig(accessibility): SUBDIRS -= qaccessibility
|
|||||||
|
|
||||||
android: SUBDIRS += \
|
android: SUBDIRS += \
|
||||||
android
|
android
|
||||||
|
|
||||||
|
qtConfig(xkbcommon): {
|
||||||
|
SUBDIRS += \
|
||||||
|
xkbkeyboard
|
||||||
|
}
|
||||||
|
60
tests/auto/other/xkbkeyboard/tst_xkbkeyboard.cpp
Normal file
60
tests/auto/other/xkbkeyboard/tst_xkbkeyboard.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the test suite of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||||
|
** 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 General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** 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-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <QtCore>
|
||||||
|
#include <QtGui>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
#include <qpa/qplatforminputcontextfactory_p.h>
|
||||||
|
#include <qpa/qplatforminputcontext.h>
|
||||||
|
|
||||||
|
class tst_XkbKeyboard : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private slots:
|
||||||
|
void verifyComposeInputContextInterface();
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_XkbKeyboard::verifyComposeInputContextInterface()
|
||||||
|
{
|
||||||
|
QPlatformInputContext *inputContext = QPlatformInputContextFactory::create(QStringLiteral("compose"));
|
||||||
|
QVERIFY(inputContext);
|
||||||
|
|
||||||
|
const char *const inputContextClassName = "QComposeInputContext";
|
||||||
|
const char *const normalizedSignature = "setXkbContext(xkb_context*)";
|
||||||
|
|
||||||
|
QVERIFY(inputContext->objectName() == QLatin1String(inputContextClassName));
|
||||||
|
|
||||||
|
int methodIndex = inputContext->metaObject()->indexOfMethod(normalizedSignature);
|
||||||
|
QMetaMethod method = inputContext->metaObject()->method(methodIndex);
|
||||||
|
Q_ASSERT(method.isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_XkbKeyboard)
|
||||||
|
#include "tst_xkbkeyboard.moc"
|
||||||
|
|
7
tests/auto/other/xkbkeyboard/xkbkeyboard.pro
Normal file
7
tests/auto/other/xkbkeyboard/xkbkeyboard.pro
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
CONFIG += testcase
|
||||||
|
TARGET = tst_xkbkeyboard
|
||||||
|
|
||||||
|
SOURCES += tst_xkbkeyboard.cpp
|
||||||
|
|
||||||
|
QT = core-private gui-private testlib
|
||||||
|
|
@ -113,7 +113,7 @@ int main(int argc, char **argv) {
|
|||||||
outIndicesBuffer.write("] = {\n");
|
outIndicesBuffer.write("] = {\n");
|
||||||
|
|
||||||
int totalUtf8Size = 0;
|
int totalUtf8Size = 0;
|
||||||
int chunkSize = 0;
|
int chunkSize = 0; // strlen of the current chunk (sizeof is bigger by 1)
|
||||||
int stringUtf8Size = 0;
|
int stringUtf8Size = 0;
|
||||||
QStringList chunks;
|
QStringList chunks;
|
||||||
for (int a = 0; a < lineCount; a++) {
|
for (int a = 0; a < lineCount; a++) {
|
||||||
@ -127,7 +127,8 @@ int main(int argc, char **argv) {
|
|||||||
int quoteCount = strings.at(a).count('"');
|
int quoteCount = strings.at(a).count('"');
|
||||||
stringUtf8Size = strings.at(a).count() - (zeroCount + quoteCount + utf8CharsCount * 3);
|
stringUtf8Size = strings.at(a).count() - (zeroCount + quoteCount + utf8CharsCount * 3);
|
||||||
chunkSize += stringUtf8Size;
|
chunkSize += stringUtf8Size;
|
||||||
if (chunkSize > 65535) {
|
// MSVC 2015 chokes if sizeof(a single string) > 0xffff
|
||||||
|
if (chunkSize >= 0xffff) {
|
||||||
static int chunkCount = 0;
|
static int chunkCount = 0;
|
||||||
qWarning() << "chunk" << ++chunkCount << "has length" << chunkSize - stringUtf8Size;
|
qWarning() << "chunk" << ++chunkCount << "has length" << chunkSize - stringUtf8Size;
|
||||||
outDataBuffer.write(",\n\n");
|
outDataBuffer.write(",\n\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user