desktop-client.c 22.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 
 * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
 * Copyright (C) 2010-2011 Red Hat, Inc.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
Daiki Ueno's avatar
Daiki Ueno committed
18
19
20
21
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif  /* HAVE_CONFIG_H */

22
#include <libxklavier/xklavier.h>
Daiki Ueno's avatar
Daiki Ueno committed
23
24

#ifdef HAVE_CSPI
25
#include <cspi/spi.h>
Daiki Ueno's avatar
Daiki Ueno committed
26
27
#endif  /* HAVE_CSPI */

28
29
#include <gdk/gdkx.h>

Daiki Ueno's avatar
Daiki Ueno committed
30
31
32
#ifdef HAVE_FAKEKEY
#include <fakekey/fakekey.h>
#endif  /* HAVE_FAKEKEY */
33
34
35

#include "eek/eek.h"
#include "eek/eek-xkl.h"
36
#include "eekboard/eekboard.h"
37
#include "desktop-client.h"
Daiki Ueno's avatar
Daiki Ueno committed
38
#include "xklutil.h"
39
40
41
42
43
44
45

#define CSW 640
#define CSH 480

enum {
    PROP_0,
    PROP_CONNECTION,
Daiki Ueno's avatar
Daiki Ueno committed
46
    PROP_EEKBOARD,
47
    PROP_CONTEXT,
48
49
50
    PROP_LAST
};

51
typedef struct _EekboardDesktopClientClass EekboardDesktopClientClass;
52

53
struct _EekboardDesktopClient {
54
55
    GObject parent;

56
    EekboardEekboard *eekboard;
57
    EekboardContext *context;
58

59
    EekKeyboard *keyboard;
60
    GdkDisplay *display;
61
62
63
    XklEngine *xkl_engine;
    XklConfigRegistry *xkl_config_registry;

64
65
    gulong xkl_config_changed_handler;
    gulong xkl_state_changed_handler;
66

67
68
    gulong key_pressed_handler;
    gulong key_released_handler;
69

Daiki Ueno's avatar
Daiki Ueno committed
70
#ifdef HAVE_CSPI
71
72
    AccessibleEventListener *focus_listener;
    AccessibleEventListener *keystroke_listener;
Daiki Ueno's avatar
Daiki Ueno committed
73
74
75
76
77
#endif  /* HAVE_CSPI */

#ifdef HAVE_FAKEKEY
    FakeKey *fakekey;
#endif  /* HAVE_FAKEKEY */
78
79
};

80
struct _EekboardDesktopClientClass {
81
82
83
    GObjectClass parent_class;
};

84
G_DEFINE_TYPE (EekboardDesktopClient, eekboard_desktop_client, G_TYPE_OBJECT);
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

static GdkFilterReturn filter_xkl_event  (GdkXEvent                 *xev,
                                          GdkEvent                  *event,
                                          gpointer                   user_data);
static void            on_xkl_config_changed
                                         (XklEngine                 *xklengine,
                                          gpointer                   user_data);

static void            on_xkl_state_changed
                                         (XklEngine                 *xklengine,
                                          XklEngineStateChange       type,
                                          gint                       value,
                                          gboolean                   restore,
                                          gpointer                   user_data);

Daiki Ueno's avatar
Daiki Ueno committed
100
#ifdef HAVE_CSPI
101
102
103
104
105
106
static SPIBoolean      focus_listener_cb (const AccessibleEvent     *event,
                                          void                      *user_data);

static SPIBoolean      keystroke_listener_cb
                                         (const AccessibleKeystroke *stroke,
                                          void                      *user_data);
Daiki Ueno's avatar
Daiki Ueno committed
107
#endif  /* HAVE_CSPI */
108
109
110
111
112
static gboolean        set_keyboard      (EekboardDesktopClient     *client,
                                          gboolean                   show,
                                          const gchar               *model,
                                          const gchar               *layouts,
                                          const gchar               *options);
113
114

static void
115
eekboard_desktop_client_set_property (GObject      *object,
116
117
118
119
                                      guint         prop_id,
                                      const GValue *value,
                                      GParamSpec   *pspec)
{
120
    EekboardDesktopClient *client = EEKBOARD_DESKTOP_CLIENT(object);
121
122
123
124
125
    GDBusConnection *connection;

    switch (prop_id) {
    case PROP_CONNECTION:
        connection = g_value_get_object (value);
126

127
        client->eekboard = eekboard_eekboard_new (connection, NULL);
Daiki Ueno's avatar
Daiki Ueno committed
128
129
130
131
132
133
134
135
136
137
138
139
140
        if (client->eekboard != NULL) {
            client->context =
                eekboard_eekboard_create_context (client->eekboard,
                                                  "eekboard-desktop-client",
                                                  NULL);
            if (client->context == NULL) {
                g_object_unref (client->eekboard);
                client->eekboard = NULL;
            } else
                eekboard_eekboard_push_context (client->eekboard,
                                                client->context,
                                                NULL);
        }
141
142
143
144
145
146
147
148
149
        break;
    default:
        g_object_set_property (object,
                               g_param_spec_get_name (pspec),
                               value);
        break;
    }
}

150
static void
151
eekboard_desktop_client_get_property (GObject    *object,
152
153
154
155
                                     guint       prop_id,
                                     GValue     *value,
                                     GParamSpec *pspec)
{
156
    EekboardDesktopClient *client = EEKBOARD_DESKTOP_CLIENT(object);
157
158

    switch (prop_id) {
Daiki Ueno's avatar
Daiki Ueno committed
159
160
161
    case PROP_EEKBOARD:
        g_value_set_object (value, client->eekboard);
        break;
162
163
164
165
166
167
168
169
170
171
172
    case PROP_CONTEXT:
        g_value_set_object (value, client->context);
        break;
    default:
        g_object_get_property (object,
                               g_param_spec_get_name (pspec),
                               value);
        break;
    }
}

173
static void
174
eekboard_desktop_client_dispose (GObject *object)
175
{
176
    EekboardDesktopClient *client = EEKBOARD_DESKTOP_CLIENT(object);
177

178
    eekboard_desktop_client_disable_xkl (client);
Daiki Ueno's avatar
Daiki Ueno committed
179
180

#ifdef HAVE_CSPI
181
182
    eekboard_desktop_client_disable_cspi_focus (client);
    eekboard_desktop_client_disable_cspi_keystroke (client);
Daiki Ueno's avatar
Daiki Ueno committed
183
184
185
#endif  /* HAVE_CSPI */

#ifdef HAVE_FAKEKEY
186
    eekboard_desktop_client_disable_fakekey (client);
Daiki Ueno's avatar
Daiki Ueno committed
187
#endif  /* HAVE_FAKEKEY */
188

189
    if (client->context) {
190
191
        if (client->eekboard) {
            eekboard_eekboard_pop_context (client->eekboard, NULL);
192
193
194
195
196
197
        }

        g_object_unref (client->context);
        client->context = NULL;
    }

198
199
200
    if (client->eekboard) {
        g_object_unref (client->eekboard);
        client->eekboard = NULL;
201
202
    }

203
204
205
206
207
    if (client->keyboard) {
        g_object_unref (client->keyboard);
        client->keyboard = NULL;
    }

Daiki Ueno's avatar
Daiki Ueno committed
208
#ifdef HAVE_FAKEKEY
209
210
211
    if (client->fakekey) {
        client->fakekey = NULL;
    }
Daiki Ueno's avatar
Daiki Ueno committed
212
#endif  /* HAVE_FAKEKEY */
213

214
215
216
217
218
    if (client->display) {
        gdk_display_close (client->display);
        client->display = NULL;
    }

219
    G_OBJECT_CLASS (eekboard_desktop_client_parent_class)->dispose (object);
220
221
222
}

static void
223
eekboard_desktop_client_class_init (EekboardDesktopClientClass *klass)
224
225
226
227
{
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
    GParamSpec *pspec;

228
229
230
    gobject_class->set_property = eekboard_desktop_client_set_property;
    gobject_class->get_property = eekboard_desktop_client_get_property;
    gobject_class->dispose = eekboard_desktop_client_dispose;
231
232
233
234
235
236
237
238
239

    pspec = g_param_spec_object ("connection",
                                 "Connection",
                                 "Connection",
                                 G_TYPE_DBUS_CONNECTION,
                                 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
    g_object_class_install_property (gobject_class,
                                     PROP_CONNECTION,
                                     pspec);
240

Daiki Ueno's avatar
Daiki Ueno committed
241
242
243
244
245
246
247
248
249
    pspec = g_param_spec_object ("eekboard",
                                 "Eekboard",
                                 "Eekboard",
                                 EEKBOARD_TYPE_EEKBOARD,
                                 G_PARAM_READABLE);
    g_object_class_install_property (gobject_class,
                                     PROP_EEKBOARD,
                                     pspec);

250
251
252
253
254
255
256
257
    pspec = g_param_spec_object ("context",
                                 "Context",
                                 "Context",
                                 EEKBOARD_TYPE_CONTEXT,
                                 G_PARAM_READABLE);
    g_object_class_install_property (gobject_class,
                                     PROP_CONTEXT,
                                     pspec);
258
259
260
}

static void
261
eekboard_desktop_client_init (EekboardDesktopClient *client)
262
{
263
    client->eekboard = NULL;
264
    client->context = NULL;
265
    client->display = NULL;
266
267
    client->xkl_engine = NULL;
    client->xkl_config_registry = NULL;
268
    client->keyboard = NULL;
269
270
271
272
    client->key_pressed_handler = 0;
    client->key_released_handler = 0;
    client->xkl_config_changed_handler = 0;
    client->xkl_state_changed_handler = 0;
Daiki Ueno's avatar
Daiki Ueno committed
273
274
275
276
277
278
279
#ifdef HAVE_CSPI
    client->focus_listener = NULL;
    client->keystroke_listener = NULL;
#endif  /* HAVE_CSPI */
#ifdef HAVE_FAKEKEY
    client->fakekey = NULL;
#endif  /* HAVE_FAKEKEY */
280
281
}

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
gboolean
eekboard_desktop_client_set_xkl_config (EekboardDesktopClient *client,
                                        const gchar *model,
                                        const gchar *layouts,
                                        const gchar *options)
{
#ifdef HAVE_CSPI
    return set_keyboard (client,
                         client->focus_listener ? FALSE : TRUE,
                         model,
                         layouts,
                         options);
#else
    return set_keyboard (client,
                         TRUE,
                         model,
                         layouts,
                         options);
#endif
}

303
gboolean
304
eekboard_desktop_client_enable_xkl (EekboardDesktopClient *client)
305
{
306
307
308
309
    if (!client->display) {
        client->display = gdk_display_get_default ();
    }
    g_assert (client->display);
310

311
312
313
    if (!client->xkl_engine) {
        client->xkl_engine =
            xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY (client->display));
314
    }
315
    g_assert (client->xkl_engine);
316
317
318
319
320
321
322

    if (!client->xkl_config_registry) {
        client->xkl_config_registry =
            xkl_config_registry_get_instance (client->xkl_engine);
        xkl_config_registry_load (client->xkl_config_registry, FALSE);
    }

323
    client->xkl_config_changed_handler =
324
325
        g_signal_connect (client->xkl_engine, "X-config-changed",
                          G_CALLBACK(on_xkl_config_changed), client);
326
    client->xkl_state_changed_handler =
327
328
329
330
331
332
333
334
335
336
337
338
        g_signal_connect (client->xkl_engine, "X-state-changed",
                          G_CALLBACK(on_xkl_state_changed), client);

    gdk_window_add_filter (NULL,
                           (GdkFilterFunc) filter_xkl_event,
                           client);
    gdk_window_add_filter (gdk_get_default_root_window (),
                           (GdkFilterFunc) filter_xkl_event,
                           client);

    xkl_engine_start_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE);

339
#ifdef HAVE_CSPI
340
341
    return set_keyboard (client, client->focus_listener ? FALSE : TRUE,
                         NULL, NULL, NULL);
342
#else
343
    return set_keyboard (client, TRUE, NULL, NULL, NULL);
344
#endif
345
346
347
}

void
348
eekboard_desktop_client_disable_xkl (EekboardDesktopClient *client)
349
350
351
352
{
    if (client->xkl_engine)
        xkl_engine_stop_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE);
    if (g_signal_handler_is_connected (client->xkl_engine,
353
                                       client->xkl_config_changed_handler))
354
        g_signal_handler_disconnect (client->xkl_engine,
355
                                     client->xkl_config_changed_handler);
356
    if (g_signal_handler_is_connected (client->xkl_engine,
357
                                       client->xkl_state_changed_handler))
358
        g_signal_handler_disconnect (client->xkl_engine,
359
                                     client->xkl_state_changed_handler);
360
361
}

Daiki Ueno's avatar
Daiki Ueno committed
362
#ifdef HAVE_CSPI
363
gboolean
364
eekboard_desktop_client_enable_cspi_focus (EekboardDesktopClient *client)
365
366
367
368
369
370
371
372
373
374
375
376
377
{
    client->focus_listener = SPI_createAccessibleEventListener
        ((AccessibleEventListenerCB)focus_listener_cb,
         client);

    if (!SPI_registerGlobalEventListener (client->focus_listener,
                                          "object:state-changed:focused"))
        return FALSE;

    if (!SPI_registerGlobalEventListener (client->focus_listener,
                                          "focus:"))
        return FALSE;

378
379
380
381
    return TRUE;
}

void
382
eekboard_desktop_client_disable_cspi_focus (EekboardDesktopClient *client)
383
384
385
386
387
388
389
390
391
{
    if (client->focus_listener) {
        SPI_deregisterGlobalEventListenerAll (client->focus_listener);
        AccessibleEventListener_unref (client->focus_listener);
        client->focus_listener = NULL;
    }
}

gboolean
392
eekboard_desktop_client_enable_cspi_keystroke (EekboardDesktopClient *client)
393
{
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    client->keystroke_listener =
        SPI_createAccessibleKeystrokeListener (keystroke_listener_cb,
                                               client);

    if (!SPI_registerAccessibleKeystrokeListener
        (client->keystroke_listener,
         SPI_KEYSET_ALL_KEYS,
         0,
         SPI_KEY_PRESSED |
         SPI_KEY_RELEASED,
         SPI_KEYLISTENER_NOSYNC))
        return FALSE;
    return TRUE;
}

void
410
eekboard_desktop_client_disable_cspi_keystroke (EekboardDesktopClient *client)
411
412
413
414
415
416
417
418
419
420
421
422
423
{
    if (client->keystroke_listener) {
        SPI_deregisterAccessibleKeystrokeListener (client->keystroke_listener,
                                                   0);
        AccessibleKeystrokeListener_unref (client->keystroke_listener);
        client->keystroke_listener = NULL;
    }
}

static SPIBoolean
focus_listener_cb (const AccessibleEvent *event,
                   void                  *user_data)
{
424
    EekboardDesktopClient *client = user_data;
425
426
427
428
429
430
431
432
433
434
435
436
    Accessible *accessible = event->source;
    AccessibleStateSet *state_set = Accessible_getStateSet (accessible);
    AccessibleRole role = Accessible_getRole (accessible);

    if (AccessibleStateSet_contains (state_set, SPI_STATE_EDITABLE) ||
        role == SPI_ROLE_TERMINAL) {
        switch (role) {
        case SPI_ROLE_TEXT:
        case SPI_ROLE_PARAGRAPH:
        case SPI_ROLE_PASSWORD_TEXT:
        case SPI_ROLE_TERMINAL:
        case SPI_ROLE_ENTRY:
437
438
439
            if (g_strcmp0 (event->type, "focus") == 0 || event->detail1 == 1) {
                eekboard_context_show_keyboard (client->context, NULL);
            }
440
441
442
        default:
            ;
        }
443
444
445
    } else {
        eekboard_context_hide_keyboard (client->context, NULL);
    }
446
447
448
449
450
451
452
453

    return FALSE;
}

static SPIBoolean
keystroke_listener_cb (const AccessibleKeystroke *stroke,
                       void                      *user_data)
{
454
    EekboardDesktopClient *client = user_data;
455
456
457
458
    EekKey *key;

    /* Ignore modifiers since the keystroke listener does not called
       when a modifier key is released. */
459
    key = eek_keyboard_find_key_by_keycode (client->keyboard,
460
                                            stroke->keycode);
461
462
463
464
465
    if (key) {
        EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
        if (symbol && eek_symbol_is_modifier (symbol))
            return FALSE;
    }
466

467
468
469
470
471
472
    if (stroke->type == SPI_KEY_PRESSED) {
        eekboard_context_press_key (client->context, stroke->keycode, NULL);
    } else {
        eekboard_context_release_key (client->context, stroke->keycode, NULL);
    }

473
474
    return TRUE;
}
Daiki Ueno's avatar
Daiki Ueno committed
475
476
#endif  /* HAVE_CSPI */

477
478
EekboardDesktopClient *
eekboard_desktop_client_new (GDBusConnection *connection)
Daiki Ueno's avatar
Daiki Ueno committed
479
{
Daiki Ueno's avatar
Daiki Ueno committed
480
481
482
483
484
485
    EekboardDesktopClient *client = g_object_new (EEKBOARD_TYPE_DESKTOP_CLIENT,
                                                  "connection", connection,
                                                  NULL);
    if (client->context)
        return client;
    return NULL;
Daiki Ueno's avatar
Daiki Ueno committed
486
}
487
488
489
490
491
492

static GdkFilterReturn
filter_xkl_event (GdkXEvent *xev,
                  GdkEvent  *event,
                  gpointer   user_data)
{
493
    EekboardDesktopClient *client = user_data;
494
495
496
497
498
499
500
501
502
503
    XEvent *xevent = (XEvent *)xev;

    xkl_engine_filter_events (client->xkl_engine, xevent);
    return GDK_FILTER_CONTINUE;
}

static void
on_xkl_config_changed (XklEngine *xklengine,
                       gpointer   user_data)
{
504
    EekboardDesktopClient *client = user_data;
505
    gboolean retval;
506

507
508
    retval = set_keyboard (client, FALSE, NULL, NULL, NULL);
    g_return_if_fail (retval);
509

Daiki Ueno's avatar
Daiki Ueno committed
510
#ifdef HAVE_FAKEKEY
511
512
    if (client->fakekey)
        fakekey_reload_keysyms (client->fakekey);
Daiki Ueno's avatar
Daiki Ueno committed
513
#endif  /* HAVE_FAKEKEY */
514
515
}

516
static gboolean
517
set_keyboard (EekboardDesktopClient *client,
518
519
520
521
              gboolean               show,
              const gchar           *model,
              const gchar           *layouts,
              const gchar           *options)
522
523
524
525
{
    EekLayout *layout;
    gchar *keyboard_name;
    static gint keyboard_serial = 0;
526
    guint keyboard_id;
527

528
529
    if (client->keyboard)
        g_object_unref (client->keyboard);
530
    layout = eek_xkl_layout_new ();
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560

    if (model) {
        if (!eek_xkl_layout_set_model (EEK_XKL_LAYOUT(layout), model)) {
            g_object_unref (layout);
            return FALSE;
        }
    }

    if (layouts) {
        XklConfigRec *rec;

        rec = eekboard_xkl_config_rec_new_from_string (layouts);
        if (!eek_xkl_layout_set_layouts (EEK_XKL_LAYOUT(layout),
                                         rec->layouts)) {
            g_object_unref (rec);
            g_object_unref (layout);
            return FALSE;
        }

        if (!eek_xkl_layout_set_variants (EEK_XKL_LAYOUT(layout),
                                          rec->variants)) {
            g_object_unref (rec);
            g_object_unref (layout);
            return FALSE;
        }            

        g_object_unref (rec);
    }

    if (options) {
Daiki Ueno's avatar
Daiki Ueno committed
561
        gchar **_options;
562

Daiki Ueno's avatar
Daiki Ueno committed
563
564
565
        _options = g_strsplit (options, ",", -1);
        if (!eek_xkl_layout_set_options (EEK_XKL_LAYOUT(layout), _options)) {
            g_strfreev (_options);
566
567
568
569
570
            g_object_unref (layout);
            return FALSE;
        }
    }

571
572
    client->keyboard = eek_keyboard_new (layout, CSW, CSH);
    eek_keyboard_set_modifier_behavior (client->keyboard,
573
                                        EEK_MODIFIER_BEHAVIOR_LATCH);
574
575

    keyboard_name = g_strdup_printf ("keyboard%d", keyboard_serial++);
576
    eek_element_set_name (EEK_ELEMENT(client->keyboard), keyboard_name);
Daiki Ueno's avatar
Daiki Ueno committed
577
    g_free (keyboard_name);
578

579
580
581
582
    keyboard_id = eekboard_context_add_keyboard (client->context,
                                                 client->keyboard,
                                                 NULL);
    eekboard_context_set_keyboard (client->context, keyboard_id, NULL);
583
584
    if (show)
        eekboard_context_show_keyboard (client->context, NULL);
585
586

    return TRUE;
587
588
589
590
591
592
593
594
595
}

static void
on_xkl_state_changed (XklEngine           *xklengine,
                      XklEngineStateChange type,
                      gint                 value,
                      gboolean             restore,
                      gpointer             user_data)
{
596
    EekboardDesktopClient *client = user_data;
597

598
    if (type == GROUP_CHANGED && client->keyboard) {
599
        gint group = eek_element_get_group (EEK_ELEMENT(client->keyboard));
600
        if (group != value) {
601
            eekboard_context_set_group (client->context, value, NULL);
602
603
604
605
        }
    }
}

Daiki Ueno's avatar
Daiki Ueno committed
606
#ifdef HAVE_FAKEKEY
Daiki Ueno's avatar
Daiki Ueno committed
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
G_INLINE_FUNC FakeKeyModifier
get_fakekey_modifiers (EekModifierType modifiers)
{
    FakeKeyModifier retval = 0;

    if (modifiers & EEK_SHIFT_MASK)
        retval |= FAKEKEYMOD_SHIFT;
    if (modifiers & EEK_CONTROL_MASK)
        retval |= FAKEKEYMOD_CONTROL;
    if (modifiers & EEK_MOD1_MASK)
        retval |= FAKEKEYMOD_ALT;
    if (modifiers & EEK_META_MASK)
        retval |= FAKEKEYMOD_META;

    return retval;
}

624
static void
625
626
627
on_key_pressed (EekKeyboard *keyboard,
                EekKey      *key,
                gpointer     user_data)
628
{
629
    EekboardDesktopClient *client = user_data;
630
631
632
    EekSymbol *symbol;

    g_assert (client->fakekey);
633

634
    symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
635
    if (EEK_IS_KEYSYM(symbol) && !eek_symbol_is_modifier (symbol)) {
Daiki Ueno's avatar
Daiki Ueno committed
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
        guint xkeysym = eek_keysym_get_xkeysym (EEK_KEYSYM(symbol));
        guint keycode =
            XKeysymToKeycode (GDK_DISPLAY_XDISPLAY (client->display), xkeysym);
        EekModifierType modifiers =
            eek_keyboard_get_modifiers (client->keyboard);
        FakeKeyModifier fakekey_modifiers = get_fakekey_modifiers (modifiers);

        fakekey_send_keyevent (client->fakekey,
                               keycode,
                               TRUE,
                               fakekey_modifiers);
        fakekey_send_keyevent (client->fakekey,
                               keycode,
                               FALSE,
                               fakekey_modifiers);
651
    }
652
653
654
}

static void
655
656
657
on_key_released (EekKeyboard *keyboard,
                 EekKey      *key,
                 gpointer     user_data)
658
{
659
    EekboardDesktopClient *client = user_data;
660
661
662
663
664
665

    g_assert (client->fakekey);
    fakekey_release (client->fakekey);
}

gboolean
666
eekboard_desktop_client_enable_fakekey (EekboardDesktopClient *client)
667
{
668
669
670
671
    if (!client->display) {
        client->display = gdk_display_get_default ();
    }
    g_assert (client->display);
672

673
674
    if (!client->fakekey) {
        client->fakekey = fakekey_init (GDK_DISPLAY_XDISPLAY (client->display));
675
676
677
    }
    g_assert (client->fakekey);

678
    client->key_pressed_handler =
679
        g_signal_connect (client->keyboard, "key-pressed",
680
                          G_CALLBACK(on_key_pressed), client);
681
    client->key_released_handler =
682
        g_signal_connect (client->keyboard, "key-released",
683
684
685
686
687
688
                          G_CALLBACK(on_key_released), client);

    return TRUE;
}

void
689
eekboard_desktop_client_disable_fakekey (EekboardDesktopClient *client)
690
691
692
693
{
    if (client->fakekey)
        fakekey_release (client->fakekey);

694
    if (g_signal_handler_is_connected (client->keyboard,
695
                                       client->key_pressed_handler))
696
        g_signal_handler_disconnect (client->keyboard,
697
                                     client->key_pressed_handler);
698
    if (g_signal_handler_is_connected (client->keyboard,
699
                                       client->key_released_handler))
700
        g_signal_handler_disconnect (client->keyboard,
701
                                     client->key_released_handler);
702
}
Daiki Ueno's avatar
Daiki Ueno committed
703
#endif  /* HAVE_FAKEKEY */