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

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 }

KDEUI

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal