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