Support modifier only shortcuts on X11

Summary:
With this change KWin/X11 reuses Wayland's modifier only shortcut
architecture. The XInput2 event filter also listens for
 * XI_RawKeyPress
 * XI_RawKeyRelease

Those events are also reported if another X11 client grabs keyboard
input. Thus KWin gets all key events, just like on Wayland.

All key events are then sent through the Xkb class which performs the
mapping from key codes to key syms and is able to detect whether the
modifier got pressed/released without another key being pressed.

This change will require a few follow up changes, which are required
also for Wayland:
 * ignore if another input device got interacted (e.g. mouse press,
   touch screen, scroll, etc)
 * use the layout from XServer instead of using our own (needed on
   Wayland in nested setup)

The biggest disadvantage of the change is that it triggers a wake
up of KWin on every key event. But as KWin already listens to all
pointer events that's not a big difference and normally a key event
will wake up the compositor any way.

Reviewers: #plasma

Subscribers: kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D2425
This commit is contained in:
Martin Gräßlin 2016-08-12 15:14:49 +02:00
parent 1eac18a8fd
commit 2c333417fa
2 changed files with 24 additions and 7 deletions

View file

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// kwin
#include <kwinglobals.h>
#include "input.h"
#include "keyboard_input.h"
#include "main.h"
#include "utils.h"
#include "x11eventfilter.h"
@ -42,6 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <X11/Xlib.h>
#if HAVE_X11_XINPUT
#include <X11/extensions/XInput2.h>
#include <X11/extensions/XI2proto.h>
#else
#define XI_RawMotion 0
#endif
@ -263,14 +265,24 @@ class XInputEventFilter : public X11EventFilter
{
public:
XInputEventFilter(X11Cursor *parent, int xi_opcode)
: X11EventFilter(XCB_GE_GENERIC, xi_opcode, QVector<int>{XI_RawMotion, XI_RawButtonPress, XI_RawButtonRelease})
: X11EventFilter(XCB_GE_GENERIC, xi_opcode, QVector<int>{XI_RawMotion, XI_RawButtonPress, XI_RawButtonRelease, XI_RawKeyPress, XI_RawKeyRelease})
, m_x11Cursor(parent)
{}
virtual ~XInputEventFilter() = default;
bool event(xcb_generic_event_t *event) override {
Q_UNUSED(event)
m_x11Cursor->schedulePoll();
xcb_ge_generic_event_t *ge = reinterpret_cast<xcb_ge_generic_event_t *>(event);
switch (ge->event_type) {
case XI_RawKeyPress:
input()->keyboard()->xkb()->updateKey(reinterpret_cast<xXIRawEvent*>(event)->detail - 8, InputRedirection::KeyboardKeyPressed);
break;
case XI_RawKeyRelease:
input()->keyboard()->xkb()->updateKey(reinterpret_cast<xXIRawEvent*>(event)->detail - 8, InputRedirection::KeyboardKeyReleased);
break;
default:
m_x11Cursor->schedulePoll();
break;
}
return false;
}
@ -332,6 +344,7 @@ void X11Cursor::initXInput()
}
m_hasXInput = true;
m_xiOpcode = xi_opcode;
input()->keyboard()->xkb()->reconfigure();
#endif
#endif
}
@ -391,6 +404,8 @@ void X11Cursor::doStartMousePolling()
XISetMask(mask1, XI_RawMotion);
XISetMask(mask1, XI_RawButtonPress);
XISetMask(mask1, XI_RawButtonRelease);
XISetMask(mask1, XI_RawKeyPress);
XISetMask(mask1, XI_RawKeyRelease);
evmasks[0].deviceid = XIAllMasterDevices;
evmasks[0].mask_len = sizeof(mask1);

View file

@ -308,10 +308,12 @@ void Xkb::updateModifiers()
QDBusConnection::sessionBus().asyncCall(msg);
}
waylandServer()->seat()->updateKeyboardModifiers(xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_DEPRESSED)),
xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LATCHED)),
xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LOCKED)),
layout);
if (waylandServer()) {
waylandServer()->seat()->updateKeyboardModifiers(xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_DEPRESSED)),
xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LATCHED)),
xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LOCKED)),
layout);
}
}
xkb_keysym_t Xkb::toKeysym(uint32_t key)