• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • sources
  • kde-4.14
  • kdelibs
  • kdeui
  • util
kmodifierkeyinfoprovider_x11.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2009 Michael Leupold <lemma@confuego.org>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) version 3, or any
8  later version accepted by the membership of KDE e.V. (or its
9  successor approved by the membership of KDE e.V.), which shall
10  act as a proxy defined in Section 6 of version 3 of the license.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <QX11Info>
22 
23 #include "kmodifierkeyinfo.h"
24 #include "kmodifierkeyinfoprovider_p.h"
25 
26 #define XK_MISCELLANY
27 #define XK_XKB_KEYS
28 #include <X11/keysymdef.h>
29 
30 struct ModifierDefinition
31 {
32  ModifierDefinition( Qt::Key _key, unsigned int _mask, const char * _name, KeySym _keysym ) {
33  key = _key;
34  mask = _mask;
35  name = _name;
36  keysym = _keysym;
37  }
38  Qt::Key key;
39  unsigned int mask;
40  const char *name; // virtual modifier name
41  KeySym keysym;
42 };
43 
44 /*
45  * Get the real modifiers related to a virtual modifier.
46  */
47 unsigned int xkbVirtualModifier(XkbDescPtr xkb, const char *name)
48 {
49  Q_ASSERT(xkb != 0);
50 
51  unsigned int mask = 0;
52  bool nameEqual;
53  for (int i = 0; i < XkbNumVirtualMods; ++i) {
54  char *modStr = XGetAtomName(xkb->dpy, xkb->names->vmods[i]);
55  if (modStr != 0) {
56  nameEqual = (strcmp(name, modStr) == 0);
57  XFree(modStr);
58  if (nameEqual) {
59  XkbVirtualModsToReal(xkb, 1 << i, &mask);
60  break;
61  }
62  }
63  }
64  return mask;
65 }
66 
67 /*
68  * Event filter to receive events from QAbstractEventDispatcher. All X11 events
69  * are forwarded to all providers.
70  */
71 bool kmodifierKeyInfoEventFilter(void *message)
72 {
73  if (KModifierKeyInfoProvider::s_eventFilterEnabled) {
74  XEvent *evt = reinterpret_cast<XEvent*>(message);
75  if (evt) {
76  QSet<KModifierKeyInfoProvider*>::const_iterator it =
77  KModifierKeyInfoProvider::s_providerList.constBegin();
78  QSet<KModifierKeyInfoProvider*>::const_iterator end =
79  KModifierKeyInfoProvider::s_providerList.constEnd();
80  for ( ; it != end; ++it) {
81  if ((*it)->x11Event(evt)) {
82  // providers usually return don't consume events and return false.
83  // If under any circumstance an event is consumed, don't forward it to
84  // other event filters.
85  return true;
86  }
87  }
88  }
89  }
90 
91  if (KModifierKeyInfoProvider::s_nextFilter) {
92  return KModifierKeyInfoProvider::s_nextFilter(message);
93  }
94 
95  return false;
96 }
97 
98 QSet<KModifierKeyInfoProvider*> KModifierKeyInfoProvider::s_providerList;
99 bool KModifierKeyInfoProvider::s_eventFilterInstalled = false;
100 bool KModifierKeyInfoProvider::s_eventFilterEnabled = false;
101 QAbstractEventDispatcher::EventFilter KModifierKeyInfoProvider::s_nextFilter = 0;
102 
103 KModifierKeyInfoProvider::KModifierKeyInfoProvider()
104  : QObject(0)
105 {
106  int code, xkberr, maj, min;
107  m_xkbAvailable = XkbQueryExtension(QX11Info::display(), &code, &m_xkbEv, &xkberr, &maj, &min);
108  if (m_xkbAvailable) {
109  XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd,
110  XkbStateNotifyMask | XkbMapNotifyMask,
111  XkbStateNotifyMask | XkbMapNotifyMask);
112  unsigned long int stateMask = XkbModifierStateMask | XkbModifierBaseMask |
113  XkbModifierLatchMask | XkbModifierLockMask |
114  XkbPointerButtonMask;
115  XkbSelectEventDetails(QX11Info::display(), XkbUseCoreKbd, XkbStateNotifyMask,
116  stateMask, stateMask);
117  }
118 
119  xkbUpdateModifierMapping();
120 
121  // add known pointer buttons
122  m_xkbButtons.insert(Qt::LeftButton, Button1Mask);
123  m_xkbButtons.insert(Qt::MidButton, Button2Mask);
124  m_xkbButtons.insert(Qt::RightButton, Button3Mask);
125  m_xkbButtons.insert(Qt::XButton1, Button4Mask);
126  m_xkbButtons.insert(Qt::XButton2, Button5Mask);
127 
128  // get the initial state
129  if (m_xkbAvailable) {
130  XkbStateRec state;
131  XkbGetState(QX11Info::display(), XkbUseCoreKbd, &state);
132  xkbModifierStateChanged(state.mods, state.latched_mods, state.locked_mods);
133  xkbButtonStateChanged(state.ptr_buttons);
134  }
135 
136  if (!s_eventFilterInstalled) {
137  // This is the first provider constructed. Install the event filter.
138  s_nextFilter = QAbstractEventDispatcher::instance()->setEventFilter(kmodifierKeyInfoEventFilter);
139  s_eventFilterInstalled = true;
140  }
141  s_eventFilterEnabled = true;
142  s_providerList.insert(this);
143 }
144 
145 KModifierKeyInfoProvider::~KModifierKeyInfoProvider()
146 {
147  s_providerList.remove(this);
148  if (s_providerList.isEmpty()) {
149  // disable filtering events
150  s_eventFilterEnabled = false;
151  }
152 }
153 
154 bool KModifierKeyInfoProvider::setKeyLatched(Qt::Key key, bool latched)
155 {
156  if (!m_xkbModifiers.contains(key)) return false;
157 
158  return XkbLatchModifiers(QX11Info::display(), XkbUseCoreKbd,
159  m_xkbModifiers[key], latched ? m_xkbModifiers[key] : 0);
160 }
161 
162 bool KModifierKeyInfoProvider::setKeyLocked(Qt::Key key, bool locked)
163 {
164  if (!m_xkbModifiers.contains(key)) return false;
165 
166  return XkbLockModifiers(QX11Info::display(), XkbUseCoreKbd,
167  m_xkbModifiers[key], locked ? m_xkbModifiers[key] : 0);
168 }
169 
170 bool KModifierKeyInfoProvider::x11Event(XEvent *event)
171 {
172  if (m_xkbAvailable) {
173  XkbEvent *kbevt;
174  unsigned int stateMask = XkbModifierStateMask | XkbModifierBaseMask |
175  XkbModifierLatchMask | XkbModifierLockMask;
176  if (event->type == m_xkbEv + XkbEventCode &&
177  (kbevt = (XkbEvent*)event) != 0)
178  {
179  if (kbevt->any.xkb_type == XkbMapNotify) {
180  xkbUpdateModifierMapping();
181  } else if (kbevt->any.xkb_type == XkbStateNotify) {
182  XkbStateNotifyEvent *snevent = (XkbStateNotifyEvent*)event;
183  if (snevent->changed & stateMask) {
184  xkbModifierStateChanged(snevent->mods, snevent->latched_mods,
185  snevent->locked_mods);
186  } else if (snevent->changed & XkbPointerButtonMask) {
187  xkbButtonStateChanged(snevent->ptr_buttons);
188  }
189  }
190  return false;
191  }
192  }
193 
194  return false;
195 }
196 
197 void KModifierKeyInfoProvider::xkbModifierStateChanged(unsigned char mods,
198  unsigned char latched_mods,
199  unsigned char locked_mods)
200 {
201  // detect keyboard modifiers
202  ModifierStates oldState;
203  ModifierStates newState;
204 
205  QHash<Qt::Key, unsigned int>::const_iterator it;
206  QHash<Qt::Key, unsigned int>::const_iterator end = m_xkbModifiers.constEnd();
207  for (it = m_xkbModifiers.constBegin(); it != end; ++it) {
208  if (!m_modifierStates.contains(it.key())) continue;
209  newState = Nothing;
210  oldState = m_modifierStates[it.key()];
211 
212  // determine the new state
213  if (mods & it.value()) {
214  newState |= Pressed;
215  }
216  if (latched_mods & it.value()) {
217  newState |= Latched;
218  }
219  if (locked_mods & it.value()) {
220  newState |= Locked;
221  }
222 
223  if (newState != oldState) {
224  m_modifierStates[it.key()] = newState;
225 
226  if ((newState ^ oldState) & Pressed) {
227  emit keyPressed(it.key(), newState & Pressed);
228  }
229  if ((newState ^ oldState) & Latched) {
230  emit keyLatched(it.key(), newState & Latched);
231  }
232  if ((newState ^ oldState) & Locked) {
233  emit keyLocked(it.key(), newState & Locked);
234  }
235  }
236  }
237 }
238 
239 void KModifierKeyInfoProvider::xkbButtonStateChanged(unsigned short ptr_buttons)
240 {
241  // detect mouse button states
242  bool newButtonState;
243 
244  QHash<Qt::MouseButton, unsigned short>::const_iterator it;
245  QHash<Qt::MouseButton, unsigned short>::const_iterator end = m_xkbButtons.constEnd();
246  for (it = m_xkbButtons.constBegin(); it != end; ++it) {
247  newButtonState = (ptr_buttons & it.value());
248  if (newButtonState != m_buttonStates[it.key()]) {
249  m_buttonStates[it.key()] = newButtonState;
250  emit buttonPressed(it.key(), newButtonState);
251  }
252  }
253 }
254 
255 void KModifierKeyInfoProvider::xkbUpdateModifierMapping()
256 {
257  m_xkbModifiers.clear();
258 
259  QList<ModifierDefinition> srcModifiers;
260  srcModifiers << ModifierDefinition(Qt::Key_Shift, ShiftMask, 0, 0)
261  << ModifierDefinition( Qt::Key_Control, ControlMask, 0, 0)
262  << ModifierDefinition(Qt::Key_Alt, 0, "Alt", XK_Alt_L)
263  // << { 0, 0, I18N_NOOP("Win"), "superkey", "" }
264  << ModifierDefinition(Qt::Key_Meta, 0, "Meta", XK_Meta_L)
265  << ModifierDefinition(Qt::Key_Super_L, 0, "Super", XK_Super_L)
266  << ModifierDefinition(Qt::Key_Hyper_L, 0, "Hyper", XK_Hyper_L)
267  << ModifierDefinition(Qt::Key_AltGr, 0, "AltGr", 0)
268  << ModifierDefinition(Qt::Key_NumLock, 0, "NumLock", XK_Num_Lock)
269  << ModifierDefinition(Qt::Key_CapsLock, LockMask, 0, 0)
270  << ModifierDefinition( Qt::Key_ScrollLock, 0, "ScrollLock", XK_Scroll_Lock);
271 
272  XkbDescPtr xkb = XkbGetKeyboard(QX11Info::display(), XkbAllComponentsMask, XkbUseCoreKbd);
273 
274  QList<ModifierDefinition>::const_iterator it;
275  QList<ModifierDefinition>::const_iterator end = srcModifiers.constEnd();
276  for (it = srcModifiers.constBegin(); it != end; ++it) {
277  unsigned int mask = it->mask;
278  if (mask == 0 && xkb != 0) {
279  // try virtual modifier first
280  if (it->name != 0) {
281  mask = xkbVirtualModifier(xkb, it->name);
282  }
283  if (mask == 0 && it->keysym != 0) {
284  mask = XkbKeysymToModifiers(QX11Info::display(), it->keysym);
285  } else if (mask == 0) {
286  // special case for AltGr
287  mask = XkbKeysymToModifiers(QX11Info::display(), XK_Mode_switch) |
288  XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Shift) |
289  XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Latch) |
290  XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Lock);
291  }
292  }
293 
294  if (mask != 0) {
295  m_xkbModifiers.insert(it->key, mask);
296  // previously unknown modifier
297  if (!m_modifierStates.contains(it->key)) {
298  m_modifierStates.insert(it->key, Nothing);
299  emit keyAdded(it->key);
300  }
301  }
302  }
303 
304  // remove modifiers which are no longer available
305  QMutableHashIterator<Qt::Key, ModifierStates> i(m_modifierStates);
306  while (i.hasNext()) {
307  i.next();
308  if (!m_xkbModifiers.contains(i.key())) {
309  Qt::Key key = i.key();
310  i.remove();
311  emit keyRemoved(key);
312  }
313  }
314 
315  if (xkb != 0) {
316  XkbFreeKeyboard(xkb, 0, true);
317  }
318 }
QAbstractEventDispatcher::instance
QAbstractEventDispatcher * instance(QThread *thread)
QAbstractEventDispatcher::EventFilter
typedef EventFilter
QMutableHashIterator
mask
#define mask
QX11Info::display
Display * display()
KStandardAction::name
const char * name(StandardAction id)
This will return the internal name of a given standard action.
Definition: kstandardaction.cpp:223
QSet::const_iterator
QList::const_iterator
kmodifierKeyInfoEventFilter
bool kmodifierKeyInfoEventFilter(void *message)
Definition: kmodifierkeyinfoprovider_x11.cpp:71
QObject
QSet
QList
QHash::const_iterator
xkbVirtualModifier
unsigned int xkbVirtualModifier(XkbDescPtr xkb, const char *name)
Definition: kmodifierkeyinfoprovider_x11.cpp:47
QAbstractEventDispatcher::setEventFilter
EventFilter setEventFilter(EventFilter filter)
QList::constEnd
const_iterator constEnd() const
QList::constBegin
const_iterator constBegin() const
KStandardShortcut::end
const KShortcut & end()
Goto end of the document.
Definition: kstandardshortcut.cpp:348
kmodifierkeyinfo.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:23:59 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal