• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kdecore
 

kdecore

  • kdecore
kglobalaccel_x11.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "config.h"
21 
22 #include <tqwindowdefs.h>
23 #ifdef Q_WS_X11
24 
25 #include "kglobalaccel_x11.h"
26 #include "kglobalaccel.h"
27 #include "kkeyserver_x11.h"
28 
29 #include <tqpopupmenu.h>
30 #include <tqregexp.h>
31 #include <tqwidget.h>
32 #include <tqmetaobject.h>
33 #include <tqucomextra_p.h>
34 #include <kapplication.h>
35 #include <kdebug.h>
36 #include <kkeynative.h>
37 
38 #ifdef Q_WS_X11
39 #include <kxerrorhandler.h>
40 #endif
41 
42 #include <X11/X.h>
43 #include <X11/Xlib.h>
44 #include <X11/keysym.h>
45 #include <fixx11h.h>
46 
47 extern "C" {
48  static int XGrabErrorHandler( Display *, XErrorEvent *e ) {
49  if ( e->error_code != BadAccess ) {
50  kdWarning() << "grabKey: got X error " << e->type << " instead of BadAccess\n";
51  }
52  return 1;
53  }
54 }
55 
56 // g_keyModMaskXAccel
57 // mask of modifiers which can be used in shortcuts
58 // (meta, alt, ctrl, shift)
59 // g_keyModMaskXOnOrOff
60 // mask of modifiers where we don't care whether they are on or off
61 // (caps lock, num lock, scroll lock)
62 static uint g_keyModMaskXAccel = 0;
63 static uint g_keyModMaskXOnOrOff = 0;
64 
65 static void calculateGrabMasks()
66 {
67  g_keyModMaskXAccel = KKeyServer::accelModMaskX();
68  g_keyModMaskXOnOrOff =
69  KKeyServer::modXLock() |
70  KKeyServer::modXNumLock() |
71  KKeyServer::modXScrollLock() |
72  KKeyServer::modXModeSwitch();
73  //kdDebug() << "g_keyModMaskXAccel = " << g_keyModMaskXAccel
74  // << "g_keyModMaskXOnOrOff = " << g_keyModMaskXOnOrOff << endl;
75 }
76 
77 //----------------------------------------------------
78 
79 static TQValueList< KGlobalAccelPrivate* >* all_accels = 0;
80 
81 KGlobalAccelPrivate::KGlobalAccelPrivate()
82 : KAccelBase( KAccelBase::NATIVE_KEYS )
83 , m_blocked( false )
84 , m_blockingDisabled( false )
85 , m_suspended( false )
86 {
87  if( all_accels == NULL )
88  all_accels = new TQValueList< KGlobalAccelPrivate* >;
89  all_accels->append( this );
90  m_sConfigGroup = "Global Shortcuts";
91  kapp->installX11EventFilter( this );
92  connect(kapp, TQT_SIGNAL(coreFakeKeyPress(unsigned int)), this, TQT_SLOT(fakeKeyPressed(unsigned int)));
93 }
94 
95 KGlobalAccelPrivate::~KGlobalAccelPrivate()
96 {
97  // TODO: Need to release all grabbed keys if the main window is not shutting down.
98  //for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
99  // const CodeMod& codemod = it.key();
100  //}
101  all_accels->remove( this );
102  if( all_accels->count() == 0 ) {
103  delete all_accels;
104  all_accels = NULL;
105  }
106 }
107 
108 void KGlobalAccelPrivate::setEnabled( bool bEnable )
109 {
110  m_bEnabled = bEnable;
111  updateConnections();
112 }
113 
114 void KGlobalAccelPrivate::blockShortcuts( bool block )
115 {
116  if( all_accels == NULL )
117  return;
118  for( TQValueList< KGlobalAccelPrivate* >::ConstIterator it = all_accels->begin();
119  it != all_accels->end();
120  ++it ) {
121  if( (*it)->m_blockingDisabled )
122  continue;
123  (*it)->m_blocked = block;
124  (*it)->updateConnections();
125  }
126 }
127 
128 void KGlobalAccelPrivate::disableBlocking( bool block )
129 {
130  m_blockingDisabled = block;
131 }
132 
133 bool KGlobalAccelPrivate::isEnabledInternal() const
134 {
135  return KAccelBase::isEnabled() && !m_blocked;
136 }
137 
138 // see #117169 - the bug is hard to reproduce, probably somewhere in X, testcase would be probably
139 // difficult to make, and so on - just don't release the grabs and only ignore the events instead
140 void KGlobalAccelPrivate::suspend( bool s )
141 {
142  m_suspended = s;
143 }
144 
145 bool KGlobalAccelPrivate::emitSignal( Signal )
146 {
147  return false;
148 }
149 
150 bool KGlobalAccelPrivate::connectKey( KAccelAction& action, const KKeyServer::Key& key )
151  { return grabKey( key, true, &action ); }
152 bool KGlobalAccelPrivate::connectKey( const KKeyServer::Key& key )
153  { return grabKey( key, true, 0 ); }
154 bool KGlobalAccelPrivate::disconnectKey( KAccelAction& action, const KKeyServer::Key& key )
155  { return grabKey( key, false, &action ); }
156 bool KGlobalAccelPrivate::disconnectKey( const KKeyServer::Key& key )
157  { return grabKey( key, false, 0 ); }
158 
159 bool KGlobalAccelPrivate::grabKey( const KKeyServer::Key& key, bool bGrab, KAccelAction* pAction )
160 {
161  if( !key.code() ) {
162  kdWarning(125) << "KGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key with null code." << endl;
163  return false;
164  }
165 
166  // Make sure that grab masks have been initialized.
167  if( g_keyModMaskXOnOrOff == 0 ) {
168  calculateGrabMasks();
169  }
170 
171  uchar keyCodeX = key.code();
172  uint keyModX = key.mod() & g_keyModMaskXAccel; // Get rid of any non-relevant bits in mod
173  // HACK: make Alt+Print work
174  // only do this for the Xorg default keyboard keycodes,
175  // other mappings (e.g. evdev) don't need or want it
176  if( key.sym() == XK_Sys_Req && XKeycodeToKeysym( qt_xdisplay(), 111, 0 ) == XK_Print ) {
177  keyModX |= KKeyServer::modXAlt();
178  keyCodeX = 111;
179  }
180  // If the MODE_SWITCH modifier was set in the original key, and was truncated in g_keyModMaskXAccel, XGrabKey will grab the wrong key
181  // See Bug 1676
182  if ((key.mod() & KKeyServer::MODE_SWITCH) && (!(g_keyModMaskXAccel & KKeyServer::MODE_SWITCH))) {
183  // FIXME
184  // Is there any way to make AltGr-based character sequences work with XGrabKey?
185  kdWarning(125) << "KGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key requiring ISO_Level3_Shift (AltGr) sequence." << endl;
186  return false;
187  }
188 
189 #ifndef __osf__
190 // this crashes under Tru64 so .....
191  kdDebug(125) << TQString(TQString( "grabKey( key: '%1', bGrab: %2 ): keyCodeX: %3 keyModX: %4\n" )
192  .arg( key.key().toStringInternal() ).arg( bGrab )
193  .arg( keyCodeX, 0, 16 ).arg( keyModX, 0, 16 ));
194 #endif
195  if( !keyCodeX ) {
196  return false;
197  }
198 
199 #ifdef Q_WS_X11
200  KXErrorHandler handler( XGrabErrorHandler );
201 #endif
202  // We'll have to grab 8 key modifier combinations in order to cover all
203  // combinations of CapsLock, NumLock, ScrollLock.
204  // Does anyone with more X-savvy know how to set a mask on qt_xrootwin so that
205  // the irrelevant bits are always ignored and we can just make one XGrabKey
206  // call per accelerator? -- ellis
207 #ifndef NDEBUG
208  TQString sDebug = TQString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
209 #endif
210  uint keyModMaskX = ~g_keyModMaskXOnOrOff;
211  for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
212  if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
213 #ifndef NDEBUG
214  sDebug += TQString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
215 #endif
216  if( bGrab )
217  XGrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask,
218  qt_xrootwin(), True, GrabModeAsync, GrabModeSync );
219  else
220  XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask, qt_xrootwin() );
221  }
222  }
223 #ifndef NDEBUG
224  kdDebug(125) << sDebug << endl;
225 #endif
226 
227  bool failed = false;
228  if( bGrab ) {
229 #ifdef Q_WS_X11
230  failed = handler.error( true ); // sync now
231 #endif
232  // If grab failed, then ungrab any grabs that could possibly succeed
233  if( failed ) {
234  kdDebug(125) << "grab failed!\n";
235  for( uint m = 0; m <= 0xff; m++ ) {
236  if(( m & keyModMaskX ) == 0 )
237  XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | m, qt_xrootwin() );
238  }
239  }
240  }
241  if( !failed )
242  {
243  CodeMod codemod;
244  codemod.code = keyCodeX;
245  codemod.mod = keyModX;
246  if( key.mod() & KKeyServer::MODE_SWITCH )
247  codemod.mod |= KKeyServer::MODE_SWITCH;
248 
249  if( bGrab )
250  m_rgCodeModToAction.insert( codemod, pAction );
251  else
252  m_rgCodeModToAction.remove( codemod );
253  }
254  return !failed;
255 }
256 
257 bool KGlobalAccelPrivate::x11Event( XEvent* pEvent )
258 {
259  //kdDebug(125) << "x11EventFilter( type = " << pEvent->type << " )" << endl;
260  switch( pEvent->type ) {
261  case MappingNotify:
262  XRefreshKeyboardMapping( &pEvent->xmapping );
263  x11MappingNotify();
264  return false;
265  case XKeyPress:
266  if( x11KeyPress( pEvent ) ) {
267  return true;
268  }
269  default:
270  return TQWidget::x11Event( pEvent );
271  }
272 }
273 
274 void KGlobalAccelPrivate::x11MappingNotify()
275 {
276  kdDebug(125) << "KGlobalAccelPrivate::x11MappingNotify()" << endl;
277  // Maybe the X modifier map has been changed.
278  KKeyServer::initializeMods();
279  calculateGrabMasks();
280  // Do new XGrabKey()s.
281  updateConnections();
282 }
283 
284 void KGlobalAccelPrivate::fakeKeyPressed(unsigned int keyCode) {
285  CodeMod codemod;
286  codemod.code = keyCode;
287  codemod.mod = 0;
288 
289  KKey key(keyCode, 0);
290 
291  kdDebug(125) << "fakeKeyPressed: seek " << key.toStringInternal()
292  << TQString(TQString( " keyCodeX: %1 keyCode: %2 keyModX: %3" )
293  .arg( codemod.code, 0, 16 ).arg( keyCode, 0, 16 ).arg( codemod.mod, 0, 16 )) << endl;
294 
295  // Search for which accelerator activated this event:
296  if( !m_rgCodeModToAction.contains( codemod ) ) {
297 #ifndef NDEBUG
298  for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
299  KAccelAction* pAction = *it;
300  kdDebug(125) << "\tcode: " << TQString::number(it.key().code, 16) << " mod: " << TQString::number(it.key().mod, 16)
301  << (pAction ? TQString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : TQString())
302  << endl;
303  }
304 #endif
305  return;
306  }
307 
308  KAccelAction* pAction = m_rgCodeModToAction[codemod];
309 
310  if( !pAction ) {
311  static bool recursion_block = false;
312  if( !recursion_block ) {
313  recursion_block = true;
314  TQPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
315  connect( pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotActivated(int)) );
316  pMenu->exec( TQPoint( 0, 0 ) );
317  disconnect( pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotActivated(int)));
318  delete pMenu;
319  recursion_block = false;
320  }
321  } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
322  return;
323  else
324  activate( pAction, KKeySequence(key) );
325 }
326 
327 bool KGlobalAccelPrivate::x11KeyPress( const XEvent *pEvent )
328 {
329  // do not change this line unless you really really know what you are doing (Matthias)
330  if ( !TQWidget::keyboardGrabber() && !TQApplication::activePopupWidget() ) {
331  XUngrabKeyboard( qt_xdisplay(), pEvent->xkey.time );
332  XFlush( qt_xdisplay()); // avoid X(?) bug
333  }
334 
335  if( !isEnabledInternal() || m_suspended ) {
336  return false;
337  }
338 
339  CodeMod codemod;
340  codemod.code = pEvent->xkey.keycode;
341  codemod.mod = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
342 
343  // If numlock is active and a keypad key is pressed, XOR the SHIFT state.
344  // e.g., KP_4 => Shift+KP_Left, and Shift+KP_4 => KP_Left.
345  if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
346  // TODO: what's the xor operator in c++?
347  uint sym = XKeycodeToKeysym( qt_xdisplay(), codemod.code, 0 );
348  // If this is a keypad key,
349  if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
350  switch( sym ) {
351  // Leave the following keys unaltered
352  // FIXME: The proper solution is to see which keysyms don't change when shifted.
353  case XK_KP_Multiply:
354  case XK_KP_Add:
355  case XK_KP_Subtract:
356  case XK_KP_Divide:
357  break;
358  default:
359  if( codemod.mod & KKeyServer::modXShift() )
360  codemod.mod &= ~KKeyServer::modXShift();
361  else
362  codemod.mod |= KKeyServer::modXShift();
363  }
364  }
365  }
366 
367  KKeyNative keyNative( pEvent );
368  KKey key = keyNative;
369 
370  kdDebug(125) << "x11KeyPress: seek " << key.toStringInternal()
371  << TQString(TQString( " keyCodeX: %1 state: %2 keyModX: %3" )
372  .arg( codemod.code, 0, 16 ).arg( pEvent->xkey.state, 0, 16 ).arg( codemod.mod, 0, 16 )) << endl;
373 
374  // Search for which accelerator activated this event:
375  if( !m_rgCodeModToAction.contains( codemod ) ) {
376 #ifndef NDEBUG
377  for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
378  KAccelAction* pAction = *it;
379  kdDebug(125) << "\tcode: " << TQString::number(it.key().code, 16) << " mod: " << TQString::number(it.key().mod, 16)
380  << (pAction ? TQString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : TQString())
381  << endl;
382  }
383 #endif
384  return false;
385  }
386 
387  KAccelAction* pAction = m_rgCodeModToAction[codemod];
388 
389  if( !pAction ) {
390  static bool recursion_block = false;
391  if( !recursion_block ) {
392  recursion_block = true;
393  TQPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
394  connect( pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotActivated(int)) );
395  pMenu->exec( TQPoint( 0, 0 ) );
396  disconnect( pMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotActivated(int)));
397  delete pMenu;
398  recursion_block = false;
399  }
400  } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
401  return false;
402  else
403  activate( pAction, KKeySequence(key) );
404 
405  return true;
406 }
407 
408 void KGlobalAccelPrivate::activate( KAccelAction* pAction, const KKeySequence& seq )
409 {
410  kdDebug(125) << "KGlobalAccelPrivate::activate( \"" << pAction->name() << "\" ) " << endl;
411 
412  TQRegExp rexPassIndex( "([ ]*int[ ]*)" );
413  TQRegExp rexPassInfo( " TQString" );
414  TQRegExp rexIndex( " ([0-9]+)$" );
415 
416  // If the slot to be called accepts an integer index
417  // and an index is present at the end of the action's name,
418  // then send the slot the given index #.
419  if( rexPassIndex.search( pAction->methodSlotPtr() ) >= 0 && rexIndex.search( pAction->name() ) >= 0 ) {
420  int n = rexIndex.cap(1).toInt();
421  kdDebug(125) << "Calling " << pAction->methodSlotPtr() << " int = " << n << endl;
422  int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
423  if( slot_id >= 0 ) {
424  TQUObject o[2];
425  static_TQUType_int.set(o+1,n);
426  const_cast< TQObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
427  }
428  } else if( rexPassInfo.search( pAction->methodSlotPtr() ) ) {
429  int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
430  if( slot_id >= 0 ) {
431  TQUObject o[4];
432  static_TQUType_TQString.set(o+1,pAction->name());
433  static_TQUType_TQString.set(o+2,pAction->label());
434  static_TQUType_ptr.set(o+3,&seq);
435  const_cast< TQObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
436  }
437  } else {
438  int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
439  if( slot_id >= 0 )
440  const_cast< TQObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, 0 );
441  }
442 }
443 
444 void KGlobalAccelPrivate::slotActivated( int iAction )
445 {
446  KAccelAction* pAction = KAccelBase::actions().actionPtr( iAction );
447  if( pAction )
448  activate( pAction, KKeySequence() );
449 }
450 
451 #include "kglobalaccel_x11.moc"
452 
453 #endif // !Q_WS_X11
KKeyServer::Key::key
KKey key() const
Converts this Key to a KKey.
KKeyServer
A collection of functions for the conversion of key presses and their modifiers from the window syste...
Definition: kkeyserver_x11.h:34
KKeyServer::modXNumLock
uint modXNumLock()
Returns the X11 NumLock modifier mask/flag.
KKeyServer::modXScrollLock
uint modXScrollLock()
Returns the X11 ScrollLock modifier mask/flag.
KKeyServer::modXAlt
uint modXAlt()
Returns the X11 Alt (Mod1) modifier mask/flag.
KKeyServer::modXModeSwitch
uint modXModeSwitch()
Returns the X11 Mode_switch modifier mask/flag.
KKeyServer::modXShift
uint modXShift()
Returns the X11 Shift modifier mask/flag.
KKeySequence
A KKeySequence object holds a sequence of up to 4 keys.
Definition: kshortcut.h:288
KGlobal::kdWarning
kdbgstream kdWarning(int area=0)
Definition: kdebug.cpp:370
KXErrorHandler
This class simplifies handling of X errors.
Definition: kxerrorhandler.h:57
KKeyServer::initializeMods
bool initializeMods()
TODO: please document.
KKeyServer::Key::sym
uint sym() const
Returns the symbol of the key.
Definition: kkeyserver_x11.h:186
KKeyServer::modXLock
uint modXLock()
Returns the X11 Lock modifier mask/flag.
KKeyNative
Representation of a key in the format native of the windowing system (eg.
Definition: kkeynative.h:37
KKey
A KKey object represents a single key with possible modifiers (Shift, Ctrl, Alt, Win).
Definition: kshortcut.h:40
KKey::toStringInternal
TQString toStringInternal() const
Returns an untranslated text representation of the key in the form "modifier+key", suitable e.g.
Definition: kshortcut.cpp:179
KKeyServer::Key::mod
uint mod() const
Returns the modifiers of the key.
Definition: kkeyserver_x11.h:180
KKeyServer::Key
Represents a key press.
Definition: kkeyserver_x11.h:137
endl
kndbgstream & endl(kndbgstream &s)
Does nothing.
Definition: kdebug.h:583
KKeyServer::Key::code
uint code() const
Returns the code of the key.
Definition: kkeyserver_x11.h:174
KKeyServer::accelModMaskX
uint accelModMaskX()
Returns bitwise OR&#39;ed mask containing Shift, Ctrl, Alt, and Win (if available).
KGlobalAccel::updateConnections
bool updateConnections()
Updates the connections of the accelerations after changing them.
Definition: kglobalaccel.cpp:90

kdecore

Skip menu "kdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdecore

Skip menu "kdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdecore by doxygen 1.8.11
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |