• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • 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 #include <kapplication.h>
00023 #include <kdebug.h>
00024 
00025 #include "kmodifierkeyinfo.h"
00026 #include "kmodifierkeyinfoprovider_p.h"
00027 
00028 #define XK_MISCELLANY
00029 #define XK_XKB_KEYS
00030 #include <X11/keysymdef.h>
00031 
00032 struct ModifierDefinition
00033 {
00034     ModifierDefinition( Qt::Key _key, unsigned int _mask, const char * _name, KeySym _keysym ) {
00035        key = _key;
00036        mask = _mask;
00037        name = _name;
00038        keysym = _keysym;
00039     }
00040     Qt::Key key;
00041     unsigned int mask;
00042     const char *name; // virtual modifier name
00043     KeySym keysym;
00044 };
00045 
00046 /*
00047  * Get the real modifiers related to a virtual modifier.
00048  */
00049 unsigned int xkbVirtualModifier(XkbDescPtr xkb, const char *name)
00050 {
00051     Q_ASSERT(xkb != 0);
00052 
00053     unsigned int mask = 0;
00054     bool nameEqual;
00055     for (int i = 0; i < XkbNumVirtualMods; ++i) {
00056         char *modStr = XGetAtomName(xkb->dpy, xkb->names->vmods[i]);
00057         if (modStr != 0) {
00058             nameEqual = (strcmp(name, modStr) == 0);
00059             XFree(modStr);
00060             if (nameEqual) {
00061                 XkbVirtualModsToReal(xkb, 1 << i, &mask);
00062                 break;
00063             }
00064         }
00065     }
00066     return mask;
00067 }
00068 
00069 KModifierKeyInfoProvider::KModifierKeyInfoProvider()
00070     : QWidget(0)
00071 {
00072     int code, xkberr, maj, min;
00073     m_xkbAvailable = XkbQueryExtension(QX11Info::display(), &code, &m_xkbEv, &xkberr, &maj, &min);
00074     if (m_xkbAvailable) {
00075         XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd,
00076                         XkbStateNotifyMask | XkbMapNotifyMask,
00077                         XkbStateNotifyMask | XkbMapNotifyMask);
00078         unsigned long int stateMask = XkbModifierStateMask | XkbModifierBaseMask |
00079                                       XkbModifierLatchMask | XkbModifierLockMask |
00080                                       XkbPointerButtonMask;
00081         XkbSelectEventDetails(QX11Info::display(), XkbUseCoreKbd, XkbStateNotifyMask,
00082                               stateMask, stateMask);
00083     }
00084 
00085     xkbUpdateModifierMapping();
00086 
00087     // add known pointer buttons
00088     m_xkbButtons.insert(Qt::LeftButton, Button1Mask);
00089     m_xkbButtons.insert(Qt::MidButton, Button2Mask);
00090     m_xkbButtons.insert(Qt::RightButton, Button3Mask);
00091     m_xkbButtons.insert(Qt::XButton1, Button4Mask);
00092     m_xkbButtons.insert(Qt::XButton2, Button5Mask);
00093 
00094     // get the initial state
00095     if (m_xkbAvailable) {
00096         XkbStateRec state;
00097         XkbGetState(QX11Info::display(), XkbUseCoreKbd, &state);
00098         xkbModifierStateChanged(state.mods, state.latched_mods, state.locked_mods);
00099         xkbButtonStateChanged(state.ptr_buttons);
00100     }
00101 
00102     if (KApplication::kApplication()) {
00103         KApplication::kApplication()->installX11EventFilter(this);
00104     } else {
00105         kDebug() << "KModifierKeyInfo can't be used without KApplication";
00106     }
00107 }
00108 
00109 KModifierKeyInfoProvider::~KModifierKeyInfoProvider()
00110 {
00111 }
00112 
00113 bool KModifierKeyInfoProvider::setKeyLatched(Qt::Key key, bool latched)
00114 {
00115     if (!m_xkbModifiers.contains(key)) return false;
00116 
00117     return XkbLatchModifiers(QX11Info::display(), XkbUseCoreKbd,
00118                              m_xkbModifiers[key], latched ? m_xkbModifiers[key] : 0);
00119 }
00120 
00121 bool KModifierKeyInfoProvider::setKeyLocked(Qt::Key key, bool locked)
00122 {
00123     if (!m_xkbModifiers.contains(key)) return false;
00124 
00125     return XkbLockModifiers(QX11Info::display(), XkbUseCoreKbd,
00126                             m_xkbModifiers[key], locked ? m_xkbModifiers[key] : 0);
00127 }
00128 
00129 bool KModifierKeyInfoProvider::x11Event(XEvent *event)
00130 {
00131     if (m_xkbAvailable) {
00132         XkbEvent *kbevt;
00133         unsigned int stateMask = XkbModifierStateMask | XkbModifierBaseMask |
00134                                  XkbModifierLatchMask | XkbModifierLockMask;
00135         if (event->type == m_xkbEv + XkbEventCode &&
00136             (kbevt = (XkbEvent*)event) != 0)
00137         {
00138             if (kbevt->any.xkb_type == XkbMapNotify) {
00139                 xkbUpdateModifierMapping();
00140             } else if (kbevt->any.xkb_type == XkbStateNotify) {
00141                 XkbStateNotifyEvent *snevent = (XkbStateNotifyEvent*)event;
00142                 if (snevent->changed & stateMask) {
00143                     xkbModifierStateChanged(snevent->mods, snevent->latched_mods,
00144                                             snevent->locked_mods);
00145                 } else if (snevent->changed & XkbPointerButtonMask) {
00146                     xkbButtonStateChanged(snevent->ptr_buttons);
00147                 }
00148             }
00149             return false;
00150         }
00151     }
00152 
00153     return false;
00154 }
00155 
00156 void KModifierKeyInfoProvider::xkbModifierStateChanged(unsigned char mods,
00157                                                        unsigned char latched_mods,
00158                                                        unsigned char locked_mods)
00159 {
00160     // detect keyboard modifiers
00161     ModifierStates oldState;
00162     ModifierStates newState;
00163     
00164     QHash<Qt::Key, unsigned int>::const_iterator it;
00165     QHash<Qt::Key, unsigned int>::const_iterator end = m_xkbModifiers.constEnd();
00166     for (it = m_xkbModifiers.constBegin(); it != end; ++it) {
00167         if (!m_modifierStates.contains(it.key())) continue;
00168         newState = Nothing;
00169         oldState = m_modifierStates[it.key()];
00170 
00171         // determine the new state
00172         if (mods & it.value()) {
00173             newState |= Pressed;
00174         }
00175         if (latched_mods & it.value()) {
00176             newState |= Latched;
00177         }
00178         if (locked_mods & it.value()) {
00179             newState |= Locked;
00180         }
00181 
00182         if (newState != oldState) {
00183             m_modifierStates[it.key()] = newState;
00184 
00185             if ((newState ^ oldState) & Pressed) {
00186                 emit keyPressed(it.key(), newState & Pressed);
00187             }
00188             if ((newState ^ oldState) & Latched) {
00189                 emit keyLatched(it.key(), newState & Latched);
00190             }
00191             if ((newState ^ oldState) & Locked) {
00192                 emit keyLocked(it.key(), newState & Locked);
00193             }
00194         }
00195     }
00196 }
00197 
00198 void KModifierKeyInfoProvider::xkbButtonStateChanged(unsigned short ptr_buttons)
00199 {
00200     // detect mouse button states
00201     bool newButtonState;
00202 
00203     QHash<Qt::MouseButton, unsigned short>::const_iterator it;
00204     QHash<Qt::MouseButton, unsigned short>::const_iterator end = m_xkbButtons.constEnd();
00205     for (it = m_xkbButtons.constBegin(); it != end; ++it) {
00206         newButtonState = (ptr_buttons & it.value());
00207         if (newButtonState != m_buttonStates[it.key()]) {
00208             m_buttonStates[it.key()] = newButtonState;
00209             emit buttonPressed(it.key(), newButtonState);
00210         }
00211     }
00212 }
00213 
00214 void KModifierKeyInfoProvider::xkbUpdateModifierMapping()
00215 {
00216     m_xkbModifiers.clear();
00217 
00218     QList<ModifierDefinition> srcModifiers;
00219     srcModifiers << ModifierDefinition(Qt::Key_Shift, ShiftMask, 0, 0)
00220                  << ModifierDefinition( Qt::Key_Control, ControlMask, 0, 0)
00221                  << ModifierDefinition(Qt::Key_Alt, 0, "Alt", XK_Alt_L)
00222                  // << { 0, 0, I18N_NOOP("Win"), "superkey", "" }
00223                  << ModifierDefinition(Qt::Key_Meta, 0, "Meta", XK_Meta_L)
00224                  << ModifierDefinition(Qt::Key_Super_L, 0, "Super", XK_Super_L)
00225                  << ModifierDefinition(Qt::Key_Hyper_L, 0, "Hyper", XK_Hyper_L)
00226                  << ModifierDefinition(Qt::Key_AltGr, 0, "AltGr", 0)
00227                  << ModifierDefinition(Qt::Key_NumLock, 0, "NumLock", XK_Num_Lock)
00228                  << ModifierDefinition(Qt::Key_CapsLock, LockMask, 0, 0)
00229                  << ModifierDefinition( Qt::Key_ScrollLock, 0, "ScrollLock", XK_Scroll_Lock);
00230 
00231     XkbDescPtr xkb = XkbGetKeyboard(QX11Info::display(), XkbAllComponentsMask, XkbUseCoreKbd);
00232 
00233     QList<ModifierDefinition>::const_iterator it;
00234     QList<ModifierDefinition>::const_iterator end = srcModifiers.constEnd();
00235     for (it = srcModifiers.constBegin(); it != end; ++it) {
00236         unsigned int mask = it->mask;
00237         if (mask == 0 && xkb != 0) {
00238             // try virtual modifier first
00239             if (it->name != 0) {
00240                 mask = xkbVirtualModifier(xkb, it->name);
00241             }
00242             if (mask == 0 && it->keysym != 0) {
00243                 mask = XkbKeysymToModifiers(QX11Info::display(), it->keysym);
00244             } else if (mask == 0) {
00245                 // special case for AltGr
00246                 mask = XkbKeysymToModifiers(QX11Info::display(), XK_Mode_switch) |
00247                        XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Shift) |
00248                        XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Latch) |
00249                        XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Lock);
00250             }
00251         }
00252 
00253         if (mask != 0) {
00254             m_xkbModifiers.insert(it->key, mask);
00255             // previously unknown modifier
00256             if (!m_modifierStates.contains(it->key)) {
00257                 m_modifierStates.insert(it->key, Nothing);
00258                 emit keyAdded(it->key);
00259             }
00260         }
00261     }
00262 
00263     // remove modifiers which are no longer available
00264     QMutableHashIterator<Qt::Key, ModifierStates> i(m_modifierStates);
00265     while (i.hasNext()) {
00266         i.next();
00267         if (!m_xkbModifiers.contains(i.key())) {
00268             Qt::Key key = i.key();
00269             i.remove();
00270             emit keyRemoved(key);
00271         }
00272     }
00273 
00274     if (xkb != 0) {
00275         XkbFreeKeyboard(xkb, 0, true);
00276     }
00277 }

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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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