00001 #include <qwindowdefs.h>
00002 #ifdef Q_WS_X11
00003
00004 #include "kglobalaccel_x11.h"
00005 #include "kglobalaccel.h"
00006 #include "kkeyserver_x11.h"
00007
00008 #include <qpopupmenu.h>
00009 #include <qregexp.h>
00010 #include <qwidget.h>
00011 #include <kapplication.h>
00012 #include <kdebug.h>
00013 #include <kkeynative.h>
00014
00015 #include <X11/X.h>
00016 #include <X11/Xlib.h>
00017 #include <X11/keysym.h>
00018
00019 #ifdef KeyPress
00020
00021 const int XKeyPress = KeyPress;
00022 const int XKeyRelease = KeyRelease;
00023 #undef KeyPress
00024 #endif
00025
00026 static bool g_bGrabFailed;
00027
00028 extern "C" {
00029 static int XGrabErrorHandler( Display *, XErrorEvent *e ) {
00030 if ( e->error_code != BadAccess ) {
00031 kdWarning() << "grabKey: got X error " << e->type << " instead of BadAccess\n";
00032 }
00033 g_bGrabFailed = true;
00034 return 0;
00035 }
00036 }
00037
00038
00039
00040
00041
00042
00043
00044 static uint g_keyModMaskXAccel = 0;
00045 static uint g_keyModMaskXOnOrOff = 0;
00046
00047 static void calculateGrabMasks()
00048 {
00049 g_keyModMaskXAccel = KKeyServer::accelModMaskX();
00050 g_keyModMaskXOnOrOff =
00051 KKeyServer::modXLock() |
00052 KKeyServer::modXNumLock() |
00053 KKeyServer::modXScrollLock();
00054
00055
00056 }
00057
00058
00059
00060 KGlobalAccelPrivate::KGlobalAccelPrivate()
00061 : KAccelBase( KAccelBase::NATIVE_KEYS )
00062 {
00063 m_sConfigGroup = "Global Shortcuts";
00064 kapp->installX11EventFilter( this );
00065 }
00066
00067 KGlobalAccelPrivate::~KGlobalAccelPrivate()
00068 {
00069
00070
00071
00072
00073 }
00074
00075 void KGlobalAccelPrivate::setEnabled( bool bEnable )
00076 {
00077 m_bEnabled = bEnable;
00078
00079 };
00080
00081 bool KGlobalAccelPrivate::emitSignal( Signal )
00082 {
00083 return false;
00084 }
00085
00086 bool KGlobalAccelPrivate::connectKey( KAccelAction& action, const KKeyServer::Key& key )
00087 { return grabKey( key, true, &action ); }
00088 bool KGlobalAccelPrivate::connectKey( const KKeyServer::Key& key )
00089 { return grabKey( key, true, 0 ); }
00090 bool KGlobalAccelPrivate::disconnectKey( KAccelAction& action, const KKeyServer::Key& key )
00091 { return grabKey( key, false, &action ); }
00092 bool KGlobalAccelPrivate::disconnectKey( const KKeyServer::Key& key )
00093 { return grabKey( key, false, 0 ); }
00094
00095 bool KGlobalAccelPrivate::grabKey( const KKeyServer::Key& key, bool bGrab, KAccelAction* pAction )
00096 {
00097 if( !key.code() ) {
00098 kdWarning(125) << "KGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key with null code." << endl;
00099 return false;
00100 }
00101
00102
00103 if( g_keyModMaskXOnOrOff == 0 )
00104 calculateGrabMasks();
00105
00106 uchar keyCodeX = key.code();
00107 uint keyModX = key.mod() & g_keyModMaskXAccel;
00108 #ifndef __osf__
00109
00110 kdDebug(125) << QString( "grabKey( key: '%1', bGrab: %2 ): keyCodeX: %3 keyModX: %4\n" )
00111 .arg( key.key().toStringInternal() ).arg( bGrab )
00112 .arg( keyCodeX, 0, 16 ).arg( keyModX, 0, 16 );
00113 #endif
00114 if( !keyCodeX )
00115 return false;
00116
00117
00118 g_bGrabFailed = false;
00119 XSync( qt_xdisplay(), 0 );
00120 XErrorHandler savedErrorHandler = XSetErrorHandler( XGrabErrorHandler );
00121
00122
00123
00124
00125
00126
00127 #ifndef NDEBUG
00128 QString sDebug = QString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
00129 #endif
00130 uint keyModMaskX = ~g_keyModMaskXOnOrOff;
00131 for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
00132 if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
00133 #ifndef NDEBUG
00134 sDebug += QString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
00135 #endif
00136 if( bGrab ) {
00137 if(keyCodeX==115)
00138 XGrabKey( qt_xdisplay(), keyCodeX, irrelevantBitsMask, qt_xrootwin(), True, GrabModeAsync, GrabModeSync );
00139 else
00140 XGrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask, qt_xrootwin(), True, GrabModeAsync, GrabModeSync );
00141
00142
00143 if( g_bGrabFailed ) {
00144 kdDebug(125) << "grab failed!\n";
00145 for( uint m = 0; m < irrelevantBitsMask; m++ )
00146 {
00147 if( m & keyModMaskX == 0 )
00148 {
00149 if(keyCodeX==115)
00150 XUngrabKey( qt_xdisplay(), keyCodeX, m, qt_xrootwin() );
00151 else
00152 XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | m, qt_xrootwin() );
00153 }
00154 }
00155 break;
00156 }
00157 } else
00158 {
00159 if(keyCodeX==115)
00160 XUngrabKey( qt_xdisplay(), keyCodeX,irrelevantBitsMask, qt_xrootwin() );
00161 else
00162 XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask, qt_xrootwin() );
00163 }
00164 }
00165 }
00166 #ifndef NDEBUG
00167 kdDebug(125) << sDebug << endl;
00168 #endif
00169
00170 XSync( qt_xdisplay(), 0 );
00171 XSetErrorHandler( savedErrorHandler );
00172
00173 if( !g_bGrabFailed ) {
00174 CodeMod codemod;
00175 codemod.code = keyCodeX;
00176 codemod.mod = keyModX;
00177 if( key.mod() & KKeyServer::MODE_SWITCH )
00178 codemod.mod |= KKeyServer::MODE_SWITCH;
00179 if(keyCodeX==115)
00180 codemod.mod=0;
00181 if( bGrab )
00182 m_rgCodeModToAction.insert( codemod, pAction );
00183 else
00184 m_rgCodeModToAction.remove( codemod );
00185 }
00186 return !g_bGrabFailed;
00187 }
00188
00189 bool KGlobalAccelPrivate::x11Event( XEvent* pEvent )
00190 {
00191
00192 switch( pEvent->type ) {
00193 case MappingNotify:
00194 x11MappingNotify();
00195 return true;
00196 case XKeyPress:
00197 if( x11KeyPress( pEvent ) )
00198 return true;
00199 default:
00200 return QWidget::x11Event( pEvent );
00201 }
00202 }
00203
00204 void KGlobalAccelPrivate::x11MappingNotify()
00205 {
00206 kdDebug(125) << "KGlobalAccelPrivate::x11MappingNotify()" << endl;
00207 if( m_bEnabled ) {
00208
00209 KKeyServer::initializeMods();
00210 calculateGrabMasks();
00211
00212 updateConnections();
00213 }
00214 }
00215
00216 bool KGlobalAccelPrivate::x11KeyPress( const XEvent *pEvent )
00217 {
00218
00219 if ( !QWidget::keyboardGrabber() && !QApplication::activePopupWidget() )
00220 XUngrabKeyboard( qt_xdisplay(), pEvent->xkey.time );
00221
00222 if( !m_bEnabled )
00223 return false;
00224
00225 CodeMod codemod;
00226 codemod.code = pEvent->xkey.keycode;
00227 codemod.mod = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
00228
00229
00230
00231 if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
00232
00233 uint sym = XKeycodeToKeysym( qt_xdisplay(), codemod.code, 0 );
00234 if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
00235 if( codemod.mod & KKeyServer::modXShift() )
00236 codemod.mod &= ~KKeyServer::modXShift();
00237 else
00238 codemod.mod |= KKeyServer::modXShift();
00239 }
00240 }
00241
00242 KKeyNative keyNative( pEvent );
00243 KKey key = keyNative;
00244 kdDebug(125) << "x11KeyPress: seek " << key.toStringInternal()
00245 << QString( " keyCodeX: %1 state: %2 keyModX: %3" )
00246 .arg( codemod.code, 0, 16 ).arg( pEvent->xkey.state, 0, 16 ).arg( codemod.mod, 0, 16 ) << endl;
00247
00248
00249 if(codemod.code==115 )
00250 {
00251 codemod.mod=0;
00252 key.init("Win");
00253 }
00254
00255 if(!m_rgCodeModToAction.contains( codemod ) ) {
00256 #ifndef NDEBUG
00257 for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
00258 KAccelAction* pAction = *it;
00259 kdDebug(125) << "\tcode: " << QString::number(it.key().code, 16) << " mod: " << QString::number(it.key().mod, 16)
00260 << (pAction ? QString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : QString::null)
00261 << endl;
00262 }
00263 #endif
00264 return false;
00265 }
00266 KAccelAction* pAction = m_rgCodeModToAction[codemod];
00267
00268 if( !pAction ) {
00269 QPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
00270 connect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)) );
00271 pMenu->exec( QPoint( 0, 0 ) );
00272 disconnect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)));
00273 delete pMenu;
00274 } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
00275 return false;
00276 else
00277 activate( pAction, KKeySequence(key) );
00278
00279 return true;
00280 }
00281
00282 void KGlobalAccelPrivate::activate( KAccelAction* pAction, const KKeySequence& seq )
00283 {
00284 kdDebug(125) << "KGlobalAccelPrivate::activate( \"" << pAction->name() << "\" ) " << endl;
00285
00286 QRegExp rexPassIndex( "([ ]*int[ ]*)" );
00287 QRegExp rexPassInfo( " QString" );
00288 QRegExp rexIndex( " ([0-9]+)$" );
00289
00290
00291
00292
00293 if( rexPassIndex.search( pAction->methodSlotPtr() ) >= 0 && rexIndex.search( pAction->name() ) >= 0 ) {
00294 int n = rexIndex.cap(1).toInt();
00295 kdDebug(125) << "Calling " << pAction->methodSlotPtr() << " int = " << n << endl;
00296 connect( this, SIGNAL(activated(int)), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00297 emit activated( n );
00298 disconnect( this, SIGNAL(activated(int)), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00299 } else if( rexPassInfo.search( pAction->methodSlotPtr() ) ) {
00300 connect( this, SIGNAL(activated(const QString&, const QString&, const KKeySequence&)), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00301 emit activated( pAction->name(), pAction->label(), seq );
00302 disconnect( this, SIGNAL(activated(const QString&, const QString&, const KKeySequence&)), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00303 } else {
00304 connect( this, SIGNAL(activated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00305 emit activated();
00306 disconnect( this, SIGNAL(activated()), pAction->objSlotPtr(), pAction->methodSlotPtr() );
00307 }
00308 }
00309
00310 void KGlobalAccelPrivate::slotActivated( int iAction )
00311 {
00312 KAccelAction* pAction = actions().actionPtr( iAction );
00313 if( pAction )
00314 activate( pAction, KKeySequence() );
00315 }
00316
00317 #include "kglobalaccel_x11.moc"
00318
00319 #endif // !Q_WS_X11