diff options
Diffstat (limited to 'src/compositor/compositor_api/qwaylandkeyboard.cpp')
-rw-r--r-- | src/compositor/compositor_api/qwaylandkeyboard.cpp | 133 |
1 files changed, 85 insertions, 48 deletions
diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp index c5ec008d7..8af7fbd8c 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.cpp +++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Copyright (C) 2017 Klarälvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// Copyright (C) 2017 Klarälvdalens Datakonsult AB (KDAB). +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "qtwaylandcompositorglobal_p.h" #include "qwaylandkeyboard.h" @@ -49,11 +13,13 @@ #include <QtCore/QFile> #include <QtCore/QStandardPaths> +#include <QKeyEvent> #include <fcntl.h> #include <unistd.h> #if QT_CONFIG(xkbcommon) #include <sys/mman.h> #include <sys/types.h> +#include <xkbcommon/xkbcommon-names.h> #endif QT_BEGIN_NAMESPACE @@ -197,11 +163,27 @@ void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable() continue; Qt::KeyboardModifiers mods = {}; - int qtKey = QXkbCommon::keysymToQtKey(syms[0], mods); + int qtKey = QXkbCommon::keysymToQtKey(syms[0], mods, nullptr, 0, false, false); if (qtKey != 0) scanCodesByQtKey->insert({layout, qtKey}, keycode); } }, &scanCodesByQtKey); + + shiftIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); + controlIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); + altIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT); + } +} + +void QWaylandKeyboardPrivate::resetKeyboardState() +{ + if (!xkbContext()) + return; + + while (!keys.isEmpty()) { + uint32_t code = fromWaylandKey(keys.first()); + keyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED); + updateModifierState(code, WL_KEYBOARD_KEY_STATE_RELEASED); } } #endif @@ -233,6 +215,15 @@ void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state) if (focusResource) { send_modifiers(focusResource->handle, compositor()->nextSerial(), modsDepressed, modsLatched, modsLocked, group); + + Qt::KeyboardModifiers currentState = Qt::NoModifier; + if (xkb_state_mod_index_is_active(xkbState(), shiftIndex, XKB_STATE_MODS_EFFECTIVE) == 1) + currentState |= Qt::ShiftModifier; + if (xkb_state_mod_index_is_active(xkbState(), controlIndex, XKB_STATE_MODS_EFFECTIVE) == 1) + currentState |= Qt::ControlModifier; + if (xkb_state_mod_index_is_active(xkbState(), altIndex, XKB_STATE_MODS_EFFECTIVE) == 1) + currentState |= Qt::AltModifier; + currentModifierState = currentState; } #else Q_UNUSED(code); @@ -272,17 +263,29 @@ void QWaylandKeyboardPrivate::maybeUpdateKeymap() #endif } +// In all current XKB keymaps there's a constant offset of 8 (for historical +// reasons) from hardware/evdev scancodes to XKB keycodes. On X11, we pass +// XKB keycodes (as sent by X server) via QKeyEvent::nativeScanCode. eglfs+evdev +// adds 8 for consistency, see qtbase/05c07c7636012ebb4131ca099ca4ea093af76410. +// eglfs+libinput also adds 8, for the same reason. Wayland protocol uses +// hardware/evdev scancodes, thus we need to subtract 8 before sending the event +// out and add it when mapping back. +#define QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET 8 + +uint QWaylandKeyboardPrivate::fromWaylandKey(const uint key) +{ +#if QT_CONFIG(xkbcommon) + const uint offset = QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET; + return key + offset; +#else + return key; +#endif +} + uint QWaylandKeyboardPrivate::toWaylandKey(const uint nativeScanCode) { #if QT_CONFIG(xkbcommon) - // In all current XKB keymaps there's a constant offset of 8 (for historical - // reasons) from hardware/evdev scancodes to XKB keycodes. On X11, we pass - // XKB keycodes (as sent by X server) via QKeyEvent::nativeScanCode. eglfs+evdev - // adds 8 for consistency, see qtbase/05c07c7636012ebb4131ca099ca4ea093af76410. - // eglfs+libinput also adds 8, for the same reason. Wayland protocol uses - // hardware/evdev scancodes, thus we need to minus 8 before sending the event - // out. - const uint offset = 8; + const uint offset = QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET; Q_ASSERT(nativeScanCode >= offset); return nativeScanCode - offset; #else @@ -508,6 +511,38 @@ void QWaylandKeyboard::sendKeyReleaseEvent(uint code) d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED); } +void QWaylandKeyboardPrivate::checkAndRepairModifierState(QKeyEvent *ke) +{ +#if QT_CONFIG(xkbcommon) + if (ke->modifiers() != currentModifierState) { + if (focusResource && ke->key() != Qt::Key_Shift + && ke->key() != Qt::Key_Control && ke->key() != Qt::Key_Alt) { + // Only repair the state for non-modifier keys + // ### slightly awkward because the standard modifier handling + // is done by QtWayland::WindowSystemEventHandler after the + // key event is delivered + uint32_t mods = 0; + + if (shiftIndex == 0 && controlIndex == 0) + maybeUpdateXkbScanCodeTable(); + + if (ke->modifiers() & Qt::ShiftModifier) + mods |= 1 << shiftIndex; + if (ke->modifiers() & Qt::ControlModifier) + mods |= 1 << controlIndex; + if (ke->modifiers() & Qt::AltModifier) + mods |= 1 << altIndex; + qCDebug(qLcWaylandCompositor) << "Keyboard modifier state mismatch detected for event" << ke << "state:" << currentModifierState << "repaired:" << Qt::hex << mods; + send_modifiers(focusResource->handle, compositor()->nextSerial(), mods, + 0, 0, group); + currentModifierState = ke->modifiers(); + } + } +#else + Q_UNUSED(ke); +#endif +} + /*! * Returns the current repeat rate. */ @@ -599,3 +634,5 @@ uint QWaylandKeyboard::keyToScanCode(int qtKey) const } QT_END_NAMESPACE + +#include "moc_qwaylandkeyboard.cpp" |