1
/****************************************************************************
5
Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org>
7
Distributed under the terms of the GNU General Public License version 2.
9
****************************************************************************/
13
#include <config-X11.h>
14
#include "config-khotkeys.h"
22
#include <kactioncollection.h>
24
#include <kkeyserver.h>
26
#include <kapplication.h>
27
#include <kdeversion.h>
30
#include "khotkeysglobal.h"
33
#include <X11/keysym.h>
43
Kbd::Kbd( bool grabbing_enabled_P, QObject* parent_P )
44
: QObject( parent_P ),
45
grabbingEnabled(grabbing_enabled_P)
47
assert( keyboard_handler == NULL );
48
keyboard_handler = this;
49
kga = new KActionCollection( this );
50
connect(kga, SIGNAL(actionTriggered(QAction*)), SLOT(actionTriggered(QAction*)));
55
keyboard_handler = NULL;
58
void Kbd::insert_item( const KShortcut& shortcut_P, Kbd_receiver* receiver_P )
60
Receiver_data& rcv = receivers[ receiver_P ];
61
rcv.shortcuts.append( shortcut_P );
63
grab_shortcut( shortcut_P );
66
void Kbd::remove_item( const KShortcut& shortcut_P, Kbd_receiver* receiver_P )
68
Receiver_data& rcv = receivers[ receiver_P ];
69
rcv.shortcuts.removeAll( shortcut_P );
71
ungrab_shortcut( shortcut_P );
72
if( rcv.shortcuts.count() == 0 )
73
receivers.remove( receiver_P );
76
void Kbd::activate_receiver( Kbd_receiver* receiver_P )
78
Receiver_data& rcv = receivers[ receiver_P ];
82
for( QList< KShortcut >::ConstIterator it( rcv.shortcuts.begin());
83
it != rcv.shortcuts.end();
88
void Kbd::deactivate_receiver( Kbd_receiver* receiver_P )
90
Receiver_data& rcv = receivers[ receiver_P ];
94
for( QList< KShortcut >::ConstIterator it( rcv.shortcuts.begin());
95
it != rcv.shortcuts.end();
97
ungrab_shortcut( *it );
100
void Kbd::grab_shortcut( const KShortcut& shortcut_P )
102
if( grabs.contains( shortcut_P ))
103
++grabs[ shortcut_P ];
106
grabs[ shortcut_P ] = 1;
108
// CHECKME ugly ugly hack
109
QString name = ' ' + QString::number( keycode_P );
110
kga->insertItem( "", name, keycode_P );
111
kga->connectItem( name, this, SLOT( key_slot( int )));
113
QString name = ' ' + shortcut_P.toString();
114
KAction* a = new KAction(name, this);
115
a->setEnabled(grabbingEnabled);
116
kga->addAction( name.toLatin1().constData(), a);
117
a->setGlobalShortcut(shortcut_P);
121
void Kbd::ungrab_shortcut( const KShortcut& shortcut_P )
123
if( !grabs.contains( shortcut_P ))
125
if( --grabs[ shortcut_P ] == 0 )
128
// CHECKME workaround for KGlobalAccel::disconnectItem() not working
129
kga->setItemEnabled( ' ' + QString::number( keycode_P ), false );
130
// kga->disconnectItem( ' ' + QString::number( keycode_P ), NULL, NULL );
131
kga->removeItem( ' ' + QString::number( keycode_P ));
133
delete kga->action( ' ' + shortcut_P.toString());
134
grabs.remove( shortcut_P );
138
void Kbd::actionTriggered(QAction* action)
140
KShortcut shortcut = static_cast<KAction*>(action)->globalShortcut();
141
if( !grabs.contains( shortcut ))
143
for( QHash< Kbd_receiver*, Receiver_data >::ConstIterator it = receivers.begin();
144
it != receivers.end();
146
if( ( *it ).shortcuts.contains( shortcut ) && ( *it ).active
147
&& it.key()->handle_key( shortcut ))
154
} // namespace KHotKeys
155
#include <X11/extensions/XTest.h>
159
static bool xtest_available = false;
160
static bool xtest_inited = false;
164
return xtest_available;
166
int dummy1, dummy2, dummy3, dummy4;
168
( XTestQueryExtension( QX11Info::display(), &dummy1, &dummy2, &dummy3, &dummy4 ) == True );
169
return xtest_available;
173
// CHECKME nevola XFlush(), musi se pak volat rucne
174
bool Kbd::send_macro_key( const QString& key, Window window_P )
182
// TODO fix this, make sure it works even with stuff like "dead_acute"
183
QKeySequence ks( key );
184
if( key == "Enter" && ks.isEmpty() )
185
key = "Return"; // CHECKE hack
186
keyboard_handler->send_macro_key( ks.isEmpty() ? 0 : ks[0], w );
188
bool ok = KKeyServer::keyQtToSymX(keycode, keysym) && KKeyServer::keyQtToModX(keycode, x_mod);
190
KeyCode x_keycode = XKeysymToKeycode( QX11Info::display(), keysym );
191
if( x_keycode == NoSymbol )
194
if( xtest() && window_P == None )
196
// CHECKME tohle jeste potrebuje modifikatory
197
bool ret = XTestFakeKeyEvent( QX11Info::display(), x_keycode, True, CurrentTime );
198
ret = ret && XTestFakeKeyEvent( QX11Info::display(), x_keycode, False, CurrentTime );
202
if( window_P == None || window_P == InputFocus )
203
window_P = windows_handler->active_window();
204
if( window_P == None ) // CHECKME tohle cele je ponekud ...
205
window_P = InputFocus;
208
ev.display = QX11Info::display();
209
ev.window = window_P;
210
ev.root = QX11Info::appRootWindow(); // I don't know whether these have to be set
211
ev.subwindow = None; // to these values, but it seems to work, hmm
212
ev.time = CurrentTime;
217
ev.keycode = x_keycode;
219
ev.same_screen = True;
220
bool ret = XSendEvent( QX11Info::display(), window_P, True, KeyPressMask, ( XEvent* )&ev );
222
ev.type = KeyRelease; // is this actually really needed ??
223
ev.display = QX11Info::display();
224
ev.window = window_P;
225
ev.root = QX11Info::appRootWindow();
227
ev.time = CurrentTime;
233
ev.keycode = x_keycode;
234
ev.same_screen = True;
235
ret = ret && XSendEvent( QX11Info::display(), window_P, True, KeyReleaseMask, ( XEvent* )&ev );
237
// Qt's autorepeat compression is broken and can create "aab" from "aba"
238
// XSync() should create delay longer than Qt's max autorepeat interval
239
XSync( QX11Info::display(), False );
243
bool Mouse::send_mouse_button( int button_P, bool release_P )
248
// CHECKME tohle jeste potrebuje modifikatory
249
// a asi i spravnou timestamp misto CurrentTime
250
bool ret = XTestFakeButtonEvent( QX11Info::display(), button_P, True, CurrentTime );
252
ret = ret && XTestFakeButtonEvent( QX11Info::display(), button_P, False, CurrentTime );
259
} // namespace KHotKeys