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

KDEUI

  • 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
30struct 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 */
47unsigned 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 */
71bool 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
98QSet<KModifierKeyInfoProvider*> KModifierKeyInfoProvider::s_providerList;
99bool KModifierKeyInfoProvider::s_eventFilterInstalled = false;
100bool KModifierKeyInfoProvider::s_eventFilterEnabled = false;
101QAbstractEventDispatcher::EventFilter KModifierKeyInfoProvider::s_nextFilter = 0;
102
103KModifierKeyInfoProvider::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
145KModifierKeyInfoProvider::~KModifierKeyInfoProvider()
146{
147 s_providerList.remove(this);
148 if (s_providerList.isEmpty()) {
149 // disable filtering events
150 s_eventFilterEnabled = false;
151 }
152}
153
154bool 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
162bool 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
170bool 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
197void 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
239void 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
255void 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}
QHash
QList
QObject
QSet
mask
#define mask
kmodifierkeyinfo.h
kmodifierKeyInfoEventFilter
bool kmodifierKeyInfoEventFilter(void *message)
Definition: kmodifierkeyinfoprovider_x11.cpp:71
xkbVirtualModifier
unsigned int xkbVirtualModifier(XkbDescPtr xkb, const char *name)
Definition: kmodifierkeyinfoprovider_x11.cpp:47
message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
KStandardShortcut::end
const KShortcut & end()
Goto end of the document.
Definition: kstandardshortcut.cpp:348
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 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
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