2
** cairo-dock-keybinder.c
3
** Login : <ctaf42@localhost.localdomain>
4
** Started on Thu Jan 31 03:57:17 2008 Cedric GESTES
8
** - Cedric GESTES <ctaf42@gmail.com>
12
** Copyright (C) 2008 Cedric GESTES
13
** This program is free software; you can redistribute it and/or modify
14
** it under the terms of the GNU General Public License as published by
15
** the Free Software Foundation; either version 3 of the License, or
16
** (at your option) any later version.
18
** This program is distributed in the hope that it will be useful,
19
** but WITHOUT ANY WARRANTY; without even the implied warranty of
20
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
** GNU General Public License for more details.
23
** You should have received a copy of the GNU General Public License
24
** along with this program; if not, write to the Free Software
25
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
* imported from tomboy_keybinder.c
31
#include <sys/types.h>
33
#include <gdk/gdkwindow.h>
37
#include <X11/extensions/XTest.h>
40
#include "eggaccelerators.h"
41
#include "cairo-dock-log.h"
42
#include "cairo-dock-X-utilities.h"
43
#include "cairo-dock-keybinder.h"
45
typedef unsigned int uint;
46
typedef struct _Binding {
47
CDBindkeyHandler handler;
54
static GSList *bindings = NULL;
55
static guint32 last_event_time = 0;
56
static gboolean processing_event = FALSE;
58
static guint num_lock_mask=0, caps_lock_mask=0, scroll_lock_mask=0;
61
lookup_ignorable_modifiers (GdkKeymap *keymap)
63
egg_keymap_resolve_virtual_modifiers (keymap,
64
EGG_VIRTUAL_LOCK_MASK,
67
egg_keymap_resolve_virtual_modifiers (keymap,
68
EGG_VIRTUAL_NUM_LOCK_MASK,
71
egg_keymap_resolve_virtual_modifiers (keymap,
72
EGG_VIRTUAL_SCROLL_LOCK_MASK,
77
grab_ungrab_with_ignorable_modifiers (GdkWindow *rootwin,
81
guint mod_masks [] = {
82
0, /* modifier only */
86
num_lock_mask | caps_lock_mask,
87
num_lock_mask | scroll_lock_mask,
88
caps_lock_mask | scroll_lock_mask,
89
num_lock_mask | caps_lock_mask | scroll_lock_mask,
93
for (i = 0; i < G_N_ELEMENTS (mod_masks); i++) {
95
XGrabKey (GDK_WINDOW_XDISPLAY (rootwin),
97
binding->modifiers | mod_masks [i],
98
GDK_WINDOW_XWINDOW (rootwin),
103
XUngrabKey (GDK_WINDOW_XDISPLAY (rootwin),
105
binding->modifiers | mod_masks [i],
106
GDK_WINDOW_XWINDOW (rootwin));
112
do_grab_key (Binding *binding)
114
GdkKeymap *keymap = gdk_keymap_get_default ();
115
GdkWindow *rootwin = gdk_get_default_root_window ();
117
EggVirtualModifierType virtual_mods = 0;
120
if (keymap == NULL || rootwin == NULL)
123
if (!egg_accelerator_parse_virtual (binding->keystring,
128
cd_debug ("Got accel %d, %d", keysym, virtual_mods);
130
binding->keycode = XKeysymToKeycode (GDK_WINDOW_XDISPLAY (rootwin),
132
if (binding->keycode == 0)
135
cd_debug ("Got keycode %d", binding->keycode);
137
egg_keymap_resolve_virtual_modifiers (keymap,
139
&binding->modifiers);
141
cd_debug ("Got modmask %d", binding->modifiers);
143
gdk_error_trap_push ();
145
grab_ungrab_with_ignorable_modifiers (rootwin,
151
if (gdk_error_trap_pop ()) {
152
g_warning ("Binding '%s' failed!", binding->keystring);
160
do_ungrab_key (Binding *binding)
162
GdkWindow *rootwin = gdk_get_default_root_window ();
164
cd_debug ("Removing grab for '%s'", binding->keystring);
166
grab_ungrab_with_ignorable_modifiers (rootwin,
173
static GdkFilterReturn
174
filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
176
GdkFilterReturn return_val = GDK_FILTER_CONTINUE;
177
XEvent *xevent = (XEvent *) gdk_xevent;
181
cd_debug ("Got Event! %d, %d", xevent->type, event->type);
183
switch (xevent->type) {
185
cd_debug ("Got KeyPress! keycode: %d, modifiers: %d",
186
xevent->xkey.keycode,
190
* Set the last event time for use when showing
191
* windows to avoid anti-focus-stealing code.
193
processing_event = TRUE;
194
last_event_time = xevent->xkey.time;
196
event_mods = xevent->xkey.state & ~(num_lock_mask |
200
for (iter = bindings; iter != NULL; iter = iter->next) {
201
Binding *binding = (Binding *) iter->data;
203
if (binding->keycode == xevent->xkey.keycode &&
204
binding->modifiers == event_mods) {
206
cd_debug ("Calling handler for '%s'...",
209
(binding->handler) (binding->keystring,
214
processing_event = FALSE;
217
cd_debug ("Got KeyRelease! ");
225
keymap_changed (GdkKeymap *map)
227
GdkKeymap *keymap = gdk_keymap_get_default ();
230
cd_debug ("Keymap changed! Regrabbing keys...");
232
for (iter = bindings; iter != NULL; iter = iter->next) {
233
Binding *binding = (Binding *) iter->data;
234
do_ungrab_key (binding);
237
lookup_ignorable_modifiers (keymap);
239
for (iter = bindings; iter != NULL; iter = iter->next) {
240
Binding *binding = (Binding *) iter->data;
241
do_grab_key (binding);
246
cd_keybinder_init (void)
248
GdkKeymap *keymap = gdk_keymap_get_default ();
249
GdkWindow *rootwin = gdk_get_default_root_window ();
251
lookup_ignorable_modifiers (keymap);
253
gdk_window_add_filter (rootwin,
257
g_signal_connect (keymap,
259
G_CALLBACK (keymap_changed),
264
cd_keybinder_stop (void)
266
GdkKeymap *keymap = gdk_keymap_get_default ();
267
GdkWindow *rootwin = gdk_get_default_root_window ();
269
num_lock_mask=0, caps_lock_mask=0, scroll_lock_mask=0;
271
g_signal_handlers_disconnect_by_func (keymap,
272
G_CALLBACK (keymap_changed),
275
gdk_window_remove_filter (rootwin,
282
cd_keybinder_bind (const char *keystring,
283
CDBindkeyHandler handler,
289
cd_debug ("%s (%s)", __func__, keystring);
292
binding = g_new0 (Binding, 1);
293
binding->keystring = g_strdup (keystring);
294
binding->handler = handler;
295
binding->user_data = user_data;
297
/* Sets the binding's keycode and modifiers */
298
success = do_grab_key (binding);
301
bindings = g_slist_prepend (bindings, binding);
303
cd_warning ("couldnt bind %s", keystring);
304
g_free (binding->keystring);
312
cd_keybinder_unbind (const char *keystring,
313
CDBindkeyHandler handler)
315
cd_debug ("%s (%s)", __func__, keystring);
320
for (iter = bindings; iter != NULL; iter = iter->next) {
321
Binding *binding = (Binding *) iter->data;
323
if (strcmp (keystring, binding->keystring) != 0 ||
324
handler != binding->handler)
327
do_ungrab_key (binding);
329
bindings = g_slist_remove (bindings, binding);
331
g_print (" --- remove key binding '%s'\n", binding->keystring);
332
g_free (binding->keystring);
339
* From eggcellrenderkeys.c.
342
cd_keybinder_is_modifier (guint keycode)
346
XModifierKeymap *mod_keymap;
347
gboolean retval = FALSE;
349
mod_keymap = XGetModifierMapping (gdk_display);
351
map_size = 8 * mod_keymap->max_keypermod;
354
while (i < map_size) {
355
if (keycode == mod_keymap->modifiermap[i]) {
362
XFreeModifiermap (mod_keymap);
368
cd_keybinder_get_current_event_time (void)
370
if (processing_event)
371
return last_event_time;
373
return GDK_CURRENT_TIME;
377
gboolean cairo_dock_simulate_key_sequence (gchar *cKeyString) // the idea was taken from xdo.
380
g_return_val_if_fail (cairo_dock_xtest_is_available (), FALSE);
381
g_return_val_if_fail (cKeyString != NULL, FALSE);
382
cd_message ("%s (%s)", __func__, cKeyString);
385
int *pKeySyms = egg_keystring_to_keysyms (cKeyString, &iNbKeys);
389
Display *dpy = cairo_dock_get_Xdisplay ();
390
for (i = 0; i < iNbKeys; i ++)
392
keycode = XKeysymToKeycode (dpy, pKeySyms[i]);
393
XTestFakeKeyEvent (dpy, keycode, TRUE, CurrentTime); // TRUE <=> presse.
396
for (i = iNbKeys-1; i >=0; i --)
398
keycode = XKeysymToKeycode (dpy, pKeySyms[i]);
399
XTestFakeKeyEvent (dpy, keycode, FALSE, CurrentTime); // TRUE <=> presse.
406
cd_warning ("The dock was not compiled with the support of XTest.");