00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "config.h"
00021
00022 #include <tqwindowdefs.h>
00023 #ifdef Q_WS_X11
00024
00025 #include "kglobalaccel_x11.h"
00026 #include "kglobalaccel.h"
00027 #include "kkeyserver_x11.h"
00028
00029 #include <tqpopupmenu.h>
00030 #include <tqregexp.h>
00031 #include <tqwidget.h>
00032 #include <tqmetaobject.h>
00033 #include <tqucomextra_p.h>
00034 #include <tdeapplication.h>
00035 #include <kdebug.h>
00036 #include <kkeynative.h>
00037
00038 #ifdef Q_WS_X11
00039 #include <kxerrorhandler.h>
00040 #endif
00041
00042 #include <X11/X.h>
00043 #include <X11/Xlib.h>
00044 #include <X11/XKBlib.h>
00045 #include <X11/keysym.h>
00046 #include <fixx11h.h>
00047
00048 extern "C" {
00049 static int XGrabErrorHandler( Display *, XErrorEvent *e ) {
00050 if ( e->error_code != BadAccess ) {
00051 kdWarning() << "grabKey: got X error " << e->type << " instead of BadAccess\n";
00052 }
00053 return 1;
00054 }
00055 }
00056
00057
00058
00059
00060
00061
00062
00063 static uint g_keyModMaskXAccel = 0;
00064 static uint g_keyModMaskXOnOrOff = 0;
00065
00066 static void calculateGrabMasks()
00067 {
00068 g_keyModMaskXAccel = KKeyServer::accelModMaskX();
00069 g_keyModMaskXOnOrOff =
00070 KKeyServer::modXLock() |
00071 KKeyServer::modXNumLock() |
00072 KKeyServer::modXScrollLock() |
00073 KKeyServer::modXModeSwitch();
00074
00075
00076 }
00077
00078
00079
00080 static TQValueList< TDEGlobalAccelPrivate* >* all_accels = 0;
00081
00082 TDEGlobalAccelPrivate::TDEGlobalAccelPrivate()
00083 : TDEAccelBase( TDEAccelBase::NATIVE_KEYS )
00084 , m_blocked( false )
00085 , m_blockingDisabled( false )
00086 , m_suspended( false )
00087 {
00088 if( all_accels == NULL )
00089 all_accels = new TQValueList< TDEGlobalAccelPrivate* >;
00090 all_accels->append( this );
00091 m_sConfigGroup = "Global Shortcuts";
00092 kapp->installX11EventFilter( this );
00093 connect(kapp, TQT_SIGNAL(coreFakeKeyPress(unsigned int)), this, TQT_SLOT(fakeKeyPressed(unsigned int)));
00094 }
00095
00096 TDEGlobalAccelPrivate::~TDEGlobalAccelPrivate()
00097 {
00098
00099
00100
00101
00102 all_accels->remove( this );
00103 if( all_accels->count() == 0 ) {
00104 delete all_accels;
00105 all_accels = NULL;
00106 }
00107 }
00108
00109 void TDEGlobalAccelPrivate::setEnabled( bool bEnable )
00110 {
00111 m_bEnabled = bEnable;
00112 updateConnections();
00113 }
00114
00115 void TDEGlobalAccelPrivate::blockShortcuts( bool block )
00116 {
00117 if( all_accels == NULL )
00118 return;
00119 for( TQValueList< TDEGlobalAccelPrivate* >::ConstIterator it = all_accels->begin();
00120 it != all_accels->end();
00121 ++it ) {
00122 if( (*it)->m_blockingDisabled )
00123 continue;
00124 (*it)->m_blocked = block;
00125 (*it)->updateConnections();
00126 }
00127 }
00128
00129 void TDEGlobalAccelPrivate::disableBlocking( bool block )
00130 {
00131 m_blockingDisabled = block;
00132 }
00133
00134 bool TDEGlobalAccelPrivate::isEnabledInternal() const
00135 {
00136 return TDEAccelBase::isEnabled() && !m_blocked;
00137 }
00138
00139
00140
00141 void TDEGlobalAccelPrivate::suspend( bool s )
00142 {
00143 m_suspended = s;
00144 }
00145
00146 bool TDEGlobalAccelPrivate::emitSignal( Signal )
00147 {
00148 return false;
00149 }
00150
00151 bool TDEGlobalAccelPrivate::connectKey( TDEAccelAction& action, const KKeyServer::Key& key )
00152 { return grabKey( key, true, &action ); }
00153 bool TDEGlobalAccelPrivate::connectKey( const KKeyServer::Key& key )
00154 { return grabKey( key, true, 0 ); }
00155 bool TDEGlobalAccelPrivate::disconnectKey( TDEAccelAction& action, const KKeyServer::Key& key )
00156 { return grabKey( key, false, &action ); }
00157 bool TDEGlobalAccelPrivate::disconnectKey( const KKeyServer::Key& key )
00158 { return grabKey( key, false, 0 ); }
00159
00160 bool TDEGlobalAccelPrivate::grabKey( const KKeyServer::Key& key, bool bGrab, TDEAccelAction* pAction )
00161 {
00162 if( !key.code() ) {
00163 kdWarning(125) << "TDEGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key with null code." << endl;
00164 return false;
00165 }
00166
00167
00168 if( g_keyModMaskXOnOrOff == 0 ) {
00169 calculateGrabMasks();
00170 }
00171
00172 uchar keyCodeX = key.code();
00173 uint keyModX = key.mod() & g_keyModMaskXAccel;
00174
00175
00176
00177 if( key.sym() == XK_Sys_Req && XkbKeycodeToKeysym( tqt_xdisplay(), 111, 0, 0 ) == XK_Print ) {
00178 keyModX |= KKeyServer::modXAlt();
00179 keyCodeX = 111;
00180 }
00181
00182
00183 if ((key.mod() & KKeyServer::MODE_SWITCH) && (!(g_keyModMaskXAccel & KKeyServer::MODE_SWITCH))) {
00184
00185
00186 kdWarning(125) << "TDEGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key requiring ISO_Level3_Shift (AltGr) sequence." << endl;
00187 return false;
00188 }
00189
00190 #ifndef __osf__
00191
00192 kdDebug(125) << TQString(TQString( "grabKey( key: '%1', bGrab: %2 ): keyCodeX: %3 keyModX: %4\n" )
00193 .arg( key.key().toStringInternal() ).arg( bGrab )
00194 .arg( keyCodeX, 0, 16 ).arg( keyModX, 0, 16 ));
00195 #endif
00196 if( !keyCodeX ) {
00197 return false;
00198 }
00199
00200 #ifdef Q_WS_X11
00201 KXErrorHandler handler( XGrabErrorHandler );
00202 #endif
00203
00204
00205
00206
00207
00208 #ifndef NDEBUG
00209 TQString sDebug = TQString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
00210 #endif
00211 uint keyModMaskX = ~g_keyModMaskXOnOrOff;
00212 for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
00213 if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
00214 #ifndef NDEBUG
00215 sDebug += TQString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
00216 #endif
00217 if( bGrab )
00218 XGrabKey( tqt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask,
00219 tqt_xrootwin(), True, GrabModeAsync, GrabModeSync );
00220 else
00221 XUngrabKey( tqt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask, tqt_xrootwin() );
00222 }
00223 }
00224 #ifndef NDEBUG
00225 kdDebug(125) << sDebug << endl;
00226 #endif
00227
00228 bool failed = false;
00229 if( bGrab ) {
00230 #ifdef Q_WS_X11
00231 failed = handler.error( true );
00232 #endif
00233
00234 if( failed ) {
00235 kdDebug(125) << "grab failed!\n";
00236 for( uint m = 0; m <= 0xff; m++ ) {
00237 if(( m & keyModMaskX ) == 0 )
00238 XUngrabKey( tqt_xdisplay(), keyCodeX, keyModX | m, tqt_xrootwin() );
00239 }
00240 }
00241 }
00242 if( !failed )
00243 {
00244 CodeMod codemod;
00245 codemod.code = keyCodeX;
00246 codemod.mod = keyModX;
00247 if( key.mod() & KKeyServer::MODE_SWITCH )
00248 codemod.mod |= KKeyServer::MODE_SWITCH;
00249
00250 if( bGrab )
00251 m_rgCodeModToAction.insert( codemod, pAction );
00252 else
00253 m_rgCodeModToAction.remove( codemod );
00254 }
00255 return !failed;
00256 }
00257
00258 bool TDEGlobalAccelPrivate::x11Event( XEvent* pEvent )
00259 {
00260
00261 switch( pEvent->type ) {
00262 case MappingNotify:
00263 XRefreshKeyboardMapping( &pEvent->xmapping );
00264 x11MappingNotify();
00265 return false;
00266 case XKeyPress:
00267 if( x11KeyPress( pEvent ) ) {
00268 return true;
00269 }
00270 default:
00271 return TQWidget::x11Event( pEvent );
00272 }
00273 }
00274
00275 void TDEGlobalAccelPrivate::x11MappingNotify()
00276 {
00277 kdDebug(125) << "TDEGlobalAccelPrivate::x11MappingNotify()" << endl;
00278
00279 KKeyServer::initializeMods();
00280 calculateGrabMasks();
00281
00282 updateConnections();
00283 }
00284
00285 void TDEGlobalAccelPrivate::fakeKeyPressed(unsigned int keyCode) {
00286 CodeMod codemod;
00287 codemod.code = keyCode;
00288 codemod.mod = 0;
00289
00290 KKey key(keyCode, 0);
00291
00292 kdDebug(125) << "fakeKeyPressed: seek " << key.toStringInternal()
00293 << TQString(TQString( " keyCodeX: %1 keyCode: %2 keyModX: %3" )
00294 .arg( codemod.code, 0, 16 ).arg( keyCode, 0, 16 ).arg( codemod.mod, 0, 16 )) << endl;
00295
00296
00297 if( !m_rgCodeModToAction.contains( codemod ) ) {
00298 #ifndef NDEBUG
00299 for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
00300 TDEAccelAction* pAction = *it;
00301 kdDebug(125) << "\tcode: " << TQString::number(it.key().code, 16) << " mod: " << TQString::number(it.key().mod, 16)
00302 << (pAction ? TQString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : TQString())
00303 << endl;
00304 }
00305 #endif
00306 return;
00307 }
00308
00309 TDEAccelAction* pAction = m_rgCodeModToAction[codemod];
00310
00311 if( !pAction ) {
00312 static bool recursion_block = false;
00313 if( !recursion_block ) {
00314 recursion_block = true;
00315 TQPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
00316 connect( pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotActivated(int)) );
00317 pMenu->exec( TQPoint( 0, 0 ) );
00318 disconnect( pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotActivated(int)));
00319 delete pMenu;
00320 recursion_block = false;
00321 }
00322 } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
00323 return;
00324 else
00325 activate( pAction, KKeySequence(key) );
00326 }
00327
00328 bool TDEGlobalAccelPrivate::x11KeyPress( const XEvent *pEvent )
00329 {
00330
00331 if ( !TQWidget::keyboardGrabber() && !TQApplication::activePopupWidget() ) {
00332 XUngrabKeyboard( tqt_xdisplay(), pEvent->xkey.time );
00333 XFlush( tqt_xdisplay());
00334 }
00335
00336 if( !isEnabledInternal() || m_suspended ) {
00337 return false;
00338 }
00339
00340 CodeMod codemod;
00341 codemod.code = pEvent->xkey.keycode;
00342 codemod.mod = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
00343
00344
00345
00346 if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
00347
00348 uint sym = XkbKeycodeToKeysym( tqt_xdisplay(), codemod.code, 0, 0 );
00349
00350 if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
00351 switch( sym ) {
00352
00353
00354 case XK_KP_Multiply:
00355 case XK_KP_Add:
00356 case XK_KP_Subtract:
00357 case XK_KP_Divide:
00358 break;
00359 default:
00360 if( codemod.mod & KKeyServer::modXShift() )
00361 codemod.mod &= ~KKeyServer::modXShift();
00362 else
00363 codemod.mod |= KKeyServer::modXShift();
00364 }
00365 }
00366 }
00367
00368 KKeyNative keyNative( pEvent );
00369 KKey key = keyNative;
00370
00371 kdDebug(125) << "x11KeyPress: seek " << key.toStringInternal()
00372 << TQString(TQString( " keyCodeX: %1 state: %2 keyModX: %3" )
00373 .arg( codemod.code, 0, 16 ).arg( pEvent->xkey.state, 0, 16 ).arg( codemod.mod, 0, 16 )) << endl;
00374
00375
00376 if( !m_rgCodeModToAction.contains( codemod ) ) {
00377 #ifndef NDEBUG
00378 for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
00379 TDEAccelAction* pAction = *it;
00380 kdDebug(125) << "\tcode: " << TQString::number(it.key().code, 16) << " mod: " << TQString::number(it.key().mod, 16)
00381 << (pAction ? TQString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : TQString())
00382 << endl;
00383 }
00384 #endif
00385 return false;
00386 }
00387
00388 TDEAccelAction* pAction = m_rgCodeModToAction[codemod];
00389
00390 if( !pAction ) {
00391 static bool recursion_block = false;
00392 if( !recursion_block ) {
00393 recursion_block = true;
00394 TQPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
00395 connect( pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotActivated(int)) );
00396 pMenu->exec( TQPoint( 0, 0 ) );
00397 disconnect( pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotActivated(int)));
00398 delete pMenu;
00399 recursion_block = false;
00400 }
00401 } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
00402 return false;
00403 else
00404 activate( pAction, KKeySequence(key) );
00405
00406 return true;
00407 }
00408
00409 void TDEGlobalAccelPrivate::activate( TDEAccelAction* pAction, const KKeySequence& seq )
00410 {
00411 kdDebug(125) << "TDEGlobalAccelPrivate::activate( \"" << pAction->name() << "\" ) " << endl;
00412
00413 TQRegExp rexPassIndex( "([ ]*int[ ]*)" );
00414 TQRegExp rexPassInfo( " TQString" );
00415 TQRegExp rexIndex( " ([0-9]+)$" );
00416
00417
00418
00419
00420 if( rexPassIndex.search( pAction->methodSlotPtr() ) >= 0 && rexIndex.search( pAction->name() ) >= 0 ) {
00421 int n = rexIndex.cap(1).toInt();
00422 kdDebug(125) << "Calling " << pAction->methodSlotPtr() << " int = " << n << endl;
00423 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00424 if( slot_id >= 0 ) {
00425 TQUObject o[2];
00426 static_TQUType_int.set(o+1,n);
00427 const_cast< TQObject* >( pAction->objSlotPtr())->tqt_invoke( slot_id, o );
00428 }
00429 } else if( rexPassInfo.search( pAction->methodSlotPtr() ) ) {
00430 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00431 if( slot_id >= 0 ) {
00432 TQUObject o[4];
00433 static_TQUType_TQString.set(o+1,pAction->name());
00434 static_TQUType_TQString.set(o+2,pAction->label());
00435 static_TQUType_ptr.set(o+3,&seq);
00436 const_cast< TQObject* >( pAction->objSlotPtr())->tqt_invoke( slot_id, o );
00437 }
00438 } else {
00439 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00440 if( slot_id >= 0 )
00441 const_cast< TQObject* >( pAction->objSlotPtr())->tqt_invoke( slot_id, 0 );
00442 }
00443 }
00444
00445 void TDEGlobalAccelPrivate::slotActivated( int iAction )
00446 {
00447 TDEAccelAction* pAction = TDEAccelBase::actions().actionPtr( iAction );
00448 if( pAction )
00449 activate( pAction, KKeySequence() );
00450 }
00451
00452 #include "kglobalaccel_x11.moc"
00453
00454 #endif // !Q_WS_X11