]> Pileus Git - ~andy/gtk/blob - gdk/linux-fb/gdkkeyboard-fb.c
f06794064cbb9cdf79890734905bcc2da9351315
[~andy/gtk] / gdk / linux-fb / gdkkeyboard-fb.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <config.h>
21 #include <gdk/gdk.h>
22 #include <gdk/gdkinternals.h>
23 #include "gdkkeysyms.h"
24 #include "gdkprivate-fb.h"
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <termios.h>
31 #include <sys/ioctl.h>
32 #include <sys/kd.h>
33 #include <sys/vt.h>
34
35 typedef struct _GdkFBKeyboard GdkFBKeyboard;
36 typedef struct _GdkFBKeyboardDevice GdkFBKeyboardDevice;
37
38 struct _GdkFBKeyboard {
39   gint fd;
40   GIOChannel *io;
41   gint io_tag;
42
43   guint modifier_state;
44   guint caps_lock : 1;
45
46   gint group;
47   gint level;
48   
49   GdkFBKeyboardDevice *dev;
50 };
51
52 struct _GdkFBKeyboardDevice {
53   char *name;
54   gboolean (*open)(GdkFBKeyboard *kb);
55   void (*close)(GdkFBKeyboard *kb);
56
57   guint    (*lookup_key)               (GdkFBKeyboard       *kb,
58                                         const GdkKeymapKey  *key);
59   gboolean (*translate_keyboard_state) (GdkFBKeyboard       *kb,
60                                         guint                hardware_keycode,
61                                         GdkModifierType      state,
62                                         gint                 group,
63                                         guint               *keyval,
64                                         gint                *effective_group,
65                                         gint                *level,
66                                         GdkModifierType     *consumed_modifiers);
67   gboolean (*get_entries_for_keyval)   (GdkFBKeyboard       *kb,
68                                         guint                keyval,
69                                         GdkKeymapKey       **keys,
70                                         gint                *n_keys);
71   gboolean (*get_entries_for_keycode)  (GdkFBKeyboard       *kb,
72                                         guint                hardware_keycode,
73                                         GdkKeymapKey       **keys,
74                                         guint              **keyvals,
75                                         gint                *n_entries);
76
77   gpointer driver_data;
78 };
79
80 static GdkFBKeyboard *gdk_fb_keyboard = NULL;
81 static GdkKeymap *default_keymap = NULL;
82
83 static gboolean xlate_open            (GdkFBKeyboard       *kb);
84 static void     xlate_close           (GdkFBKeyboard       *kb);
85 static guint    xlate_lookup          (GdkFBKeyboard       *kb,
86                                        const GdkKeymapKey  *key);
87 static gboolean xlate_translate       (GdkFBKeyboard       *kb,
88                                        guint                hardware_keycode,
89                                        GdkModifierType      state,
90                                        gint                 group,
91                                        guint               *keyval,
92                                        gint                *effective_group,
93                                        gint                *level,
94                                        GdkModifierType     *consumed_modifiers);
95 static gboolean xlate_get_for_keyval  (GdkFBKeyboard       *kb,
96                                        guint                keyval,
97                                        GdkKeymapKey       **keys,
98                                        gint                *n_keys);
99 static gboolean xlate_get_for_keycode (GdkFBKeyboard       *kb,
100                                        guint                hardware_keycode,
101                                        GdkKeymapKey       **keys,
102                                        guint              **keyvals,
103                                        gint                *n_entries);
104
105 static gboolean raw_open            (GdkFBKeyboard       *kb);
106 static void     raw_close           (GdkFBKeyboard       *kb);
107 static guint    raw_lookup          (GdkFBKeyboard       *kb,
108                                      const GdkKeymapKey  *key);
109 static gboolean raw_translate       (GdkFBKeyboard       *kb,
110                                      guint                hardware_keycode,
111                                      GdkModifierType      state,
112                                      gint                 group,
113                                      guint               *keyval,
114                                      gint                *effective_group,
115                                      gint                *level,
116                                      GdkModifierType     *consumed_modifiers);
117 static gboolean raw_get_for_keyval  (GdkFBKeyboard       *kb,
118                                      guint                keyval,
119                                      GdkKeymapKey       **keys,
120                                      gint                *n_keys);
121 static gboolean raw_get_for_keycode (GdkFBKeyboard       *kb,
122                                      guint                hardware_keycode,
123                                      GdkKeymapKey       **keys,
124                                      guint              **keyvals,
125                                      gint                *n_entries);
126
127
128 static GdkFBKeyboardDevice keyb_devs[] =
129 {
130   {
131     "xlate",
132     xlate_open,
133     xlate_close,
134     xlate_lookup,
135     xlate_translate,
136     xlate_get_for_keyval,
137     xlate_get_for_keycode
138   },
139   {
140     "raw",
141     raw_open,
142     raw_close,
143     raw_lookup,
144     raw_translate,
145     raw_get_for_keyval,
146     raw_get_for_keycode
147   },
148 };
149
150 GdkKeymap*
151 gdk_keymap_get_default_for_display (GdkDisplay *display)
152 {
153   if (default_keymap == NULL)
154     default_keymap = g_object_new (gdk_keymap_get_type (), NULL);
155
156   return default_keymap;
157 }
158
159 GdkKeymap*
160 gdk_keymap_get_for_display (GdkDisplay *display)
161 {
162   return gdk_keymap_get_default_for_display (display);
163 }
164
165 PangoDirection
166 gdk_keymap_get_direction (GdkKeymap *keymap)
167 {
168   /* FIXME: Only supports LTR keymaps at the moment */
169   return PANGO_DIRECTION_LTR;
170 }
171
172 guint
173 gdk_fb_keyboard_modifiers (void)
174 {
175   return gdk_fb_keyboard->modifier_state;
176 }
177
178 gboolean
179 gdk_fb_keyboard_init (gboolean open_dev)
180 {
181   GdkFBKeyboard *keyb;
182   char *keyb_type;
183   int i;
184
185   gdk_fb_keyboard = g_new0 (GdkFBKeyboard, 1);
186   keyb = gdk_fb_keyboard;
187   keyb->fd = -1;
188   
189   keyb_type = getenv ("GDK_KEYBOARD_TYPE");
190   
191   if (!keyb_type)
192     keyb_type = "xlate";
193
194   for (i = 0; i < G_N_ELEMENTS(keyb_devs); i++)
195     {
196       if (g_ascii_strcasecmp(keyb_type, keyb_devs[i].name)==0)
197         break;
198     }
199   
200   if (i == G_N_ELEMENTS(keyb_devs))
201     {
202       g_warning ("No keyboard driver of type %s found", keyb_type);
203       return FALSE;
204     }
205
206   keyb->dev = &keyb_devs[i];
207
208   if (open_dev)
209     return gdk_fb_keyboard_open ();
210   else
211     return TRUE;
212 }
213
214 gboolean
215 gdk_fb_keyboard_open (void)
216 {
217   GdkFBKeyboard *keyb;
218   GdkFBKeyboardDevice *device;
219
220   keyb = gdk_fb_keyboard;
221   device = keyb->dev;
222
223   if (!device->open(keyb))
224     {
225       g_warning ("Keyboard driver open failed");
226       return FALSE;
227     }
228
229   return TRUE;
230 }
231
232 void 
233 gdk_fb_keyboard_close (void)
234 {
235   gdk_fb_keyboard->dev->close(gdk_fb_keyboard);
236 }
237
238
239 gboolean
240 gdk_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
241                                    guint          keyval,
242                                    GdkKeymapKey **keys,
243                                    gint          *n_keys)
244 {
245   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
246   g_return_val_if_fail (keys != NULL, FALSE);
247   g_return_val_if_fail (n_keys != NULL, FALSE);
248   g_return_val_if_fail (keyval != 0, FALSE);
249
250   return gdk_fb_keyboard->dev->get_entries_for_keyval (gdk_fb_keyboard,
251                                                        keyval,
252                                                        keys,
253                                                        n_keys);
254 }
255
256 gboolean
257 gdk_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
258                                     guint          hardware_keycode,
259                                     GdkKeymapKey **keys,
260                                     guint        **keyvals,
261                                     gint          *n_entries)
262 {
263   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
264   g_return_val_if_fail (n_entries != NULL, FALSE);
265   
266   return gdk_fb_keyboard->dev->get_entries_for_keycode (gdk_fb_keyboard,
267                                                         hardware_keycode,
268                                                         keys,
269                                                         keyvals,
270                                                         n_entries);
271 }
272
273
274 guint
275 gdk_keymap_lookup_key (GdkKeymap          *keymap,
276                        const GdkKeymapKey *key)
277 {
278   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0);
279   g_return_val_if_fail (key != NULL, 0);
280   g_return_val_if_fail (key->group < 4, 0);
281
282   return gdk_fb_keyboard->dev->lookup_key (gdk_fb_keyboard,  key);
283 }
284
285
286 gboolean
287 gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
288                                      guint            hardware_keycode,
289                                      GdkModifierType  state,
290                                      gint             group,
291                                      guint           *keyval,
292                                      gint            *effective_group,
293                                      gint            *level,
294                                      GdkModifierType *consumed_modifiers)
295 {
296   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
297   g_return_val_if_fail (group < 4, FALSE);
298
299   return gdk_fb_keyboard->dev->translate_keyboard_state (gdk_fb_keyboard,
300                                                          hardware_keycode,
301                                                          state,
302                                                          group,
303                                                          keyval,
304                                                          effective_group,
305                                                          level,
306                                                          consumed_modifiers);
307 }
308
309 static void
310 gdk_fb_handle_key (guint hw_keycode,
311                    guint keyval,
312                    guint modifier_state,
313                    guint8 group,
314                    gchar *string,
315                    gint string_length,
316                    gboolean key_up)
317 {
318   GdkWindow *win;
319   GdkEvent *event;
320
321   /* handle some magic keys */
322   if (key_up &&
323       (modifier_state & GDK_CONTROL_MASK) &&
324       (modifier_state & GDK_MOD1_MASK))
325     {
326       if (keyval == GDK_BackSpace)
327         {
328           ioctl (gdk_display->tty_fd, KDSKBMODE, K_XLATE);
329           exit (1);
330         }
331           
332       if (keyval == GDK_Return)
333         gdk_fb_redraw_all ();
334     }
335
336   win = gdk_fb_keyboard_event_window (gdk_fb_window_find_focus (),
337                                       key_up ? GDK_KEY_RELEASE : GDK_KEY_PRESS);
338   if (win)
339     {
340       event = gdk_event_make (win,
341                               key_up ? GDK_KEY_RELEASE : GDK_KEY_PRESS,
342                               TRUE);
343     
344       event->key.state = modifier_state;
345       event->key.keyval = keyval;
346       event->key.string = string;
347       event->key.length = string_length;
348       event->key.hardware_keycode = hw_keycode;
349       event->key.group = group;
350     }
351   else
352     g_free (string);
353 }
354
355 /******************************************************
356  ********* Device specific keyboard code **************
357  ******************************************************/
358
359
360 /* XLATE keyboard driver */
361
362 struct {
363   char *str;
364   guint code;
365   guint modifier;
366 } xlate_codes[] =
367 {
368   {"\x5b\x41", GDK_F1},
369   {"\x5b\x42", GDK_F2},
370   {"\x5b\x43", GDK_F3},
371   {"\x5b\x44", GDK_F4},
372   {"\x5b\x45", GDK_F5},
373   {"\x31\x37\x7e", GDK_F6},
374   {"\x31\x38\x7e", GDK_F7},
375   {"\x31\x39\x7e", GDK_F8},
376   {"\x32\x30\x7e", GDK_F9},
377   {"\x32\x31\x7e", GDK_F10},
378   {"\x32\x33\x7e", GDK_F11},
379   {"\x32\x34\x7e", GDK_F12},
380   
381   {"\x32\x35\x7e", GDK_F1, GDK_SHIFT_MASK},
382   {"\x32\x36\x7e", GDK_F2, GDK_SHIFT_MASK},
383   {"\x32\x38\x7e", GDK_F3, GDK_SHIFT_MASK},
384   {"\x32\x39\x7e", GDK_F4, GDK_SHIFT_MASK},
385   {"\x33\x31\x7e", GDK_F5, GDK_SHIFT_MASK},
386   {"\x33\x32\x7e", GDK_F6, GDK_SHIFT_MASK},
387   {"\x33\x33\x7e", GDK_F7, GDK_SHIFT_MASK},
388   {"\x33\x34\x7e", GDK_F8, GDK_SHIFT_MASK},
389
390   {"\x31\x7e", GDK_Home},
391   {"\x35\x7e", GDK_Page_Up},
392   {"\x34\x7e", GDK_End},
393   {"\x36\x7e", GDK_Page_Down},
394   {"\x32\x7e", GDK_Insert},
395   {"\x33\x7e", GDK_Delete},
396
397   {"\x41", GDK_Up},
398   {"\x44", GDK_Left},
399   {"\x42", GDK_Down},
400   {"\x43", GDK_Right},
401   {"\x50", GDK_Break},
402 };
403
404 struct {
405   guint code;
406   guint modifier;
407 } xlate_chars[] =
408 {
409   /* 0x00 */
410   {'@', GDK_CONTROL_MASK},
411   {'a', GDK_CONTROL_MASK},
412   {'b', GDK_CONTROL_MASK},
413   {'c', GDK_CONTROL_MASK},
414   {'d', GDK_CONTROL_MASK},
415   {'e', GDK_CONTROL_MASK},
416   {'f', GDK_CONTROL_MASK},
417   {'g', GDK_CONTROL_MASK},
418   {'h', GDK_CONTROL_MASK},
419   {GDK_Tab, 0},
420   {'j', GDK_CONTROL_MASK},
421   {'k', GDK_CONTROL_MASK},
422   {'l', GDK_CONTROL_MASK},
423   {GDK_Return, 0},
424   {'n', GDK_CONTROL_MASK},
425   {'o', GDK_CONTROL_MASK},
426   /* 0x10 */
427   {'p', GDK_CONTROL_MASK},
428   {'q', GDK_CONTROL_MASK},
429   {'r', GDK_CONTROL_MASK},
430   {'s', GDK_CONTROL_MASK},
431   {'t', GDK_CONTROL_MASK},
432   {'u', GDK_CONTROL_MASK},
433   {'v', GDK_CONTROL_MASK},
434   {'w', GDK_CONTROL_MASK},
435   {'x', GDK_CONTROL_MASK},
436   {'y', GDK_CONTROL_MASK},
437   {'z', GDK_CONTROL_MASK},
438   {GDK_Escape, 0},
439   {'\\', GDK_CONTROL_MASK},
440   {']', GDK_CONTROL_MASK},
441   {'^', GDK_CONTROL_MASK},
442   {'_', GDK_CONTROL_MASK},
443   /* 0x20 */
444   {GDK_space, 0},
445   {'!', 0},
446   {'"', 0},
447   {'#', 0},
448   {'$', 0},
449   {'%', 0},
450   {'&', 0},
451   {'\'', 0},
452   {'(', 0},
453   {')', 0},
454   {'*', 0},
455   {'+', 0},
456   {',', 0},
457   {'-', 0},
458   {'.', 0},
459   {'/', 0},
460   /* 0x30 */
461   {'0', 0},
462   {'1', 0},
463   {'2', 0},
464   {'3', 0},
465   {'4', 0},
466   {'5', 0},
467   {'6', 0},
468   {'7', 0},
469   {'8', 0},
470   {'9', 0},
471   {':', 0},
472   {';', 0},
473   {'<', 0},
474   {'=', 0},
475   {'>', 0},
476   {'?', 0},
477   /* 0x40 */
478   {'@', 0},
479   {'A', 0},
480   {'B', 0},
481   {'C', 0},
482   {'D', 0},
483   {'E', 0},
484   {'F', 0},
485   {'G', 0},
486   {'H', 0},
487   {'I', 0},
488   {'J', 0},
489   {'K', 0},
490   {'L', 0},
491   {'M', 0},
492   {'N', 0},
493   {'O', 0},
494   /* 0x50 */
495   {'P', 0},
496   {'Q', 0},
497   {'R', 0},
498   {'S', 0},
499   {'T', 0},
500   {'U', 0},
501   {'V', 0},
502   {'W', 0},
503   {'X', 0},
504   {'Y', 0},
505   {'Z', 0},
506   {'[', 0},
507   {'\\', 0},
508   {']', 0},
509   {'^', 0},
510   {'_', 0},
511   /* 0x60 */
512   {'`', 0},
513   {'a', 0},
514   {'b', 0},
515   {'c', 0},
516   {'d', 0},
517   {'e', 0},
518   {'f', 0},
519   {'g', 0},
520   {'h', 0},
521   {'i', 0},
522   {'j', 0},
523   {'k', 0},
524   {'l', 0},
525   {'m', 0},
526   {'n', 0},
527   {'o', 0},
528   /* 0x70 */
529   {'p', 0},
530   {'q', 0},
531   {'r', 0},
532   {'s', 0},
533   {'t', 0},
534   {'u', 0},
535   {'v', 0},
536   {'w', 0},
537   {'x', 0},
538   {'y', 0},
539   {'z', 0},
540   {'{', 0},
541   {'|', 0},
542   {'}', 0},
543   {'~', 0},
544   {GDK_BackSpace, 0},
545   /* 0x80 */
546   {0, 0},
547   {0, 0},
548   {0, 0},
549   {0, 0},
550   {0, 0},
551   {0, 0},
552   {0, 0},
553   {0, 0},
554   {0, 0},
555   {0, 0},
556   {0, 0},
557   {0, 0},
558   {0, 0},
559   {0, 0},
560   {0, 0},
561   {0, 0},
562   /* 0x90 */
563   {0, 0},
564   {0, 0},
565   {0, 0},
566   {0, 0},
567   {0, 0},
568   {0, 0},
569   {0, 0},
570   {0, 0},
571   {0, 0},
572   {0, 0},
573   {0, 0},
574   {0, 0},
575   {0, 0},
576   {0, 0},
577   {0, 0},
578   {0, 0},
579   /* 0xA0 */
580   {0, 0},
581   {0, 0},
582   {0, 0},
583   {0, 0},
584   {0, 0},
585   {0, 0},
586   {0, 0},
587   {0, 0},
588   {0, 0},
589   {0, 0},
590   {0, 0},
591   {0, 0},
592   {0, 0},
593   {0, 0},
594   {0, 0},
595   {0, 0},
596   /* 0xB0 */
597   {0, 0},
598   {0, 0},
599   {0, 0},
600   {0, 0},
601   {0, 0},
602   {0, 0},
603   {0, 0},
604   {0, 0},
605   {0, 0},
606   {0, 0},
607   {0, 0},
608   {0, 0},
609   {0, 0},
610   {0, 0},
611   {0, 0},
612   {0, 0},
613   /* 0xC0 */
614   {0, 0},
615   {0, 0},
616   {0, 0},
617   {0, 0},
618   {0, 0},
619   {0, 0},
620   {0, 0},
621   {0, 0},
622   {0, 0},
623   {0, 0},
624   {0, 0},
625   {0, 0},
626   {0, 0},
627   {0, 0},
628   {0, 0},
629   {0, 0},
630   /* 0xD0 */
631   {0, 0},
632   {0, 0},
633   {0, 0},
634   {0, 0},
635   {0, 0},
636   {0, 0},
637   {0, 0},
638   {0, 0},
639   {0, 0},
640   {0, 0},
641   {0, 0},
642   {0, 0},
643   {0, 0},
644   {0, 0},
645   {0, 0},
646   {0, 0},
647   /* 0xE0 */
648   {0, 0},
649   {0, 0},
650   {0, 0},
651   {0, 0},
652   {0, 0},
653   {0, 0},
654   {0, 0},
655   {0, 0},
656   {0, 0},
657   {0, 0},
658   {0, 0},
659   {0, 0},
660   {0, 0},
661   {0, 0},
662   {0, 0},
663   {0, 0},
664   /* 0xF0 */
665   {0, 0},
666   {0, 0},
667   {0, 0},
668   {0, 0},
669   {0, 0},
670   {0, 0},
671   {0, 0},
672   {0, 0},
673   {0, 0},
674   {0, 0},
675   {0, 0},
676   {0, 0},
677   {0, 0},
678   {0, 0},
679   {0, 0},
680   {0, 0},
681 };
682
683 static gboolean
684 iscode (char *code, char *str, int str_max)
685 {
686   int i;
687
688   for (i = 0; code[i] && (i < str_max); i++)
689     {
690       if (code[i] != str[i])
691         return FALSE;
692     }
693   return (code[i] == 0);
694 }
695
696 static gboolean
697 xlate_io (GIOChannel *gioc,
698           GIOCondition cond,
699           gpointer data)
700 {
701   GdkFBKeyboard *keyb = (GdkFBKeyboard *)data;
702   guchar buf[128];
703   guint keycode;
704   guint modifier;
705   gboolean handled;
706   int i, n, j;
707   int left;
708   
709   n = read (keyb->fd, buf, sizeof(buf));
710   if (n <= 0)
711     g_error ("Nothing from keyboard!");
712
713   for (i = 0; i < n; )
714     {
715       handled = FALSE;
716       modifier = 0;
717       if ((buf[i] == 27) && (i+1 != n)) /* Escape */
718         {
719           /* Esc is not the last char in buffer, interpret as code sequence */
720           if (buf[i+1] == '[')
721             {
722               i += 2;
723               left = n-i;
724               if (left <= 0)
725                 return TRUE;
726
727               for (j=0;j<G_N_ELEMENTS (xlate_codes);j++)
728                 {
729                   if (iscode (xlate_codes[j].str, &buf[i], left))
730                     {
731                       /* Ctrl-Alt Return can't be pressed in the XLATE driver,
732                        * use Shift F1 instead */
733                       if ((xlate_codes[j].code == GDK_F1) &&
734                           (xlate_codes[j].modifier & GDK_SHIFT_MASK))
735                         gdk_fb_redraw_all ();
736
737                       if ((xlate_codes[j].code == GDK_F2) &&
738                           (xlate_codes[j].modifier & GDK_SHIFT_MASK))
739                         {
740                           static gint deg = 0;
741                           deg = (deg + 1) % 4;
742                             
743                           gdk_fb_set_rotation (deg);
744                         }
745
746                       if ((xlate_codes[j].code == GDK_F8) &&
747                           (xlate_codes[j].modifier & GDK_SHIFT_MASK))
748                         exit (1);
749
750                       
751                       gdk_fb_handle_key (xlate_codes[j].code,
752                                          xlate_codes[j].code,
753                                          xlate_codes[j].modifier,
754                                          0,
755                                          NULL,
756                                          0,
757                                          FALSE);
758                       gdk_fb_handle_key (xlate_codes[j].code,
759                                          xlate_codes[j].code,
760                                          xlate_codes[j].modifier,
761                                          0,
762                                          NULL,
763                                          0,
764                                          TRUE);
765                       i += strlen (xlate_codes[j].str);
766                       handled = TRUE;
767                       break;
768                     }
769                 }
770             }
771           else
772             {
773               /* Alt-key */
774               modifier |= GDK_MOD1_MASK;
775               i++;
776             }
777         }
778       if (!handled)
779         {
780           char dummy[2];
781           gint len;
782           
783           keycode = xlate_chars[buf[i]].code;
784           if (keycode == 0)
785             keycode = buf[i];
786           modifier |= xlate_chars[buf[i]].modifier;
787           
788           dummy[0] = keycode;
789           dummy[1] = 0;
790
791           len = ((keycode < 255) && isprint (keycode)) ? 1 : 0;
792           gdk_fb_handle_key (keycode,
793                              keycode,
794                              modifier,
795                              0,
796                              (len)?g_strdup(dummy) : NULL,
797                              len,
798                              FALSE);
799           gdk_fb_handle_key (keycode,
800                              keycode,
801                              modifier,
802                              0,
803                              (len)?g_strdup(dummy) : NULL,
804                              len,
805                              TRUE);
806           i++;
807         }
808     }
809   return TRUE;
810 }
811
812 static gboolean
813 write_string (gint         fd,
814               const gchar *str)
815 {
816   gsize to_write = strlen (str);
817
818   while (to_write > 0)
819     {
820       gssize count = write (fd, str, to_write);
821       if (count < 0)
822         {
823           if (errno != EINTR)
824             return FALSE;
825         }
826       else
827         {
828           to_write -= count;
829           str += count;
830         }
831     }
832
833   return TRUE;
834 }
835
836 static gboolean
837 xlate_open (GdkFBKeyboard *kb)
838 {
839   const char cursoroff_str[] = "\033[?1;0;0c";
840   struct termios ts;
841   
842   tcgetattr (gdk_display->tty_fd, &ts);
843   ts.c_cc[VTIME] = 0;
844   ts.c_cc[VMIN] = 1;
845   ts.c_lflag &= ~(ICANON|ECHO|ISIG);
846   ts.c_iflag = 0;
847   tcsetattr (gdk_display->tty_fd, TCSAFLUSH, &ts);
848
849   tcsetpgrp (gdk_display->tty_fd, getpgrp());
850
851   write_string (gdk_display->tty_fd, cursoroff_str);
852   
853   ioctl (gdk_display->tty_fd, KDSKBMODE, K_XLATE);
854
855   kb->fd = gdk_display->tty_fd;
856   kb->io = g_io_channel_unix_new (kb->fd);
857   kb->io_tag = g_io_add_watch (kb->io,
858                                G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
859                                xlate_io,
860                                kb);
861   
862   return TRUE;
863 }
864
865 static void
866 xlate_close (GdkFBKeyboard *kb)
867 {
868   struct termios ts;
869   const char cursoron_str[] = "\033c\033[3g\033]R";
870
871   write_string (gdk_display->tty_fd, cursoron_str);
872
873   tcgetattr (gdk_display->tty_fd, &ts);
874   ts.c_lflag |= (ICANON|ECHO|ISIG);
875   tcsetattr (gdk_display->tty_fd, TCSAFLUSH, &ts);
876   
877   g_source_remove (kb->io_tag);
878   g_io_channel_unref (kb->io);
879   kb->fd = -1;
880   /* don't close kb->fd, it is the tty from gdk_display */
881 }
882
883 static guint
884 xlate_lookup (GdkFBKeyboard       *kb,
885               const GdkKeymapKey  *key)
886 {
887   if (key->group != 0)
888     return 0;
889   if (key->level != 0)
890     return 0;
891   return key->keycode;
892 }
893
894 static gboolean
895 xlate_translate (GdkFBKeyboard       *kb,
896                  guint                hardware_keycode,
897                  GdkModifierType      state,
898                  gint                 group,
899                  guint               *keyval,
900                  gint                *effective_group,
901                  gint                *level,
902                  GdkModifierType     *consumed_modifiers)
903 {
904   if (keyval)
905     *keyval = hardware_keycode;
906   if (effective_group)
907     *effective_group = 0;
908   if (level)
909     *level = 0;
910   if (consumed_modifiers)
911     *consumed_modifiers = 0;
912   return TRUE;
913 }
914
915 static gboolean
916 xlate_get_for_keyval (GdkFBKeyboard       *kb,
917                       guint                keyval,
918                       GdkKeymapKey       **keys,
919                       gint                *n_keys)
920 {
921   *n_keys = 1;
922   *keys = g_new (GdkKeymapKey, 1);
923   (*keys)->keycode = keyval;
924   (*keys)->group = 0;
925   (*keys)->level = 0;
926   return TRUE;
927 }
928
929 static gboolean
930 xlate_get_for_keycode (GdkFBKeyboard       *kb,
931                        guint                hardware_keycode,
932                        GdkKeymapKey       **keys,
933                        guint              **keyvals,
934                        gint                *n_entries)
935 {
936   if (keys)
937     {
938       *keys = g_new (GdkKeymapKey, 1);
939       (*keys)->keycode = hardware_keycode;
940       (*keys)->level = 0;
941       (*keys)->group = 0;
942     }
943   if (keyvals)
944     {
945       *keyvals = g_new (guint, 1);
946       **keyvals = hardware_keycode;
947     }
948   if (n_entries)
949     *n_entries = 1;
950
951   return TRUE;
952 }
953
954 /* Raw keyboard support */
955
956 static const guint trans_table[256][3] = {
957   /* 0x00 */
958   {0, 0, 0},
959   {GDK_Escape, 0, 0},
960   {'1', '!', 0},
961   {'2', '@', 0},
962   {'3', '#', 0},
963   {'4', '$', 0},
964   {'5', '%', 0},
965   {'6', '^', 0},
966   {'7', '&', 0},
967   {'8', '*', 0},
968   {'9', '(', 0},
969   {'0', ')', 0},
970   {'-', '_', 0},
971   {'=', '+', 0},
972   {GDK_BackSpace, 0, 0},
973   {GDK_Tab, 0, 0},
974
975   /* 0x10 */
976   {'q', 'Q', 0},
977   {'w', 'W', 0},
978   {'e', 'E', 0},
979   {'r', 'R', 0},
980   {'t', 'T', 0},
981   {'y', 'Y', 0},
982   {'u', 'U', 0},
983   {'i', 'I', 0},
984   {'o', 'O', 0},
985   {'p', 'P', 0},
986   {'[', '{', 0},
987   {']', '}', 0},
988   {GDK_Return, 0, 0},
989   {GDK_Control_L, 0, 0}, /* mod */
990   {'a', 'A', 0},
991   {'s', 'S', 0},
992
993         /* 0x20 */
994   {'d', 'D', 0},
995   {'f', 'F', 0},
996   {'g', 'G', 0},
997   {'h', 'H', 0},
998   {'j', 'J', 0},
999   {'k', 'K', 0},
1000   {'l', 'L', 0},
1001   {';', ':', 0},
1002   {'\'', '"', 0},
1003   {'`', '~', 0},
1004   {GDK_Shift_L, 0, 0}, /* mod */
1005   {'\\', 0, 0},
1006   {'z', 0, 0},
1007   {'x', 0, 0},
1008   {'c', 0, 0},
1009
1010   {'v', 'V', 0},
1011
1012         /* 0x30 */
1013   {'b', 'B', 0},
1014   {'n', 'N', 0},
1015   {'m', 'M', 0},
1016   {',', 0, 0},
1017   {'.', 0, 0},
1018   {'/', 0, 0},
1019   {GDK_Shift_R, 0, 0}, /* mod */
1020   {GDK_KP_Multiply, 0, 0},
1021   {0, 0, 0},
1022   {GDK_space, 0, 0},
1023   {0, 0, 0},
1024   {GDK_F1, 0, 0},
1025   {GDK_F2, 0, 0},
1026   {GDK_F3, 0, 0},
1027   {GDK_F4, 0, 0},
1028   {GDK_F5, 0, 0},
1029
1030         /* 0x40 */
1031   {GDK_F6, 0, 0},
1032   {GDK_F7, 0, 0},
1033   {GDK_F8, 0, 0},
1034   {GDK_F9, 0, 0},
1035   {GDK_F10, 0, 0},
1036   {0, 0, 0},
1037   {0, 0, 0},
1038   {'7', 0, 0},
1039   {'8', 0, 0},
1040   {'9', 0, 0},
1041   {'-', 0, 0},
1042   {'4', 0, 0},
1043   {'5', 0, 0},
1044   {'6', 0, 0},
1045   {'+', 0, 0},
1046   {'1', 0, 0},
1047
1048         /* 0x50 */
1049   {'2', 0, 0},
1050   {'3', 0, 0},
1051   {'0', 0, 0},
1052   {'.', 0, 0},
1053   {0, 0, 0},
1054   {0, 0, 0},
1055   {0, 0, 0},
1056   {GDK_F11, 0, 0},
1057   {GDK_F12, 0, 0},
1058   {0, 0, 0},
1059   {0, 0, 0},
1060   {0, 0, 0},
1061   {0, 0, 0},
1062   {0, 0, 0},
1063   {0, 0, 0},
1064   {0, 0, 0},
1065
1066         /* 0x60 */
1067   {GDK_Return, 0, 0},
1068   {0, 0, 0},
1069   {0, 0, 0},
1070   {0, 0, 0},
1071   {0, 0, 0},
1072   {0, 0, 0},
1073   {GDK_Home, 0, 0},
1074   {GDK_Up, 0, 0},
1075   {GDK_Page_Up, 0, 0},
1076   {GDK_Left, 0, 0},
1077   {GDK_Right, 0, 0},
1078   {GDK_End, 0, 0},
1079   {GDK_Down, 0, 0},
1080   {GDK_Page_Down, 0, 0},
1081   {GDK_Insert, 0, 0},
1082   {GDK_Delete, 0, 0},
1083
1084         /* 0x70 */
1085   {0, 0, 0},
1086   {0, 0, 0},
1087   {0, 0, 0},
1088   {0, 0, 0},
1089   {0, 0, 0},
1090   {0, 0, 0},
1091   {0, 0, 0},
1092   {0, 0, 0},
1093   {0, 0, 0},
1094   {0, 0, 0},
1095   {0, 0, 0},
1096   {0, 0, 0},
1097   {0, 0, 0},
1098   {0, 0, 0},
1099   {0, 0, 0},
1100   {0, 0, 0},
1101
1102         /* 0x80 */
1103   {0, 0, 0},
1104   {0, 0, 0},
1105   {0, 0, 0},
1106   {0, 0, 0},
1107   {0, 0, 0},
1108   {0, 0, 0},
1109   {0, 0, 0},
1110   {0, 0, 0},
1111   {0, 0, 0},
1112   {0, 0, 0},
1113   {0, 0, 0},
1114   {0, 0, 0},
1115   {0, 0, 0},
1116   {0, 0, 0},
1117   {0, 0, 0},
1118   {0, 0, 0},
1119
1120         /* 0x90 */
1121   {0, 0, 0},
1122   {0, 0, 0},
1123   {0, 0, 0},
1124   {0, 0, 0},
1125   {0, 0, 0},
1126   {0, 0, 0},
1127   {0, 0, 0},
1128   {0, 0, 0},
1129   {0, 0, 0},
1130   {0, 0, 0},
1131   {0, 0, 0},
1132   {0, 0, 0},
1133   {0, 0, 0},
1134   {0, 0, 0},
1135   {0, 0, 0},
1136   {0, 0, 0},
1137
1138         /* 0xA0 */
1139   {0, 0, 0},
1140   {0, 0, 0},
1141   {0, 0, 0},
1142   {0, 0, 0},
1143   {0, 0, 0},
1144   {0, 0, 0},
1145   {0, 0, 0},
1146   {0, 0, 0},
1147   {0, 0, 0},
1148   {0, 0, 0},
1149   {0, 0, 0},
1150   {0, 0, 0},
1151   {0, 0, 0},
1152   {0, 0, 0},
1153   {0, 0, 0},
1154   {0, 0, 0},
1155
1156         /* 0xB0 */
1157   {0, 0, 0},
1158   {0, 0, 0},
1159   {0, 0, 0},
1160   {0, 0, 0},
1161   {0, 0, 0},
1162   {0, 0, 0},
1163   {0, 0, 0},
1164   {0, 0, 0},
1165   {0, 0, 0},
1166   {0, 0, 0},
1167   {0, 0, 0},
1168   {0, 0, 0},
1169   {0, 0, 0},
1170   {0, 0, 0},
1171   {0, 0, 0},
1172   {0, 0, 0},
1173
1174         /* 0xC0 */
1175   {0, 0, 0},
1176   {0, 0, 0},
1177   {0, 0, 0},
1178   {0, 0, 0},
1179   {0, 0, 0},
1180   {0, 0, 0},
1181   {0, 0, 0},
1182   {0, 0, 0},
1183   {GDK_Up, 0, 0},
1184   {0, 0, 0},
1185   {0, 0, 0},
1186   {GDK_Left, 0, 0},
1187   {0, 0, 0},
1188   {GDK_Right, 0, 0},
1189   {0, 0, 0},
1190   {0, 0, 0},
1191
1192         /* 0xD0 */
1193   {GDK_Down, 0, 0},
1194   {0, 0, 0},
1195   {0, 0, 0},
1196   {0, 0, 0},
1197   {0, 0, 0},
1198   {0, 0, 0},
1199   {0, 0, 0},
1200   {0, 0, 0},
1201   {0, 0, 0},
1202   {0, 0, 0},
1203   {0, 0, 0},
1204   {0, 0, 0},
1205   {0, 0, 0},
1206   {0, 0, 0},
1207   {0, 0, 0},
1208   {0, 0, 0},
1209
1210         /* 0xE0 */
1211   {0, 0, 0},
1212   {0, 0, 0},
1213   {0, 0, 0},
1214   {0, 0, 0},
1215   {0, 0, 0},
1216   {0, 0, 0},
1217   {0, 0, 0},
1218   {0, 0, 0},
1219   {0, 0, 0},
1220   {0, 0, 0},
1221   {0, 0, 0},
1222   {0, 0, 0},
1223   {0, 0, 0},
1224   {0, 0, 0},
1225   {0, 0, 0},
1226   {0, 0, 0},
1227
1228         /* 0xF0 */
1229   {0, 0, 0},
1230   {0, 0, 0},
1231   {0, 0, 0},
1232   {0, 0, 0},
1233   {0, 0, 0},
1234   {0, 0, 0},
1235   {0, 0, 0},
1236   {0, 0, 0},
1237   {0, 0, 0},
1238   {0, 0, 0},
1239   {0, 0, 0},
1240   {0, 0, 0},
1241   {0, 0, 0},
1242   {0, 0, 0},
1243   {0, 0, 0},
1244   {0, 0, 0},
1245 };
1246
1247 static gboolean
1248 raw_io (GIOChannel *gioc,
1249         GIOCondition cond,
1250         gpointer data)
1251 {
1252   GdkFBKeyboard *k = data;
1253   guchar buf[128];
1254   int i, n;
1255
1256   n = read (k->fd, buf, sizeof(buf));
1257   if (n <= 0)
1258     g_error("Nothing from keyboard!");
1259
1260   for (i = 0; i < n; i++)
1261     {
1262       guchar keycode;
1263       gboolean key_up;
1264       char dummy[2];
1265       int len;
1266       int mod;
1267       guint keyval;
1268
1269       keycode = buf[i] & 0x7F;
1270       key_up = buf[i] & 0x80;
1271
1272       if (keycode > G_N_ELEMENTS (trans_table))
1273         {
1274           g_warning ("Unknown keycode");
1275           continue;
1276         }
1277
1278       if ( (keycode == 0x1D) /* left Ctrl */
1279            || (keycode == 0x9D) /* right Ctrl */
1280            || (keycode == 0x38) /* left Alt */
1281            || (keycode == 0xB8) /* right Alt */
1282            || (keycode == 0x2A) /* left Shift */
1283            || (keycode == 0x36) /* right Shift */)
1284         {
1285           switch (keycode)
1286             {
1287             case 0x1D: /* Left Ctrl */
1288             case 0x9D: /* Right Ctrl */
1289               if (key_up)
1290                 k->modifier_state &= ~GDK_CONTROL_MASK;
1291               else
1292                 k->modifier_state |= GDK_CONTROL_MASK;
1293               break;
1294             case 0x38: /* Left Alt */
1295             case 0xB8: /* Right Alt */
1296               if (key_up)
1297                 k->modifier_state &= ~GDK_MOD1_MASK;
1298               else
1299                 k->modifier_state |= GDK_MOD1_MASK;
1300               break;
1301             case 0x2A: /* Left Shift */
1302             case 0x36: /* Right Shift */
1303               if (key_up)
1304                 k->modifier_state &= ~GDK_SHIFT_MASK;
1305               else
1306                 k->modifier_state |= GDK_SHIFT_MASK;
1307               break;
1308             }
1309           continue; /* Don't generate events for modifiers */
1310         }
1311
1312       if (keycode == 0x3A /* Caps lock */)
1313         {
1314           if (!key_up)
1315             k->caps_lock = !k->caps_lock;
1316           
1317           ioctl (k->fd, KDSETLED, k->caps_lock ? LED_CAP : 0);
1318           continue;
1319         }
1320
1321       if (trans_table[keycode][0] >= GDK_F1 &&
1322           trans_table[keycode][0] <= GDK_F35 &&
1323           (k->modifier_state & GDK_MOD1_MASK))
1324         {
1325           if (key_up) /* Only switch on release */
1326             {
1327               gint vtnum = trans_table[keycode][0] - GDK_F1 + 1;
1328
1329               /* Do the whole funky VT switch thing */
1330               ioctl (gdk_display->console_fd, VT_ACTIVATE, vtnum);
1331             }
1332
1333           continue;
1334         }
1335
1336       keyval = 0;
1337       mod = 0;
1338       if (k->modifier_state & GDK_CONTROL_MASK)
1339         mod = 2;
1340       else if (k->modifier_state & GDK_SHIFT_MASK)
1341         mod = 1;
1342       do {
1343         keyval = trans_table[keycode][mod--];
1344       } while (!keyval && (mod >= 0));
1345
1346       if (k->caps_lock && (keyval >= 'a') && (keyval <= 'z'))
1347         keyval = toupper (keyval);
1348
1349       if (!keyval)
1350         continue;
1351
1352       len = isprint (keyval) ? 1 : 0;
1353       dummy[0] = keyval;
1354       dummy[1] = 0;
1355
1356       gdk_fb_handle_key (keycode,
1357                          keyval,
1358                          k->modifier_state,
1359                          0,
1360                          (len)?g_strdup(dummy):NULL,
1361                          len,
1362                          key_up);
1363     }
1364
1365   return TRUE;
1366 }
1367
1368 static gboolean
1369 raw_open (GdkFBKeyboard *kb)
1370 {
1371   const char cursoroff_str[] = "\033[?1;0;0c";
1372   struct termios ts;
1373   
1374   tcgetattr (gdk_display->tty_fd, &ts);
1375   ts.c_cc[VTIME] = 0;
1376   ts.c_cc[VMIN] = 1;
1377   ts.c_lflag &= ~(ICANON|ECHO|ISIG);
1378   ts.c_iflag = 0;
1379   tcsetattr (gdk_display->tty_fd, TCSAFLUSH, &ts);
1380
1381   tcsetpgrp (gdk_display->tty_fd, getpgrp());
1382
1383   write_string (gdk_display->tty_fd, cursoroff_str);
1384   
1385   if (ioctl (gdk_display->tty_fd, KDSKBMODE, K_MEDIUMRAW) < 0)
1386     {
1387       g_warning ("setting tty to K_MEDIUMRAW failed (are you root?)");
1388       return FALSE;
1389     }
1390
1391   kb->fd = gdk_display->tty_fd;
1392   kb->io = g_io_channel_unix_new (kb->fd);
1393   kb->io_tag = g_io_add_watch (kb->io,
1394                                G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1395                                raw_io,
1396                                kb);
1397   
1398   return TRUE;
1399 }
1400
1401 static void
1402 raw_close (GdkFBKeyboard *kb)
1403 {
1404   struct termios ts;
1405   const char cursoron_str[] = "\033c";
1406
1407   write_string (gdk_display->tty_fd, cursoron_str);
1408
1409   tcgetattr (gdk_display->tty_fd, &ts);
1410   ts.c_lflag |= (ICANON|ECHO|ISIG);
1411   tcsetattr (gdk_display->tty_fd, TCSAFLUSH, &ts);
1412   
1413   ioctl (gdk_display->tty_fd, KDSKBMODE, K_XLATE);
1414
1415   g_source_remove (kb->io_tag);
1416   g_io_channel_unref (kb->io);
1417   /* don't close kb->fd, it is the tty from gdk_display */
1418 }
1419
1420 static guint
1421 raw_lookup (GdkFBKeyboard       *kb,
1422             const GdkKeymapKey  *key)
1423 {
1424   if (key->group != 0)
1425     return 0;
1426   if ((key->keycode < 0) || (key->keycode >= 256))
1427     return 0;
1428   if ((key->level < 0) || (key->level >= 3))
1429     return 0;
1430   return trans_table[key->keycode][key->level];
1431 }
1432
1433 static gboolean
1434 raw_translate (GdkFBKeyboard       *kb,
1435                guint                hardware_keycode,
1436                GdkModifierType      state,
1437                gint                 group,
1438                guint               *keyval,
1439                gint                *effective_group,
1440                gint                *level,
1441                GdkModifierType     *consumed_modifiers)
1442 {
1443   guint tmp_keyval;
1444   gint tmp_level;
1445
1446   if (keyval)
1447     *keyval = 0;
1448   if (effective_group)
1449     *effective_group = 0;
1450   if (level)
1451     *level = 0;
1452   if (consumed_modifiers)
1453     *consumed_modifiers = 0;
1454
1455   if ((hardware_keycode < 0) || (hardware_keycode >= 256))
1456     return FALSE;
1457
1458   if (group != 0)
1459     return FALSE;
1460
1461   if (state & GDK_CONTROL_MASK)
1462     tmp_level = 2;
1463   else if (state & GDK_SHIFT_MASK)
1464     tmp_level = 1;
1465   else
1466     tmp_level = 0;
1467
1468   do {
1469     tmp_keyval = trans_table[hardware_keycode][tmp_level --];
1470   } while (!tmp_keyval && (tmp_level >= 0));
1471
1472   if (keyval)
1473     *keyval = tmp_keyval;
1474   if (level)
1475     *level = tmp_level;
1476
1477   return TRUE;
1478 }
1479
1480 static gboolean
1481 raw_get_for_keyval (GdkFBKeyboard       *kb,
1482                     guint                keyval,
1483                     GdkKeymapKey       **keys,
1484                     gint                *n_keys)
1485 {
1486   GArray *retval;
1487   int i, j;
1488
1489   retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
1490
1491   for (i = 0; i < 256; i++)
1492     for (j = 0; j < 3; j++)
1493       if (trans_table[i][j] == keyval)
1494         {
1495           GdkKeymapKey key;
1496
1497           key.keycode = i;
1498           key.group = 0;
1499           key.level = j;
1500
1501           g_array_append_val (retval, key);
1502         }
1503
1504   if (retval->len > 0)
1505     {
1506       *keys = (GdkKeymapKey*) retval->data;
1507       *n_keys = retval->len;
1508     }
1509   else
1510     {
1511       *keys = NULL;
1512       *n_keys = 0;
1513     }
1514
1515   g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
1516
1517   return *n_keys > 0;
1518 }
1519
1520 static gboolean
1521 raw_get_for_keycode (GdkFBKeyboard       *kb,
1522                      guint                hardware_keycode,
1523                      GdkKeymapKey       **keys,
1524                      guint              **keyvals,
1525                      gint                *n_entries)
1526 {
1527   GArray *key_array;
1528   GArray *keyval_array;
1529   int i;
1530
1531   if (hardware_keycode <= 0 ||
1532       hardware_keycode >= 256)
1533     { 
1534       if (keys)
1535         *keys = NULL;
1536       if (keyvals)
1537         *keyvals = NULL;
1538
1539       *n_entries = 0;
1540       return FALSE;
1541     }
1542
1543   if (keys)
1544     key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
1545   else
1546     key_array = NULL;
1547
1548   if (keyvals)
1549     keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
1550   else
1551     keyval_array = NULL;
1552
1553   for (i = 0; i < 3; i++)
1554     {
1555       if (key_array)
1556         {
1557           GdkKeymapKey key;
1558
1559           key.keycode = hardware_keycode;
1560           key.group = 0;
1561           key.level = i;
1562
1563           g_array_append_val (key_array, key);
1564         }
1565
1566       if (keyval_array)
1567         {
1568           g_array_append_val (keyval_array, trans_table[hardware_keycode][i]);
1569         }
1570     }
1571
1572   if ((key_array && key_array->len > 0) ||
1573       (keyval_array && keyval_array->len > 0))
1574     { 
1575       if (keys)
1576         *keys = (GdkKeymapKey*) key_array->data;
1577
1578       if (keyvals)
1579         *keyvals = (guint*) keyval_array->data;
1580
1581       if (key_array)
1582         *n_entries = key_array->len;
1583       else
1584         *n_entries = keyval_array->len;
1585     }
1586   else
1587     { 
1588       if (keys)
1589         *keys = NULL;
1590
1591       if (keyvals)
1592         *keyvals = NULL;
1593
1594       *n_entries = 0;
1595     }
1596
1597   if (key_array)
1598     g_array_free (key_array, key_array->len > 0 ? FALSE : TRUE);
1599   if (keyval_array)
1600     g_array_free (keyval_array, keyval_array->len > 0 ? FALSE : TRUE);
1601
1602   return *n_entries > 0;
1603 }