Remove not-wanted modifiers prior to evaluating global shortcuts
Summary: When triggering global shortcuts we are more interested in the hold keys than the currently active modifiers. E.g. capslock should not be seen as "shift is hold". Similar we need to remove consumed modifiers. Shift+5 is % and not Shift+% - the shift modifier is consumed and needs to be removed from shortcut evaluation. To support this we need to have the actual state directly from xkbcommon. Thus a new method is added which exposes the modifiers relevant for global shortcut matching. In addition on every key press all consumed modifiers are calculated and kept so that they can be used for shortcut matching. In addition a workaround is added for Backtab. Similar workaround exists in kglobalaccel for X11. The problem is that our shortcuts are stored incorrectly: Shift+Tab instead of Backtab. Thus a mapping back is required. To make everything worse KWin registers the wrong key sequence "Alt+Shift+Backtab" which doesn't make any sense and is broken on X11 at least. The workaround supports both special cases. The one for Backtab should be turned into Shift+Tab and also KWin's special case of adding shift to backtab. CCBUG: 368581 Reviewers: #kwin, #plasma_on_wayland, bshah Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D2768
This commit is contained in:
parent
64126a9717
commit
4235871667
6 changed files with 66 additions and 10 deletions
|
@ -89,7 +89,6 @@ void GlobalShortcutsTest::testConsumedShift()
|
|||
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTSHIFT, timestamp++);
|
||||
QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier);
|
||||
kwinApp()->platform()->keyboardKeyPressed(KEY_5, timestamp++);
|
||||
QEXPECT_FAIL("", "Consumed modifiers are not removed from checking", Continue);
|
||||
QTRY_COMPARE(triggeredSpy.count(), 1);
|
||||
kwinApp()->platform()->keyboardKeyReleased(KEY_5, timestamp++);
|
||||
|
||||
|
|
|
@ -138,7 +138,6 @@ void TabBoxTest::testCapsLock()
|
|||
QCOMPARE(input()->keyboardModifiers(), Qt::NoModifier);
|
||||
QCOMPARE(tabboxClosedSpy.count(), 1);
|
||||
QCOMPARE(TabBox::TabBox::self()->isGrabbed(), false);
|
||||
QEXPECT_FAIL("", "capslock modifies the shortcut to walk back", Continue);
|
||||
QCOMPARE(workspace()->activeClient(), c2);
|
||||
|
||||
surface3.reset();
|
||||
|
|
|
@ -247,16 +247,33 @@ bool processShortcut(Qt::KeyboardModifiers mods, T key, U &shortcuts)
|
|||
bool GlobalShortcutsManager::processKey(Qt::KeyboardModifiers mods, uint32_t key)
|
||||
{
|
||||
if (m_kglobalAccelInterface) {
|
||||
bool retVal = false;
|
||||
int keyQt = 0;
|
||||
if (KKeyServer::symXToKeyQt(key, &keyQt)) {
|
||||
QMetaObject::invokeMethod(m_kglobalAccelInterface,
|
||||
"checkKeyPressed",
|
||||
Qt::DirectConnection,
|
||||
Q_RETURN_ARG(bool, retVal),
|
||||
Q_ARG(int, int(mods) | keyQt));
|
||||
if (retVal) {
|
||||
auto check = [this] (Qt::KeyboardModifiers mods, int keyQt) {
|
||||
bool retVal = false;
|
||||
QMetaObject::invokeMethod(m_kglobalAccelInterface,
|
||||
"checkKeyPressed",
|
||||
Qt::DirectConnection,
|
||||
Q_RETURN_ARG(bool, retVal),
|
||||
Q_ARG(int, int(mods) | keyQt));
|
||||
return retVal;
|
||||
};
|
||||
if (check(mods, keyQt)) {
|
||||
return true;
|
||||
} else if (keyQt == Qt::Key_Backtab) {
|
||||
// KGlobalAccel on X11 has some workaround for Backtab
|
||||
// see kglobalaccel/src/runtime/plugins/xcb/kglobalccel_x11.cpp method x11KeyPress
|
||||
// Apparently KKeySequenceWidget captures Shift+Tab instead of Backtab
|
||||
// thus if the key is backtab we should adjust to add shift again and use tab
|
||||
// in addition KWin registers the shortcut incorrectly as Alt+Shift+Backtab
|
||||
// this should be changed to either Alt+Backtab or Alt+Shift+Tab to match KKeySequenceWidget
|
||||
// trying the variants
|
||||
if (check(mods | Qt::ShiftModifier, keyQt)) {
|
||||
return true;
|
||||
}
|
||||
if (check(mods | Qt::ShiftModifier, Qt::Key_Tab)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -436,7 +436,7 @@ public:
|
|||
}
|
||||
bool keyEvent(QKeyEvent *event) override {
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
return input()->shortcuts()->processKey(event->modifiers(), event->nativeVirtualKey());
|
||||
return input()->shortcuts()->processKey(input()->keyboard()->xkb()->modifiersRelevantForGlobalShortcuts(), event->nativeVirtualKey());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ Xkb::Xkb(InputRedirection *input)
|
|||
, m_altModifier(0)
|
||||
, m_metaModifier(0)
|
||||
, m_modifiers(Qt::NoModifier)
|
||||
, m_consumedModifiers(Qt::NoModifier)
|
||||
, m_keysym(XKB_KEY_NoSymbol)
|
||||
{
|
||||
if (!m_context) {
|
||||
|
@ -295,6 +296,7 @@ void Xkb::updateKey(uint32_t key, InputRedirection::KeyboardKeyState state)
|
|||
}
|
||||
}
|
||||
updateModifiers();
|
||||
updateConsumedModifiers(key);
|
||||
if (state == InputRedirection::KeyboardKeyPressed) {
|
||||
m_modOnlyShortcut.pressCount++;
|
||||
if (m_modOnlyShortcut.pressCount == 1 &&
|
||||
|
@ -368,6 +370,42 @@ void Xkb::updateModifiers()
|
|||
}
|
||||
}
|
||||
|
||||
void Xkb::updateConsumedModifiers(uint32_t key)
|
||||
{
|
||||
Qt::KeyboardModifiers mods = Qt::NoModifier;
|
||||
if (xkb_state_mod_index_is_consumed(m_state, key + 8, m_shiftModifier) == 1) {
|
||||
mods |= Qt::ShiftModifier;
|
||||
}
|
||||
if (xkb_state_mod_index_is_consumed(m_state, key + 8, m_altModifier) == 1) {
|
||||
mods |= Qt::AltModifier;
|
||||
}
|
||||
if (xkb_state_mod_index_is_consumed(m_state, key + 8, m_controlModifier) == 1) {
|
||||
mods |= Qt::ControlModifier;
|
||||
}
|
||||
if (xkb_state_mod_index_is_consumed(m_state, key + 8, m_metaModifier) == 1) {
|
||||
mods |= Qt::MetaModifier;
|
||||
}
|
||||
m_consumedModifiers = mods;
|
||||
}
|
||||
|
||||
Qt::KeyboardModifiers Xkb::modifiersRelevantForGlobalShortcuts() const
|
||||
{
|
||||
Qt::KeyboardModifiers mods = Qt::NoModifier;
|
||||
if (xkb_state_mod_index_is_active(m_state, m_shiftModifier, XKB_STATE_MODS_EFFECTIVE) == 1) {
|
||||
mods |= Qt::ShiftModifier;
|
||||
}
|
||||
if (xkb_state_mod_index_is_active(m_state, m_altModifier, XKB_STATE_MODS_EFFECTIVE) == 1) {
|
||||
mods |= Qt::AltModifier;
|
||||
}
|
||||
if (xkb_state_mod_index_is_active(m_state, m_controlModifier, XKB_STATE_MODS_EFFECTIVE) == 1) {
|
||||
mods |= Qt::ControlModifier;
|
||||
}
|
||||
if (xkb_state_mod_index_is_active(m_state, m_metaModifier, XKB_STATE_MODS_EFFECTIVE) == 1) {
|
||||
mods |= Qt::MetaModifier;
|
||||
}
|
||||
return mods & ~m_consumedModifiers;
|
||||
}
|
||||
|
||||
xkb_keysym_t Xkb::toKeysym(uint32_t key)
|
||||
{
|
||||
if (!m_state) {
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
QString toString(xkb_keysym_t keysym);
|
||||
Qt::Key toQtKey(xkb_keysym_t keysym);
|
||||
Qt::KeyboardModifiers modifiers() const;
|
||||
Qt::KeyboardModifiers modifiersRelevantForGlobalShortcuts() const;
|
||||
bool shouldKeyRepeat(quint32 key) const;
|
||||
|
||||
void switchToNextLayout();
|
||||
|
@ -76,6 +77,7 @@ private:
|
|||
void updateKeymap(xkb_keymap *keymap);
|
||||
void createKeymapFile();
|
||||
void updateModifiers();
|
||||
void updateConsumedModifiers(uint32_t key);
|
||||
InputRedirection *m_input;
|
||||
xkb_context *m_context;
|
||||
xkb_keymap *m_keymap;
|
||||
|
@ -86,6 +88,7 @@ private:
|
|||
xkb_mod_index_t m_altModifier;
|
||||
xkb_mod_index_t m_metaModifier;
|
||||
Qt::KeyboardModifiers m_modifiers;
|
||||
Qt::KeyboardModifiers m_consumedModifiers;
|
||||
xkb_keysym_t m_keysym;
|
||||
struct {
|
||||
uint pressCount = 0;
|
||||
|
|
Loading…
Reference in a new issue