8#include "kmodifierkeyinfoprovider_xcb.h"
9#include "kmodifierkeyinfo.h"
11#include <QGuiApplication>
15#include <X11/XKBlib.h>
16#include <X11/keysymdef.h>
19struct ModifierDefinition {
20 ModifierDefinition(
Qt::Key _key,
unsigned int _mask,
const char *_name, KeySym _keysym)
36unsigned int xkbVirtualModifier(XkbDescPtr xkb,
const char *name)
38 Q_ASSERT(xkb !=
nullptr);
40 unsigned int mask = 0;
42 for (
int i = 0; i < XkbNumVirtualMods; ++i) {
43 char *modStr = XGetAtomName(xkb->dpy, xkb->names->vmods[i]);
44 if (modStr !=
nullptr) {
45 nameEqual = (strcmp(name, modStr) == 0);
48 XkbVirtualModsToReal(xkb, 1 << i, &mask);
61KModifierKeyInfoProviderXcb::KModifierKeyInfoProviderXcb()
62 : KModifierKeyInfoProvider()
64 , m_xkbAvailable(false)
72 m_xkbAvailable = XkbQueryExtension(display(), &code, &m_xkbEv, &xkberr, &maj, &min);
77 XkbSelectEvents(display(),
79 XkbStateNotifyMask | XkbMapNotifyMask,
80 XkbStateNotifyMask | XkbMapNotifyMask);
82 unsigned long int stateMask = XkbModifierStateMask
84 | XkbModifierLatchMask
86 | XkbPointerButtonMask;
89 XkbSelectEventDetails(display(), XkbUseCoreKbd, XkbStateNotifyMask, stateMask, stateMask);
92 xkbUpdateModifierMapping();
102 if (m_xkbAvailable) {
104 XkbGetState(display(), XkbUseCoreKbd, &state);
105 xkbModifierStateChanged(state.mods, state.latched_mods, state.locked_mods);
106 xkbButtonStateChanged(state.ptr_buttons);
112KModifierKeyInfoProviderXcb::~KModifierKeyInfoProviderXcb()
114 if (m_xkbAvailable) {
119bool KModifierKeyInfoProviderXcb::setKeyLatched(
Qt::Key key,
bool latched)
121 if (!m_xkbModifiers.
contains(key)) {
125 return XkbLatchModifiers(display(), XkbUseCoreKbd, m_xkbModifiers[key], latched ? m_xkbModifiers[key] : 0);
128bool KModifierKeyInfoProviderXcb::setKeyLocked(
Qt::Key key,
bool locked)
130 if (!m_xkbModifiers.
contains(key)) {
134 return XkbLockModifiers(display(), XkbUseCoreKbd, m_xkbModifiers[key], locked ? m_xkbModifiers[key] : 0);
140typedef struct _xcb_xkb_map_notify_event_t {
141 uint8_t response_type;
144 xcb_timestamp_t time;
146 uint8_t ptrBtnActions;
148 xcb_keycode_t minKeyCode;
149 xcb_keycode_t maxKeyCode;
152 xcb_keycode_t firstKeySym;
154 xcb_keycode_t firstKeyAct;
156 xcb_keycode_t firstKeyBehavior;
157 uint8_t nKeyBehavior;
158 xcb_keycode_t firstKeyExplicit;
159 uint8_t nKeyExplicit;
160 xcb_keycode_t firstModMapKey;
162 xcb_keycode_t firstVModMapKey;
163 uint8_t nVModMapKeys;
164 uint16_t virtualMods;
166} _xcb_xkb_map_notify_event_t;
167typedef struct _xcb_xkb_state_notify_event_t {
168 uint8_t response_type;
171 xcb_timestamp_t time;
179 int16_t latchedGroup;
183 uint8_t compatGrabMods;
185 uint8_t compatLoockupMods;
186 uint16_t ptrBtnState;
188 xcb_keycode_t keycode;
190 uint8_t requestMajor;
191 uint8_t requestMinor;
192} _xcb_xkb_state_notify_event_t;
196 uint8_t response_type;
199 xcb_timestamp_t time;
202 _xcb_xkb_map_notify_event_t map_notify;
203 _xcb_xkb_state_notify_event_t state_notify;
207bool KModifierKeyInfoProviderXcb::nativeEventFilter(
const QByteArray &eventType,
void *message, qintptr *)
209 if (!m_xkbAvailable || eventType !=
"xcb_generic_event_t") {
212 xcb_generic_event_t *
event =
static_cast<xcb_generic_event_t *
>(message);
213 if ((
event->response_type & ~0x80) == m_xkbEv + XkbEventCode) {
214 _xkb_event *kbevt =
reinterpret_cast<_xkb_event *
>(
event);
215 unsigned int stateMask = XkbModifierStateMask | XkbModifierBaseMask | XkbModifierLatchMask | XkbModifierLockMask;
216 if (kbevt->any.xkbType == XkbMapNotify) {
217 xkbUpdateModifierMapping();
218 }
else if (kbevt->any.xkbType == XkbStateNotify) {
219 if (kbevt->state_notify.changed & stateMask) {
220 xkbModifierStateChanged(kbevt->state_notify.mods, kbevt->state_notify.latchedMods, kbevt->state_notify.lockedMods);
221 }
else if (kbevt->state_notify.changed & XkbPointerButtonMask) {
222 xkbButtonStateChanged(kbevt->state_notify.ptrBtnState);
229void KModifierKeyInfoProviderXcb::xkbModifierStateChanged(
unsigned char mods,
unsigned char latched_mods,
unsigned char locked_mods)
232 ModifierStates newState;
236 for (it = m_xkbModifiers.
constBegin(); it != end; ++it) {
237 if (!m_modifierStates.contains(it.key())) {
243 if (mods & it.value()) {
246 if (latched_mods & it.value()) {
249 if (locked_mods & it.value()) {
253 stateUpdated(it.key(), newState);
257void KModifierKeyInfoProviderXcb::xkbButtonStateChanged(
unsigned short ptr_buttons)
264 for (it = m_xkbButtons.
constBegin(); it != end; ++it) {
265 newButtonState = (ptr_buttons & it.value());
266 if (newButtonState != m_buttonStates[it.key()]) {
267 m_buttonStates[it.key()] = newButtonState;
268 Q_EMIT buttonPressed(it.key(), newButtonState);
273void KModifierKeyInfoProviderXcb::xkbUpdateModifierMapping()
275 if (!m_xkbAvailable) {
278 m_xkbModifiers.
clear();
282 srcModifiers << ModifierDefinition(
Qt::Key_Shift, ShiftMask,
nullptr, 0)
284 << ModifierDefinition(
Qt::Key_Alt, 0,
"Alt", XK_Alt_L)
286 << ModifierDefinition(
Qt::Key_Meta, 0,
"Meta", XK_Meta_L)
295 XkbDescPtr xkb = XkbGetKeyboard(display(), XkbAllComponentsMask, XkbUseCoreKbd);
299 for (it = srcModifiers.
constBegin(); it != end; ++it) {
300 unsigned int mask = it->mask;
301 if (mask == 0 && xkb !=
nullptr) {
303 if (it->name !=
nullptr) {
304 mask = xkbVirtualModifier(xkb, it->name);
306 if (mask == 0 && it->keysym != 0) {
307 mask = XkbKeysymToModifiers(display(), it->keysym);
308 }
else if (mask == 0) {
311 mask = XkbKeysymToModifiers(display(), XK_Mode_switch)
312 | XkbKeysymToModifiers(display(), XK_ISO_Level3_Shift)
313 | XkbKeysymToModifiers(display(), XK_ISO_Level3_Latch)
314 | XkbKeysymToModifiers(display(), XK_ISO_Level3_Lock);
320 m_xkbModifiers.
insert(it->key, mask);
322 if (!m_modifierStates.contains(it->key)) {
323 m_modifierStates.insert(it->key, Nothing);
324 Q_EMIT keyAdded(it->key);
331 while (i.hasNext()) {
333 if (!m_xkbModifiers.
contains(i.key())) {
336 Q_EMIT keyRemoved(key);
340 if (xkb !=
nullptr) {
341 XkbFreeKeyboard(xkb, 0,
true);
345#include "moc_kmodifierkeyinfoprovider_xcb.cpp"
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
const QList< QKeySequence > & end()
void installNativeEventFilter(QAbstractNativeEventFilter *filterObj)
QCoreApplication * instance()
void removeNativeEventFilter(QAbstractNativeEventFilter *filterObject)
const_iterator constBegin() const const
const_iterator constEnd() const const
bool contains(const Key &key) const const
iterator insert(const Key &key, const T &value)
const_iterator constBegin() const const
const_iterator constEnd() const const