KDEUI
kmodifierkeyinfoprovider_x11.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright 2009 Michael Leupold <lemma@confuego.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Lesser General Public 00006 License as published by the Free Software Foundation; either 00007 version 2.1 of the License, or (at your option) version 3, or any 00008 later version accepted by the membership of KDE e.V. (or its 00009 successor approved by the membership of KDE e.V.), which shall 00010 act as a proxy defined in Section 6 of version 3 of the license. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License along with this library. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 #include <QX11Info> 00022 00023 #include "kmodifierkeyinfo.h" 00024 #include "kmodifierkeyinfoprovider_p.h" 00025 00026 #define XK_MISCELLANY 00027 #define XK_XKB_KEYS 00028 #include <X11/keysymdef.h> 00029 00030 struct ModifierDefinition 00031 { 00032 ModifierDefinition( Qt::Key _key, unsigned int _mask, const char * _name, KeySym _keysym ) { 00033 key = _key; 00034 mask = _mask; 00035 name = _name; 00036 keysym = _keysym; 00037 } 00038 Qt::Key key; 00039 unsigned int mask; 00040 const char *name; // virtual modifier name 00041 KeySym keysym; 00042 }; 00043 00044 /* 00045 * Get the real modifiers related to a virtual modifier. 00046 */ 00047 unsigned int xkbVirtualModifier(XkbDescPtr xkb, const char *name) 00048 { 00049 Q_ASSERT(xkb != 0); 00050 00051 unsigned int mask = 0; 00052 bool nameEqual; 00053 for (int i = 0; i < XkbNumVirtualMods; ++i) { 00054 char *modStr = XGetAtomName(xkb->dpy, xkb->names->vmods[i]); 00055 if (modStr != 0) { 00056 nameEqual = (strcmp(name, modStr) == 0); 00057 XFree(modStr); 00058 if (nameEqual) { 00059 XkbVirtualModsToReal(xkb, 1 << i, &mask); 00060 break; 00061 } 00062 } 00063 } 00064 return mask; 00065 } 00066 00067 /* 00068 * Event filter to receive events from QAbstractEventDispatcher. All X11 events 00069 * are forwarded to all providers. 00070 */ 00071 bool kmodifierKeyInfoEventFilter(void *message) 00072 { 00073 if (KModifierKeyInfoProvider::s_eventFilterEnabled) { 00074 XEvent *evt = reinterpret_cast<XEvent*>(message); 00075 if (evt) { 00076 QSet<KModifierKeyInfoProvider*>::const_iterator it = 00077 KModifierKeyInfoProvider::s_providerList.constBegin(); 00078 QSet<KModifierKeyInfoProvider*>::const_iterator end = 00079 KModifierKeyInfoProvider::s_providerList.constEnd(); 00080 for ( ; it != end; ++it) { 00081 if ((*it)->x11Event(evt)) { 00082 // providers usually return don't consume events and return false. 00083 // If under any circumstance an event is consumed, don't forward it to 00084 // other event filters. 00085 return true; 00086 } 00087 } 00088 } 00089 } 00090 00091 if (KModifierKeyInfoProvider::s_nextFilter) { 00092 return KModifierKeyInfoProvider::s_nextFilter(message); 00093 } 00094 00095 return false; 00096 } 00097 00098 QSet<KModifierKeyInfoProvider*> KModifierKeyInfoProvider::s_providerList; 00099 bool KModifierKeyInfoProvider::s_eventFilterInstalled = false; 00100 bool KModifierKeyInfoProvider::s_eventFilterEnabled = false; 00101 QAbstractEventDispatcher::EventFilter KModifierKeyInfoProvider::s_nextFilter = 0; 00102 00103 KModifierKeyInfoProvider::KModifierKeyInfoProvider() 00104 : QWidget(0) 00105 { 00106 int code, xkberr, maj, min; 00107 m_xkbAvailable = XkbQueryExtension(QX11Info::display(), &code, &m_xkbEv, &xkberr, &maj, &min); 00108 if (m_xkbAvailable) { 00109 XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd, 00110 XkbStateNotifyMask | XkbMapNotifyMask, 00111 XkbStateNotifyMask | XkbMapNotifyMask); 00112 unsigned long int stateMask = XkbModifierStateMask | XkbModifierBaseMask | 00113 XkbModifierLatchMask | XkbModifierLockMask | 00114 XkbPointerButtonMask; 00115 XkbSelectEventDetails(QX11Info::display(), XkbUseCoreKbd, XkbStateNotifyMask, 00116 stateMask, stateMask); 00117 } 00118 00119 xkbUpdateModifierMapping(); 00120 00121 // add known pointer buttons 00122 m_xkbButtons.insert(Qt::LeftButton, Button1Mask); 00123 m_xkbButtons.insert(Qt::MidButton, Button2Mask); 00124 m_xkbButtons.insert(Qt::RightButton, Button3Mask); 00125 m_xkbButtons.insert(Qt::XButton1, Button4Mask); 00126 m_xkbButtons.insert(Qt::XButton2, Button5Mask); 00127 00128 // get the initial state 00129 if (m_xkbAvailable) { 00130 XkbStateRec state; 00131 XkbGetState(QX11Info::display(), XkbUseCoreKbd, &state); 00132 xkbModifierStateChanged(state.mods, state.latched_mods, state.locked_mods); 00133 xkbButtonStateChanged(state.ptr_buttons); 00134 } 00135 00136 if (!s_eventFilterInstalled) { 00137 // This is the first provider constructed. Install the event filter. 00138 s_nextFilter = QAbstractEventDispatcher::instance()->setEventFilter(kmodifierKeyInfoEventFilter); 00139 s_eventFilterInstalled = true; 00140 } 00141 s_eventFilterEnabled = true; 00142 s_providerList.insert(this); 00143 } 00144 00145 KModifierKeyInfoProvider::~KModifierKeyInfoProvider() 00146 { 00147 s_providerList.remove(this); 00148 if (s_providerList.isEmpty()) { 00149 // disable filtering events 00150 s_eventFilterEnabled = false; 00151 } 00152 } 00153 00154 bool KModifierKeyInfoProvider::setKeyLatched(Qt::Key key, bool latched) 00155 { 00156 if (!m_xkbModifiers.contains(key)) return false; 00157 00158 return XkbLatchModifiers(QX11Info::display(), XkbUseCoreKbd, 00159 m_xkbModifiers[key], latched ? m_xkbModifiers[key] : 0); 00160 } 00161 00162 bool KModifierKeyInfoProvider::setKeyLocked(Qt::Key key, bool locked) 00163 { 00164 if (!m_xkbModifiers.contains(key)) return false; 00165 00166 return XkbLockModifiers(QX11Info::display(), XkbUseCoreKbd, 00167 m_xkbModifiers[key], locked ? m_xkbModifiers[key] : 0); 00168 } 00169 00170 bool KModifierKeyInfoProvider::x11Event(XEvent *event) 00171 { 00172 if (m_xkbAvailable) { 00173 XkbEvent *kbevt; 00174 unsigned int stateMask = XkbModifierStateMask | XkbModifierBaseMask | 00175 XkbModifierLatchMask | XkbModifierLockMask; 00176 if (event->type == m_xkbEv + XkbEventCode && 00177 (kbevt = (XkbEvent*)event) != 0) 00178 { 00179 if (kbevt->any.xkb_type == XkbMapNotify) { 00180 xkbUpdateModifierMapping(); 00181 } else if (kbevt->any.xkb_type == XkbStateNotify) { 00182 XkbStateNotifyEvent *snevent = (XkbStateNotifyEvent*)event; 00183 if (snevent->changed & stateMask) { 00184 xkbModifierStateChanged(snevent->mods, snevent->latched_mods, 00185 snevent->locked_mods); 00186 } else if (snevent->changed & XkbPointerButtonMask) { 00187 xkbButtonStateChanged(snevent->ptr_buttons); 00188 } 00189 } 00190 return false; 00191 } 00192 } 00193 00194 return false; 00195 } 00196 00197 void KModifierKeyInfoProvider::xkbModifierStateChanged(unsigned char mods, 00198 unsigned char latched_mods, 00199 unsigned char locked_mods) 00200 { 00201 // detect keyboard modifiers 00202 ModifierStates oldState; 00203 ModifierStates newState; 00204 00205 QHash<Qt::Key, unsigned int>::const_iterator it; 00206 QHash<Qt::Key, unsigned int>::const_iterator end = m_xkbModifiers.constEnd(); 00207 for (it = m_xkbModifiers.constBegin(); it != end; ++it) { 00208 if (!m_modifierStates.contains(it.key())) continue; 00209 newState = Nothing; 00210 oldState = m_modifierStates[it.key()]; 00211 00212 // determine the new state 00213 if (mods & it.value()) { 00214 newState |= Pressed; 00215 } 00216 if (latched_mods & it.value()) { 00217 newState |= Latched; 00218 } 00219 if (locked_mods & it.value()) { 00220 newState |= Locked; 00221 } 00222 00223 if (newState != oldState) { 00224 m_modifierStates[it.key()] = newState; 00225 00226 if ((newState ^ oldState) & Pressed) { 00227 emit keyPressed(it.key(), newState & Pressed); 00228 } 00229 if ((newState ^ oldState) & Latched) { 00230 emit keyLatched(it.key(), newState & Latched); 00231 } 00232 if ((newState ^ oldState) & Locked) { 00233 emit keyLocked(it.key(), newState & Locked); 00234 } 00235 } 00236 } 00237 } 00238 00239 void KModifierKeyInfoProvider::xkbButtonStateChanged(unsigned short ptr_buttons) 00240 { 00241 // detect mouse button states 00242 bool newButtonState; 00243 00244 QHash<Qt::MouseButton, unsigned short>::const_iterator it; 00245 QHash<Qt::MouseButton, unsigned short>::const_iterator end = m_xkbButtons.constEnd(); 00246 for (it = m_xkbButtons.constBegin(); it != end; ++it) { 00247 newButtonState = (ptr_buttons & it.value()); 00248 if (newButtonState != m_buttonStates[it.key()]) { 00249 m_buttonStates[it.key()] = newButtonState; 00250 emit buttonPressed(it.key(), newButtonState); 00251 } 00252 } 00253 } 00254 00255 void KModifierKeyInfoProvider::xkbUpdateModifierMapping() 00256 { 00257 m_xkbModifiers.clear(); 00258 00259 QList<ModifierDefinition> srcModifiers; 00260 srcModifiers << ModifierDefinition(Qt::Key_Shift, ShiftMask, 0, 0) 00261 << ModifierDefinition( Qt::Key_Control, ControlMask, 0, 0) 00262 << ModifierDefinition(Qt::Key_Alt, 0, "Alt", XK_Alt_L) 00263 // << { 0, 0, I18N_NOOP("Win"), "superkey", "" } 00264 << ModifierDefinition(Qt::Key_Meta, 0, "Meta", XK_Meta_L) 00265 << ModifierDefinition(Qt::Key_Super_L, 0, "Super", XK_Super_L) 00266 << ModifierDefinition(Qt::Key_Hyper_L, 0, "Hyper", XK_Hyper_L) 00267 << ModifierDefinition(Qt::Key_AltGr, 0, "AltGr", 0) 00268 << ModifierDefinition(Qt::Key_NumLock, 0, "NumLock", XK_Num_Lock) 00269 << ModifierDefinition(Qt::Key_CapsLock, LockMask, 0, 0) 00270 << ModifierDefinition( Qt::Key_ScrollLock, 0, "ScrollLock", XK_Scroll_Lock); 00271 00272 XkbDescPtr xkb = XkbGetKeyboard(QX11Info::display(), XkbAllComponentsMask, XkbUseCoreKbd); 00273 00274 QList<ModifierDefinition>::const_iterator it; 00275 QList<ModifierDefinition>::const_iterator end = srcModifiers.constEnd(); 00276 for (it = srcModifiers.constBegin(); it != end; ++it) { 00277 unsigned int mask = it->mask; 00278 if (mask == 0 && xkb != 0) { 00279 // try virtual modifier first 00280 if (it->name != 0) { 00281 mask = xkbVirtualModifier(xkb, it->name); 00282 } 00283 if (mask == 0 && it->keysym != 0) { 00284 mask = XkbKeysymToModifiers(QX11Info::display(), it->keysym); 00285 } else if (mask == 0) { 00286 // special case for AltGr 00287 mask = XkbKeysymToModifiers(QX11Info::display(), XK_Mode_switch) | 00288 XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Shift) | 00289 XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Latch) | 00290 XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Lock); 00291 } 00292 } 00293 00294 if (mask != 0) { 00295 m_xkbModifiers.insert(it->key, mask); 00296 // previously unknown modifier 00297 if (!m_modifierStates.contains(it->key)) { 00298 m_modifierStates.insert(it->key, Nothing); 00299 emit keyAdded(it->key); 00300 } 00301 } 00302 } 00303 00304 // remove modifiers which are no longer available 00305 QMutableHashIterator<Qt::Key, ModifierStates> i(m_modifierStates); 00306 while (i.hasNext()) { 00307 i.next(); 00308 if (!m_xkbModifiers.contains(i.key())) { 00309 Qt::Key key = i.key(); 00310 i.remove(); 00311 emit keyRemoved(key); 00312 } 00313 } 00314 00315 if (xkb != 0) { 00316 XkbFreeKeyboard(xkb, 0, true); 00317 } 00318 }
KDE 4.6 API Reference