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