• 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 TQ_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 <private/tqucomextra_p.h>
34#include <tdeapplication.h>
35#include <kdebug.h>
36#include <kkeynative.h>
37
38#ifdef TQ_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
48extern "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)
63static uint g_keyModMaskXAccel = 0;
64static uint g_keyModMaskXOnOrOff = 0;
65
66static 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
80static TQValueList< TDEGlobalAccelPrivate* >* all_accels = 0;
81
82TDEGlobalAccelPrivate::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, TQ_SIGNAL(coreFakeKeyPress(unsigned int)), this, TQ_SLOT(fakeKeyPressed(unsigned int)));
94}
95
96TDEGlobalAccelPrivate::~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
109void TDEGlobalAccelPrivate::setEnabled( bool bEnable )
110{
111 m_bEnabled = bEnable;
112 updateConnections();
113}
114
115void 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
129void TDEGlobalAccelPrivate::disableBlocking( bool block )
130{
131 m_blockingDisabled = block;
132}
133
134bool 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
141void TDEGlobalAccelPrivate::suspend( bool s )
142{
143 m_suspended = s;
144}
145
146bool TDEGlobalAccelPrivate::emitSignal( Signal )
147{
148 return false;
149}
150
151bool TDEGlobalAccelPrivate::connectKey( TDEAccelAction& action, const KKeyServer::Key& key )
152 { return grabKey( key, true, &action ); }
153bool TDEGlobalAccelPrivate::connectKey( const KKeyServer::Key& key )
154 { return grabKey( key, true, 0 ); }
155bool TDEGlobalAccelPrivate::disconnectKey( TDEAccelAction& action, const KKeyServer::Key& key )
156 { return grabKey( key, false, &action ); }
157bool TDEGlobalAccelPrivate::disconnectKey( const KKeyServer::Key& key )
158 { return grabKey( key, false, 0 ); }
159
160bool 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 TQ_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 TQ_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
258bool 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
275void 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
285void 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, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotActivated(int)) );
317 pMenu->exec( TQPoint( 0, 0 ) );
318 disconnect( pMenu, TQ_SIGNAL(activated(int)), this, TQ_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
328bool 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, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotActivated(int)) );
396 pMenu->exec( TQPoint( 0, 0 ) );
397 disconnect( pMenu, TQ_SIGNAL(activated(int)), this, TQ_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
409void 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_QUType_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_QUType_TQString.set(o+1,pAction->name());
434 static_QUType_TQString.set(o+2,pAction->label());
435 static_QUType_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
445void 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 // !TQ_WS_X11
KKeyNative
Representation of a key in the format native of the windowing system (eg.
Definition kkeynative.h:38
KKeySequence
A KKeySequence object holds a sequence of up to 4 keys.
Definition tdeshortcut.h:289
KKey
A KKey object represents a single key with possible modifiers (Shift, Ctrl, Alt, Win).
Definition tdeshortcut.h:41
KXErrorHandler
This class simplifies handling of X errors.
Definition kxerrorhandler.h:58
endl
kndbgstream & endl(kndbgstream &s)
Does nothing.
Definition kdebug.h:583
KKeyServer
A collection of functions for the conversion of key presses and their modifiers from the window syste...
Definition kkeyserver_x11.h:35
KKeyServer::modXModeSwitch
uint modXModeSwitch()
Returns the X11 Mode_switch modifier mask/flag.
KKeyServer::modXShift
uint modXShift()
Returns the X11 Shift modifier mask/flag.
KKeyServer::modXNumLock
uint modXNumLock()
Returns the X11 NumLock modifier mask/flag.
KKeyServer::modXLock
uint modXLock()
Returns the X11 Lock modifier mask/flag.
KKeyServer::accelModMaskX
uint accelModMaskX()
Returns bitwise OR'ed mask containing Shift, Ctrl, Alt, and Win (if available).
KKeyServer::modXAlt
uint modXAlt()
Returns the X11 Alt (Mod1) modifier mask/flag.
KKeyServer::modXScrollLock
uint modXScrollLock()
Returns the X11 ScrollLock modifier mask/flag.
KKeyServer::initializeMods
bool initializeMods()
TODO: please document.
TDEStdAccel::key
int key(StdAccel id)
Definition tdestdaccel.cpp:383
KKeyServer::Key
Represents a key press.
Definition kkeyserver_x11.h:138

tdecore

Skip menu "tdecore"
  • Main Page
  • 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
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.8
This website is maintained by Timothy Pearson.