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