kdecore Library API Documentation

kglobalaccel_win.cpp

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., 59 Temple Place - Suite 330,
00017     Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #include "config.h"
00021 
00022 #include <qwindowdefs.h>
00023 #ifdef Q_WS_WIN
00024 
00025 #include "kglobalaccel_win.h"
00026 #include "kglobalaccel.h"
00027 #include "kkeyserver_x11.h"
00028 
00029 #include <qpopupmenu.h>
00030 #include <qregexp.h>
00031 #include <qwidget.h>
00032 #include <qmetaobject.h>
00033 #include <private/qucomextra_p.h>
00034 #include <kapplication.h>
00035 #include <kdebug.h>
00036 #include <kkeynative.h>
00037 
00038 //----------------------------------------------------
00039 
00040 KGlobalAccelPrivate::KGlobalAccelPrivate()
00041 : KAccelBase( KAccelBase::NATIVE_KEYS )
00042 {
00043     m_sConfigGroup = "Global Shortcuts";
00044 //  kapp->installX11EventFilter( this );
00045 }
00046 
00047 KGlobalAccelPrivate::~KGlobalAccelPrivate()
00048 {
00049     // TODO: Need to release all grabbed keys if the main window is not shutting down.
00050     //for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
00051     //  const CodeMod& codemod = it.key();
00052     //}
00053 }
00054 
00055 void KGlobalAccelPrivate::setEnabled( bool bEnable )
00056 {
00057     m_bEnabled = bEnable;
00058     //updateConnections();
00059 }
00060 
00061 bool KGlobalAccelPrivate::emitSignal( Signal )
00062 {
00063     return false;
00064 }
00065 
00066 bool KGlobalAccelPrivate::connectKey( KAccelAction& action, const KKeyServer::Key& key )
00067     { return grabKey( key, true, &action ); }
00068 bool KGlobalAccelPrivate::connectKey( const KKeyServer::Key& key )
00069     { return grabKey( key, true, 0 ); }
00070 bool KGlobalAccelPrivate::disconnectKey( KAccelAction& action, const KKeyServer::Key& key )
00071     { return grabKey( key, false, &action ); }
00072 bool KGlobalAccelPrivate::disconnectKey( const KKeyServer::Key& key )
00073     { return grabKey( key, false, 0 ); }
00074 
00075 bool KGlobalAccelPrivate::grabKey( const KKeyServer::Key& key, bool bGrab, KAccelAction* pAction )
00076 {
00077     /*
00078     if( !key.code() ) {
00079         kdWarning(125) << "KGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key with null code." << endl;
00080         return false;
00081     }
00082 
00083     // Make sure that grab masks have been initialized.
00084     if( g_keyModMaskXOnOrOff == 0 )
00085         calculateGrabMasks();
00086 
00087     uchar keyCodeX = key.code();
00088     uint keyModX = key.mod() & g_keyModMaskXAccel; // Get rid of any non-relevant bits in mod
00089     // HACK: make Alt+Print work
00090     if( key.sym() == XK_Sys_Req ) {
00091         keyModX |= KKeyServer::modXAlt();
00092         keyCodeX = 111;
00093     }
00094 
00095     kdDebug(125) << QString( "grabKey( key: '%1', bGrab: %2 ): keyCodeX: %3 keyModX: %4\n" )
00096         .arg( key.key().toStringInternal() ).arg( bGrab )
00097         .arg( keyCodeX, 0, 16 ).arg( keyModX, 0, 16 );
00098     if( !keyCodeX )
00099         return false;
00100 
00101     // We'll have to grab 8 key modifier combinations in order to cover all
00102     //  combinations of CapsLock, NumLock, ScrollLock.
00103     // Does anyone with more X-savvy know how to set a mask on qt_xrootwin so that
00104     //  the irrelevant bits are always ignored and we can just make one XGrabKey
00105     //  call per accelerator? -- ellis
00106 #ifndef NDEBUG
00107     QString sDebug = QString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
00108 #endif
00109     uint keyModMaskX = ~g_keyModMaskXOnOrOff;
00110     for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
00111         if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
00112 #ifndef NDEBUG
00113             sDebug += QString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
00114 #endif
00115             if( bGrab )
00116                 XGrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask,
00117                     qt_xrootwin(), True, GrabModeAsync, GrabModeSync );
00118             else
00119                 XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask, qt_xrootwin() );
00120         }
00121     }
00122 #ifndef NDEBUG
00123     kdDebug(125) << sDebug << endl;
00124 #endif
00125 
00126         bool failed = false;
00127         if( bGrab ) {
00128 #ifdef Q_WS_X11
00129             failed = handler.error( true ); // sync now
00130 #endif
00131             // If grab failed, then ungrab any grabs that could possibly succeed
00132         if( failed ) {
00133             kdDebug(125) << "grab failed!\n";
00134             for( uint m = 0; m <= 0xff; m++ ) {
00135                 if( m & keyModMaskX == 0 )
00136                     XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | m, qt_xrootwin() );
00137                 }
00138                 }
00139     }
00140         if( !failed )
00141         {
00142         CodeMod codemod;
00143         codemod.code = keyCodeX;
00144         codemod.mod = keyModX;
00145         if( key.mod() & KKeyServer::MODE_SWITCH )
00146             codemod.mod |= KKeyServer::MODE_SWITCH;
00147 
00148         if( bGrab )
00149             m_rgCodeModToAction.insert( codemod, pAction );
00150         else
00151             m_rgCodeModToAction.remove( codemod );
00152     }
00153     return !failed;*/
00154     return false;
00155 }
00156 
00157 /*bool KGlobalAccelPrivate::x11Event( XEvent* pEvent )
00158 {
00159     //kdDebug(125) << "x11EventFilter( type = " << pEvent->type << " )" << endl;
00160     switch( pEvent->type ) {
00161      case MappingNotify:
00162             XRefreshKeyboardMapping( &pEvent->xmapping );
00163         x11MappingNotify();
00164         return false;
00165      case XKeyPress:
00166         if( x11KeyPress( pEvent ) )
00167             return true;
00168      default:
00169         return QWidget::x11Event( pEvent );
00170     }
00171 }
00172 
00173 void KGlobalAccelPrivate::x11MappingNotify()
00174 {
00175     kdDebug(125) << "KGlobalAccelPrivate::x11MappingNotify()" << endl;
00176     if( m_bEnabled ) {
00177         // Maybe the X modifier map has been changed.
00178         KKeyServer::initializeMods();
00179         calculateGrabMasks();
00180         // Do new XGrabKey()s.
00181         updateConnections();
00182     }
00183 }
00184 
00185 bool KGlobalAccelPrivate::x11KeyPress( const XEvent *pEvent )
00186 {
00187     // do not change this line unless you really really know what you are doing (Matthias)
00188     if ( !QWidget::keyboardGrabber() && !QApplication::activePopupWidget() ) {
00189         XUngrabKeyboard( qt_xdisplay(), pEvent->xkey.time );
00190                 XFlush( qt_xdisplay()); // avoid X(?) bug
00191         }
00192 
00193     if( !m_bEnabled )
00194         return false;
00195 
00196     CodeMod codemod;
00197     codemod.code = pEvent->xkey.keycode;
00198     codemod.mod = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
00199 
00200     // If numlock is active and a keypad key is pressed, XOR the SHIFT state.
00201     //  e.g., KP_4 => Shift+KP_Left, and Shift+KP_4 => KP_Left.
00202     if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
00203         // TODO: what's the xor operator in c++?
00204         uint sym = XKeycodeToKeysym( qt_xdisplay(), codemod.code, 0 );
00205         // If this is a keypad key,
00206         if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
00207             switch( sym ) {
00208                 // Leave the following keys unaltered
00209                 // FIXME: The proper solution is to see which keysyms don't change when shifted.
00210                 case XK_KP_Multiply:
00211                 case XK_KP_Add:
00212                 case XK_KP_Subtract:
00213                 case XK_KP_Divide:
00214                     break;
00215                 default:
00216                     if( codemod.mod & KKeyServer::modXShift() )
00217                         codemod.mod &= ~KKeyServer::modXShift();
00218                     else
00219                         codemod.mod |= KKeyServer::modXShift();
00220             }
00221         }
00222     }
00223 
00224     KKeyNative keyNative( pEvent );
00225     KKey key = keyNative;
00226 
00227     kdDebug(125) << "x11KeyPress: seek " << key.toStringInternal()
00228         << QString( " keyCodeX: %1 state: %2 keyModX: %3" )
00229             .arg( codemod.code, 0, 16 ).arg( pEvent->xkey.state, 0, 16 ).arg( codemod.mod, 0, 16 ) << endl;
00230 
00231     // Search for which accelerator activated this event:
00232     if( !m_rgCodeModToAction.contains( codemod ) ) {
00233 #ifndef NDEBUG
00234         for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
00235             KAccelAction* pAction = *it;
00236             kdDebug(125) << "\tcode: " << QString::number(it.key().code, 16) << " mod: " << QString::number(it.key().mod, 16)
00237                 << (pAction ? QString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : QString::null)
00238                 << endl;
00239         }
00240 #endif
00241         return false;
00242     }
00243     KAccelAction* pAction = m_rgCodeModToAction[codemod];
00244 
00245     if( !pAction ) {
00246                 static bool recursion_block = false;
00247                 if( !recursion_block ) {
00248                         recursion_block = true;
00249                 QPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
00250                 connect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)) );
00251                 pMenu->exec( QPoint( 0, 0 ) );
00252                 disconnect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)));
00253                 delete pMenu;
00254                         recursion_block = false;
00255                 }
00256     } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
00257         return false;
00258     else
00259         activate( pAction, KKeySequence(key) );
00260 
00261     return true;
00262 }*/
00263 
00264 void KGlobalAccelPrivate::activate( KAccelAction* pAction, const KKeySequence& seq )
00265 {
00266     kdDebug(125) << "KGlobalAccelPrivate::activate( \"" << pAction->name() << "\" ) " << endl;
00267 
00268     QRegExp rexPassIndex( "([ ]*int[ ]*)" );
00269     QRegExp rexPassInfo( " QString" );
00270     QRegExp rexIndex( " ([0-9]+)$" );
00271 
00272     // If the slot to be called accepts an integer index
00273     //  and an index is present at the end of the action's name,
00274     //  then send the slot the given index #.
00275     if( rexPassIndex.search( pAction->methodSlotPtr() ) >= 0 && rexIndex.search( pAction->name() ) >= 0 ) {
00276         int n = rexIndex.cap(1).toInt();
00277         kdDebug(125) << "Calling " << pAction->methodSlotPtr() << " int = " << n << endl;
00278                 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00279                 if( slot_id >= 0 ) {
00280                     QUObject o[2];
00281                     static_QUType_int.set(o+1,n);
00282                     const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
00283                 }
00284     } else if( rexPassInfo.search( pAction->methodSlotPtr() ) ) {
00285                 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00286                 if( slot_id >= 0 ) {
00287                     QUObject o[4];
00288                     static_QUType_QString.set(o+1,pAction->name());
00289                     static_QUType_QString.set(o+2,pAction->label());
00290                     static_QUType_ptr.set(o+3,&seq);
00291                     const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
00292                 }
00293     } else {
00294                 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00295                 if( slot_id >= 0 )
00296                     const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, 0 );
00297     }
00298 }
00299 
00300 void KGlobalAccelPrivate::slotActivated( int iAction )
00301 {
00302     KAccelAction* pAction = actions().actionPtr( iAction );
00303     if( pAction )
00304         activate( pAction, KKeySequence() );
00305 }
00306 
00307 #include "kglobalaccel_win.moc"
00308 
00309 #endif // !Q_WS_WIN
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 9 07:54:00 2005 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003