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

KDEUI

kglobalaccel_x11.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002     Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Library General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to
00016     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017     Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kglobalaccel_x11.h"
00021 
00022 #include <config.h>
00023 
00024 #include <QtGui/QWidgetList>
00025 
00026 #include "kaction.h"
00027 #include "kdedglobalaccel.h"
00028 #include "kkeyserver_x11.h"
00029 
00030 #include <kapplication.h>
00031 #include <kdebug.h>
00032 
00033 #include <QtCore/QRegExp>
00034 #include <QtGui/QWidget>
00035 #include <QtCore/QMetaClassInfo>
00036 #include <QtGui/QMenu>
00037 
00038 #include <kxerrorhandler.h>
00039 
00040 #include <X11/X.h>
00041 #include <X11/Xlib.h>
00042 #include <X11/Xutil.h>
00043 #include <X11/keysym.h>
00044 #include <fixx11h.h>
00045 
00046 extern "C" {
00047   static int XGrabErrorHandler( Display *, XErrorEvent *e ) {
00048     if ( e->error_code != BadAccess ) {
00049         kWarning() << "grabKey: got X error " << e->type << " instead of BadAccess\n";
00050     }
00051     return 1;
00052   }
00053 }
00054 
00055 // g_keyModMaskXAccel
00056 //  mask of modifiers which can be used in shortcuts
00057 //  (meta, alt, ctrl, shift)
00058 // g_keyModMaskXOnOrOff
00059 //  mask of modifiers where we don't care whether they are on or off
00060 //  (caps lock, num lock, scroll lock)
00061 static uint g_keyModMaskXAccel = 0;
00062 static uint g_keyModMaskXOnOrOff = 0;
00063 
00064 static void calculateGrabMasks()
00065 {
00066     g_keyModMaskXAccel = KKeyServer::accelModMaskX();
00067     g_keyModMaskXOnOrOff =
00068             KKeyServer::modXLock() |
00069             KKeyServer::modXNumLock() |
00070             KKeyServer::modXScrollLock() |
00071             KKeyServer::modXModeSwitch();
00072     //kDebug() << "g_keyModMaskXAccel = " << g_keyModMaskXAccel
00073     //  << "g_keyModMaskXOnOrOff = " << g_keyModMaskXOnOrOff << endl;
00074 }
00075 
00076 //----------------------------------------------------
00077 
00078 KGlobalAccelImpl::KGlobalAccelImpl(KdedGlobalAccel *owner)
00079     : m_owner(owner)
00080 {
00081     calculateGrabMasks();
00082 }
00083 
00084 bool KGlobalAccelImpl::grabKey( int keyQt, bool grab )
00085 {
00086     if( !keyQt ) {
00087         kWarning(125) << "Tried to grab key with null code.";
00088         return false;
00089     }
00090 
00091     int keyCodeX;
00092     uint keyModX;
00093     KKeyServer::keyQtToCodeX(keyQt, &keyCodeX);
00094     KKeyServer::keyQtToModX(keyQt, &keyModX);
00095 
00096     keyModX &= g_keyModMaskXAccel; // Get rid of any non-relevant bits in mod
00097     
00098     // HACK: make Alt+Print work
00099     // only do this for the Xorg default keyboard keycodes,
00100     // other mappings (e.g. evdev) don't need or want it
00101     if( keyCodeX == XK_Sys_Req && XKeycodeToKeysym( QX11Info::display(), 111, 0 ) == XK_Print ) {
00102         keyModX |= KKeyServer::modXAlt();
00103         keyCodeX = 111;
00104     }
00105 
00106     if( !keyCodeX )
00107         return false;
00108 
00109     kDebug(125) << "grabKey keyQt " << (keyQt & ~Qt::KeyboardModifierMask)
00110         << " mod " << (keyQt & Qt::KeyboardModifierMask) << " ( key: '" << QKeySequence(keyQt).toString()
00111         << "', grab: " << grab << " ): keyCodeX: " << keyCodeX << " keyModX: " << keyModX << endl;
00112 
00113     KXErrorHandler handler( XGrabErrorHandler );
00114 
00115     // We'll have to grab 8 key modifier combinations in order to cover all
00116     //  combinations of CapsLock, NumLock, ScrollLock.
00117     // Does anyone with more X-savvy know how to set a mask on QX11Info::appRootWindow so that
00118     //  the irrelevant bits are always ignored and we can just make one XGrabKey
00119     //  call per accelerator? -- ellis
00120 #ifndef NDEBUG
00121     QString sDebug = QString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
00122 #endif
00123     uint keyModMaskX = ~g_keyModMaskXOnOrOff;
00124     for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
00125         if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
00126 #ifndef NDEBUG
00127             sDebug += QString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
00128 #endif
00129             if( grab )
00130                 XGrabKey( QX11Info::display(), keyCodeX, keyModX | irrelevantBitsMask,
00131                     QX11Info::appRootWindow(), True, GrabModeAsync, GrabModeSync );
00132             else
00133                 XUngrabKey( QX11Info::display(), keyCodeX, keyModX | irrelevantBitsMask, QX11Info::appRootWindow() );
00134         }
00135     }
00136 
00137 #ifndef NDEBUG
00138     kDebug(125) << sDebug;
00139 #endif
00140 
00141     bool failed = false;
00142     if( grab ) {
00143         failed = handler.error( true ); // sync now
00144         if( failed ) {
00145             kDebug(125) << "grab failed!\n";
00146             for( uint m = 0; m <= 0xff; m++ ) {
00147                 if(( m & keyModMaskX ) == 0 )
00148                     XUngrabKey( QX11Info::display(), keyCodeX, keyModX | m, QX11Info::appRootWindow() );
00149                 }
00150             }
00151     }
00152     
00153     return !failed;
00154 }
00155 
00156 bool KGlobalAccelImpl::x11Event( XEvent* event )
00157 {
00158     switch( event->type ) {
00159         case MappingNotify:
00160             XRefreshKeyboardMapping(&event->xmapping);
00161             x11MappingNotify();
00162             return true;
00163 
00164          case XKeyPress:
00165             if( x11KeyPress( event ) )
00166                 return true;
00167             break;
00168     }
00169     return false;
00170 }
00171 
00172 void KGlobalAccelImpl::x11MappingNotify()
00173 {
00174     kDebug(125) << "KGlobalAccelImpl::x11MappingNotify()";
00175     // Maybe the X modifier map has been changed.
00176     uint oldKeyModMaskXAccel = g_keyModMaskXAccel;
00177     uint oldKeyModMaskXOnOrOff = g_keyModMaskXOnOrOff;
00178 
00179     KKeyServer::initializeMods();
00180     calculateGrabMasks();
00181     
00182 #if 0   //### investigate!
00183     if (oldKeyModMaskXAccel != g_keyModMaskXAccel || oldKeyModMaskXOnOrOff != g_keyModMaskXOnOrOff)
00184         // Do new XGrabKey()s.
00185         m_owner->regrabKeys();
00186 #endif
00187 }
00188 
00189 bool KGlobalAccelImpl::x11KeyPress( const XEvent *pEvent )
00190 {
00191     // Keyboard needs to be ungrabed after XGrabKey() activates the grab, otherwise
00192         // it becomes frozen. There is a chance this will ungrab even when it should
00193         // not, if some code calls XGrabKeyboard() directly, but doing so in kded
00194         // should be very unlikely, and probably stupid.
00195         // If this code is again moved out of kded for some reason, this needs
00196         // to be revisited (I'm pretty sure this used to break KWin).
00197     if( !QWidget::keyboardGrabber() && !QApplication::activePopupWidget()) {
00198         XUngrabKeyboard( QX11Info::display(), pEvent->xkey.time );
00199         XFlush( QX11Info::display()); // avoid X(?) bug
00200     }
00201 
00202     uchar keyCodeX = pEvent->xkey.keycode;
00203     uint keyModX = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
00204 
00205     KeySym keySym;
00206     XLookupString( (XKeyEvent*) pEvent, 0, 0, &keySym, 0 );
00207     uint keySymX = (uint)keySym;
00208 
00209     // If numlock is active and a keypad key is pressed, XOR the SHIFT state.
00210     //  e.g., KP_4 => Shift+KP_Left, and Shift+KP_4 => KP_Left.
00211     if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
00212         uint sym = XKeycodeToKeysym( QX11Info::display(), keyCodeX, 0 );
00213         // If this is a keypad key,
00214         if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
00215             switch( sym ) {
00216                 // Leave the following keys unaltered
00217                 // FIXME: The proper solution is to see which keysyms don't change when shifted.
00218                 case XK_KP_Multiply:
00219                 case XK_KP_Add:
00220                 case XK_KP_Subtract:
00221                 case XK_KP_Divide:
00222                     break;
00223                 default:
00224                     keyModX ^= KKeyServer::modXShift();
00225             }
00226         }
00227     }
00228 
00229     int keyCodeQt;
00230     int keyModQt;
00231     KKeyServer::symXToKeyQt(keySymX, &keyCodeQt);
00232     KKeyServer::modXToQt(keyModX, &keyModQt);
00233     
00234     int keyQt = keyCodeQt | keyModQt;
00235     
00236     kDebug(125) << "Qt " << keyQt << " [Key: " << keyCodeQt << " Mod: " << keyModQt << "] X [Key: " << keySymX << " Mod: " << keyModX << "]";
00237 
00238     // All that work for this hey... argh...
00239     if (m_owner->keyPressed(keyQt))
00240         return true;
00241 
00242     return false;
00243 }
00244 
00245 void KGlobalAccelImpl::setEnabled( bool enable )
00246 {
00247     if (enable) {
00248         kapp->installX11EventFilter( this );
00249     } else
00250         kapp->removeX11EventFilter( this );
00251 }
00252 
00253 
00254 #include "kglobalaccel_x11.moc"

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
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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