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

tdecore

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

tdecore

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

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.