use system libraries
[xkbdbthid.git] / xkbd-0.8.15_bthid / src / libvirtkeys.c
1 /*
2  * virtkeyslib - Routines to support virtual keyboards and handwriting input under X.
3  * Copyright (c) 2000, Merle F. McClelland for CompanionLink
4  * 
5  * See the files COPYRIGHT and LICENSE for distribution information.
6  * 
7  */
8
9 /***************************************************************************** 
10  * Includes
11  ****************************************************************************/
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <X11/X.h>
15 #include <X11/Xlib.h>
16 #include <X11/Xlibint.h>
17 #include <X11/Xutil.h>
18 #include <X11/cursorfont.h>
19 #include <X11/keysymdef.h>
20 #include <X11/keysym.h>
21 #include <X11/extensions/XTest.h>
22 #include <X11/Xos.h>
23 #include <X11/Xproto.h>
24 #include <ctype.h>
25
26 // Note that we use this local copy here, because the installed version may or
27 // may not exist, and may not (yet) be up to date.
28
29 //#include "hidcd.h"
30 #include "libvirtkeys.h"
31
32 int debug;
33
34 // We keep these here as static variables so that Tk/TCL routines don't have to deal with them
35
36 static Display *dpy = NULL;
37 static KeySym *keymap = NULL;
38 static int minKeycode = 0;
39 static int maxKeycode = 0;
40 static int keysymsPerKeycode = 0;
41
42 // #define USEMODEMODIFIERS 0
43 // #define USEMODIFIERS 1
44
45 // Set USEMODIFIERS only if there is no XKB entension in the server - modifiers do not work
46 // the same way if it is enabled. For testing on my desktop system, and for general use, I
47 // leave this option off and it works fine on both XKB-enabled and non-enabled servers.
48
49 // These variables are set when we parse the Modifier Map - we look up the KeySyms
50 // for the modifiers and match them to the specific KeySyms for Alt and Meta (left or right)
51 // and remember the index for use later on.
52
53 #define noModifierMapIndex (Mod5MapIndex + 1)
54 #define numModifierIndexes (noModifierMapIndex + 1)
55 int ShiftModifierIndex = 0;
56 int AltModifierIndex = 0;
57 int MetaModifierIndex = 0;
58 #ifdef USEMODEMODIFER
59 int ModeModifierIndex = 0;
60 int ModeModifierMask = 0;
61 #else
62 int ModeSwitchKeyCode = 0;
63 #endif
64
65 // Table of modifiers
66
67 KeyCode modifierTable[numModifierIndexes];
68
69 static int createModifierTable()
70 {
71         XModifierKeymap *modifiers;
72         KeyCode *kp;
73         KeyCode kc;
74         KeySym ks;
75         int modifier_index;
76         int modifier_key;
77
78         if (dpy == NULL)
79                 return FALSE;
80
81         // Right off the bat, we check to see if the XK_Mode_switch keycode is assigned to a Keycode.
82         // It must be in order for everything to work. Also, this must not be a shifted code, either.
83
84         kc = XKeysymToKeycode(dpy, XK_Mode_switch);
85
86         if (kc == 0)
87         {
88                 fprintf(stderr, "Mode_switch must be assigned to an unshifted keycode and a modifier.\n");
89                 return FALSE;
90         }
91
92         // Now we look up the Keycode, using index 0 (unshifted). If the returned KeySym is not equal
93         // to XK_Mode_switch, then it's an error.
94
95         if (XKeycodeToKeysym(dpy, kc, 0) != XK_Mode_switch)
96         {
97                 fprintf(stderr, "Mode_switch must be assigned to an unshifted keycode and a modifier.\n");
98                 return FALSE;
99         }
100
101         // We fake-out the lookup of the Mode_switch modifer for now, since the Mode_switch scheme isn't
102         // directly usable when the KXB extension is used. Actually, it doesn't interfere with the use
103         // of Mode_switch, but we can't generate fake events properly to do XLookupString in the
104         // lookup routine (XKB uses different modifier bits for Mode_switch state). So, we worked
105         // around that below, and all we have to do here is save the KeyCode for the XK_Mode_switch
106         // character.
107
108         ModeSwitchKeyCode = kc;
109         
110         // Get get the list of all modifiers from the server. Note that a single modifier
111         // can be represented by multiple KeyCodes. For example, there are two Shift keys, each with
112         // its own KeyCode. Pressing either indicates the "Shift" modifier state. We just need to
113         // get the first KeyCode for each modifier, and put that KeyCode in our modifierTable for
114         // use when sending the character KeyCodes. Entries in the table returned by XGetModifierMapping
115         // are 0 if the entry indicates no code exists for the entry.
116
117         modifiers = XGetModifierMapping(dpy);
118
119         kp = modifiers->modifiermap;    
120
121         // Now, iterate through the list, finding the first non-zero keycode for each
122         // modifier index. If no modifier keycode is found, that's ok, since not all
123         // modifiers exist on all systems. We have a fake modifer representing the "None"
124         // case that immediately follows Mod5MapIndex in the index list and tables. This
125         // doesn't correspond to any real modifier.
126
127         for (modifier_index = 0; modifier_index < 8; modifier_index++)
128         {
129                 modifierTable[modifier_index] = 0; // Initialze the table entry
130
131                 // Now, look through the array of modifiers for the first non-zero value
132
133                 for (modifier_key = 0; modifier_key < modifiers->max_keypermod; modifier_key++)
134                 {
135                         int keycode = kp[modifier_index * modifiers->max_keypermod + modifier_key]; 
136
137                         if (keycode != 0)
138                         {
139                                 modifierTable[modifier_index] = keycode;
140                                 break;
141                         }
142                 }
143         }
144
145         modifierTable[noModifierMapIndex] = 0; // Initialze the "None" entry
146
147 #ifdef USEMODEMODIFIER
148         // We need to find the modifier associated with the Mode_switch key. - ACTUALLY, DOESN'T WORK with XKB EXTENSION!
149
150         ModeModifierIndex = -1;
151 #endif
152
153         // Now determine which of the Mod1 through Mod5 codes correspond to the Alt, Meta, etc. modifiers
154
155         for (modifier_index = Mod1MapIndex; modifier_index <= Mod5MapIndex; modifier_index++)
156         {
157                 if (modifierTable[modifier_index])
158                 {
159                         ks = XKeycodeToKeysym(dpy, modifierTable[modifier_index], 0);
160                         switch (ks)
161                         {
162                         case XK_Meta_R:
163                         case XK_Meta_L:
164
165                                 MetaModifierIndex = modifier_index;
166                                 break;
167
168                         case XK_Alt_R:
169                         case XK_Alt_L:
170
171                                 AltModifierIndex = modifier_index;
172                                 break;
173
174                         case XK_Shift_R:
175                         case XK_Shift_L:
176
177                                 ShiftModifierIndex = modifier_index;
178                                 break;
179
180 #ifdef USEMODEMODIFER
181                         case XK_Mode_switch:
182
183                                 ModeModifierIndex = modifier_index;
184                                 ModeModifierMask = (1 << modifier_index);       // Create a mask for the ModeModifier 
185                                 break;
186 #endif
187                         }
188                 }
189         }
190
191 #ifdef USEMODEMODIFER
192         // If the Mode_switch key is not assigned to a modifier, we have an error
193
194         if (ModeModifierIndex == -1)
195                 return FALSE;
196 #endif
197         if (debug)
198         {
199                 for (modifier_index = ShiftMapIndex; modifier_index < numModifierIndexes; modifier_index++)
200                 fprintf(stderr, "Keycode for modifier index %d is %x\n", modifier_index, modifierTable[modifier_index]);
201                 fprintf(stderr, "Meta index is %d\n", MetaModifierIndex);
202                 fprintf(stderr, "Alt index is %d\n", AltModifierIndex);
203                 fprintf(stderr, "Shift index is %d\n", ShiftModifierIndex);
204 #ifdef USEMODEMODIFER
205                 fprintf(stderr, "Mode_switch index is %d\n", ModeModifierIndex);
206                 fprintf(stderr, "ModeModiferMask is %d\n", ModeModifierMask);
207 #else
208                 fprintf(stderr, "Mode_switch KeyCode is %d\n", ModeSwitchKeyCode);
209 #endif
210         }
211
212         return TRUE;
213 }
214
215 // This routine looks up the KeySym table in the server. If the table contains 4 columns, it is already
216 // set up for use with the Mode_Shift key. If so, we just return it as-is. If not, a copy is made of the
217 // table into a new table that has empty definitions for the extra columns.
218
219 int loadKeySymTable() 
220 {
221         if (dpy == NULL)
222                 return FALSE;
223
224         // Now we load other variables fromthe server that we use in the other routines.
225
226         XDisplayKeycodes(dpy, &minKeycode, &maxKeycode);
227         keymap = XGetKeyboardMapping(dpy, minKeycode, 
228                                         (maxKeycode - minKeycode + 1), 
229                                         &keysymsPerKeycode);
230
231         if (debug)
232         {
233                 int k;
234                 int n;
235
236                 for (k = 0; k < (maxKeycode - minKeycode + 1); k++)
237                 {
238                         fprintf(stderr, "%-10d", (k + minKeycode));
239                         for (n = 0; n < keysymsPerKeycode; n++)
240                                 fprintf(stderr, "%-10s\t", XKeysymToString(keymap[(k * keysymsPerKeycode + n)]));
241                         fprintf(stderr, "\n");
242                 }
243         }
244
245         // We take the KeySym table that the server gave us, and check to see if it 
246         // contains 4 columns (i.e. 4 keysymsPerKeycode). If it does, the routine just
247         // returns, and we will use the table as-is. If it doesn't contain 4 columns, the
248         // routine copies the passed table into one that does, and returns that. That allows
249         // us to utilitize the "Mode_Shift" key to access columns 2 and 3 (of 0..3), and to
250         // assign those columns to any KeySyms that don't currently exist in the table. That
251         // allows the program to autoconfigure the server to include definitions for KeySyms 
252         // that the Keyboard config file references, whether or not they exist in the table
253         // before the program runs.
254
255         // We check to see if the table contains 2 or 4 columns. Any other configuration is
256         // NOT supported! If 4, then just return the table that was returned by the GetKeyboardMapping
257         // call.
258
259         if (keysymsPerKeycode == 4)
260                 return TRUE;
261
262         if (keysymsPerKeycode == 2)
263         {
264                 // We have to make a copy of the table by allocating one that has 4 columns instead of
265                 // 2, copying the table entries, and then initializing all unused entries to NoSymbol.
266
267                 int k;
268                 int n;
269                 KeySym *newKeymap = Xmalloc((maxKeycode - minKeycode + 1) * 4 * sizeof(KeySym));
270
271                 for (k = 0; k < (maxKeycode - minKeycode + 1); k++)
272                 {
273                         // Initialize the new entries
274
275                         for (n = 2; n < 4; n++)
276                                 newKeymap[((k * 4) + n)] = NoSymbol;
277
278                         // Copy over the existing ones
279
280                         for (n = 0; n < keysymsPerKeycode; n++)
281                                 newKeymap[((k * 4) + n)] = keymap[((k * keysymsPerKeycode) + n)];
282                 }
283
284                 // Indicate that the new table has 4 entries per Keycode
285
286                 keysymsPerKeycode = 4;
287
288                 // Discard the old keymap
289
290                 XFree(keymap);
291
292                 keymap = newKeymap;
293
294                 return TRUE;
295         }
296         else
297         {
298                 fprintf(stderr, "Sorry - server Keyboard map doesn't contain either 2 or 4 KeySyms per Keycode - unsupported!\n");
299                 return FALSE;
300         }
301 }
302
303 // This routine takes a KeySym, a pointer to a keycodeEntry table array, and an optional labelBuffer
304 // pointer. It looks up the specified KeySym in the table of KeySym&KeyCodes, and stores the proper
305 // sequence of KeyCodes that should be generated, including Modifier keys, to cause the XServer to
306 // generate the KeySym on the other end of the wire. The optional labelBuffer pointer will be
307 // set to point to an allocated buffer containing the ASCII string corresponding to the label on the
308 // key. Not all programs care about this, so passing NULL for the pointer means no label will be
309 // returned.
310
311 int lookupKeyCodeSequence(KeySym ks, struct keycodeEntry *table, char **labelBuffer)
312 {
313         int keycode;
314         int column;
315         int availableKeycode;
316         int availableColumn;
317         int assignedKeycode;
318         int assignedColumn;
319         int found = FALSE;
320 #ifdef USEMODIFIERS
321         int len;
322         XEvent fakeEvent;
323         int modifiers;
324 #else
325         KeyCode ModeModifier;
326 #endif
327
328         // If these aren't set, then we aren't initialized
329
330         if ((dpy == NULL) || (keymap == NULL))
331                 return FALSE;
332
333         assignedColumn = -1;
334         assignedKeycode = -1;
335
336         availableColumn = -1;
337         availableKeycode = -1;
338
339         // We do two things here - we look to see if the KeySym is already assigned, and if so,
340         // save its position in the table, while at the same time looking for the next available
341         // NoSymbol entry (for possible assignment).
342
343         for (keycode = 0; ((keycode < (maxKeycode - minKeycode + 1)) && !found); keycode++)
344         {
345                 for (column = 0; ((column < keysymsPerKeycode) && !found); column++)
346                 {
347                         if (keymap[(keycode * keysymsPerKeycode + column)] == ks)
348                         {
349                                 found = TRUE;
350                                 assignedKeycode = keycode;
351                                 assignedColumn = column;
352                         }
353                         else if (availableColumn == -1)
354                         {
355                                 // We only save the first one we find, but only if the unshifted column
356                                 // is NOT one of the modifier keys. This is extremely important. If we tack-on
357                                 // definitions to the columns 2 and 3 of a modifier key, expecially Shift,
358                                 // we will actually send the wrong code if Mode_switch is followed by Shift.
359
360                                 if (!IsModifierKey(keymap[(keycode * keysymsPerKeycode + 0)]))
361                                 {
362                                         if (keymap[(keycode * keysymsPerKeycode + column)] == NoSymbol)
363                                         {
364                                                 availableColumn = column;
365                                                 availableKeycode = keycode;
366                                         }
367                                 }
368                         }
369                 }
370         }
371
372         if (!found)
373         {
374
375                 if (debug)
376                         fprintf(stderr, "KeySym not found - will assign at Keycode %d, Column %d\n", 
377                                 (availableKeycode + minKeycode), availableColumn);
378
379                 // We assign the KeySym to the next available NoSymbol entry, assuming there
380                 // is one! We can tell because availableColumn will not be -1 if we found an entry
381                 // that can be used.
382
383                 if (availableColumn == -1)
384                         return FALSE;
385
386                 // Ok. We can assign the KeySym to the entry in the table at the available Column and Keycode.
387                 // We must update the server when we do this, so we can look up the string associated with the
388                 // assigned KeySym. This can cause a lot of server thrashing the first time it's done.
389
390                 keymap[(availableKeycode * keysymsPerKeycode + availableColumn)] = ks;
391
392
393                 // We point to only the row that we are changing, and say that we are chaing just one. Note that
394                 // the keycode index passed must be based on minKeycode.
395
396                 XChangeKeyboardMapping(dpy, (availableKeycode + minKeycode), 
397                                 keysymsPerKeycode, &keymap[(availableKeycode * keysymsPerKeycode)], 1);
398
399                 assignedKeycode = availableKeycode;
400                 assignedColumn  = availableColumn;
401
402         }
403         else if (debug)
404                 fprintf(stderr, "KeySym %x found at Keycode %d, Column %d\n", (unsigned int)ks, (assignedKeycode + minKeycode), assignedColumn);
405
406
407         // If we get here, we assigned it. Now set up the table with the appropriate
408         // information
409
410 #ifdef USEMODIFIERS
411         modifiers = 0;
412         ModeModifier = modifierTable[ModeModifierIndex]; 
413 #else
414         ModeModifier = ModeSwitchKeyCode;
415 #endif
416
417         switch (assignedColumn)
418         {
419         case 0: // Unshifted case
420
421                 table[0].keycode = (assignedKeycode + minKeycode);      // Store the keycode
422                 table[0].direction = keyDownUp;         // Store the key direction (in this case, Down and Up)
423                 table[1].keycode = 0;                   // Store the sequence terminator
424
425                 break;
426
427         case 1: // Shifted case - we have to simulate pressing down the shift modifier, 
428                 // then the character key, then releasing shift
429
430                 table[0].keycode = modifierTable[ShiftMapIndex];// Store the keycode for the shift key
431                 table[0].direction = keyDown;           // Store the key direction (in this case, just Down)
432
433                 table[1].keycode = (assignedKeycode + minKeycode);      // Store the keycode
434                 table[1].direction = keyDownUp;         // Store the key direction (in this case, Down and Up)
435
436                 table[2].keycode = modifierTable[ShiftMapIndex];// Store the keycode for the shift key
437                 table[2].direction = keyUp;             // Store the key direction (in this case, just Up)
438
439                 table[3].keycode = 0;                   // Store the sequence terminator
440
441 #ifdef USEMODEMODIFER
442                 modifiers |= ShiftMask;                 // Add-in the modifier bit for the Mode_switch modifier
443 #endif
444                 break;
445
446         case 2: // Unshifted Mode_switch case
447                 table[0].keycode = ModeModifier;        // Store the keycode for the Mode switch code
448                 table[0].direction = keyDown;           // Store the key direction (in this case, Down)
449
450                 table[1].keycode = (assignedKeycode + minKeycode);      // Store the keycode
451                 table[1].direction = keyDownUp;         // Store the key direction (in this case, Down and Up)
452
453                 table[2].keycode = ModeModifier;        // Store the keycode for the Mode switch code
454                 table[2].direction = keyUp;             // Store the key direction (in this case, Up)
455
456                 table[3].keycode = 0;                   // Store the sequence terminator
457 #ifdef USEMODIFIERS
458                 modifiers |= ModeModifierMask;          // Add-in the modifier bit for the Mode_switch modifier
459 #endif
460                 break;
461
462         case 3:
463
464                 // Note that the order is important here - we first do the shift, so that the interpretation
465                 // of the shift key is not impacted by the ModeModifier. This accounts for key maps where the
466                 // interpretation of the shift key is not defined when Mode_switch is pressed first.
467
468                 table[0].keycode = modifierTable[ShiftMapIndex];// Store the keycode for the shift key
469                 table[0].direction = keyDown;   // Store the key direction (in this case, just Down)
470
471                 table[1].keycode = ModeModifier;        // Store the keycode for the Mode switch code
472                 table[1].direction = keyDown;           // Store the key direction (in this case, Down)
473
474                 table[2].keycode = (assignedKeycode + minKeycode);      // Store the keycode
475                 table[2].direction = keyDownUp;         // Store the key direction (in this case, Down and Up)
476
477                 table[3].keycode = ModeModifier;        // Store the keycode for the Mode switch code
478                 table[3].direction = keyUp;             // Store the key direction (in this case, Up)
479
480                 table[4].keycode = modifierTable[ShiftMapIndex];// Store the keycode for the shift key
481                 table[4].direction = keyUp;     // Store the key direction (in this case, just Up)
482
483                 table[5].keycode = 0;           // Store the sequence terminator
484
485 #ifdef USEMODEMODIFER
486                 modifiers |= (ShiftMask | ModeModifierMask);    // Add-in the modifier bit for the Mode_switch and Shift modifiers
487 #endif
488                 break;
489
490         }
491
492         // If the server is compiled with XKB, this does not work!!! The XKB extension uses additional state bits for
493         // Mode_switch, and the use of the ModeModifierMask doesn't work. So, we just interpret the KeySym directly for
494         // the label string.
495
496 #ifdef USEMODEMODIFER
497         // Now look up the string that represents the keycode in the correct state, taking
498         // into account the Shift and Mode_switch modifiers (set above).
499
500         fakeEvent.xkey.type = KeyPress;
501         fakeEvent.xkey.display = dpy;
502         fakeEvent.xkey.time = CurrentTime;
503         fakeEvent.xkey.x = fakeEvent.xkey.y = 0;
504         fakeEvent.xkey.x_root = fakeEvent.xkey.y_root = 0;
505         fakeEvent.xkey.state = modifiers;
506         fakeEvent.xkey.keycode = (assignedKeycode + minKeycode);
507
508         if (labelBuffer)
509         {
510                 *labelBuffer = malloc(MAXLABELLEN+1);
511
512                 len = XLookupString((XKeyEvent *)&fakeEvent, *labelBuffer, MAXLABELLEN, NULL, NULL);
513
514                 (*labelBuffer)[len] = '\0';
515
516                 if (debug)
517                         fprintf(stderr, "modifiers = %x, keycode = %d, len = %d, labelBuffer = '%s'\n", 
518                                 modifiers, fakeEvent.xkey.keycode, len, (len > 0 ? *labelBuffer : "(null)"));
519         }
520 #else
521         if (labelBuffer)
522         {
523                 *labelBuffer = malloc(2);
524                 if ((ks & 0xff00) == 0xff00)
525                         (*labelBuffer)[0] = ks;
526                 else
527                         (*labelBuffer)[0] = ks & 0xff;
528                 (*labelBuffer)[1] = '\0';
529                 if (debug)
530                         fprintf(stderr, "labelBuffer = '%s'\n", *labelBuffer);
531         }
532 #endif
533
534         return TRUE;
535 }
536
537 // Routine to test for and set up the XTest extension. Returns FALSE if the set up fails or if the extension
538 // isn't installed.
539
540 int setupXTest()
541 {
542         int event, error;
543         int major, minor;
544
545         if (dpy == NULL)
546                 return FALSE;
547
548         // does the display have the Xtest-extension?
549
550         if (!XTestQueryExtension(dpy, &event, &error, &major, &minor))
551         {
552                 // nope, extension not supported
553
554                 fprintf(stderr, "XTest extension not supported on server \"%s\"\n.", DisplayString(dpy));
555
556                 return FALSE;
557         }
558
559         // sync the server
560         XSync(dpy, True);
561
562         return TRUE;
563 }
564
565 void closeXTest()
566 {
567         if (dpy == NULL)
568                 return;
569
570         // discard and even flush all events on the remote display
571
572         XTestDiscard(dpy);
573
574         XFlush(dpy);
575 }
576
577
578 void sendKeySequence(struct keycodeEntry *entries, int controlMode, int metaMode, int altMode, int shiftMode)
579 {
580         int s = 0;
581         KeyCode kc;
582
583         if (entries == NULL)
584                 return;
585
586         // The Control, Meta, and Alt modifiers are set and unset outside the scope of the
587         // sequences in the table. The table sequences determine which column in the key table
588         // is selected, whereas the control, meta, and alt keys do not (they just set modifier
589         // bits in the receiving application. Thus, we press and unpress these modifiers before
590         // and after sending the sequence.
591
592         if (controlMode)
593                 sendKey(modifierTable[ControlMapIndex], keyDown);       // Send a down event for the control modifier key
594
595         if (metaMode)
596                 sendKey(modifierTable[MetaModifierIndex], keyDown);     // Send a down event for the meta modifier key
597
598         if (altMode)
599                 sendKey(modifierTable[AltModifierIndex], keyDown);      // Send a down event for the alt modifier key
600
601         if (shiftMode)
602                 sendKey(modifierTable[ShiftModifierIndex], keyDown);    // Send a down event for the shift modifier key
603
604         while ((kc = entries[s].keycode))
605         {
606                 enum keyDirection kd = entries[s].direction;
607
608                 sendKey(kc, kd);
609                 s++;
610         }
611
612         // Now send the corresponding up events for the modifiers
613
614         if (controlMode)
615                 sendKey(modifierTable[ControlMapIndex], keyUp);         // Send an up event for the control modifier key
616
617         if (metaMode)
618                 sendKey(modifierTable[MetaModifierIndex], keyUp);       // Send an up event for the meta modifier key
619
620         if (altMode)
621                 sendKey(modifierTable[AltModifierIndex], keyUp);        // Send an up event for the alt modifier key
622
623         if (shiftMode)
624                 sendKey(modifierTable[ShiftModifierIndex], keyUp);      // Send an up event for the shift modifier key
625
626 }
627
628 void sendKey(KeyCode character, enum keyDirection keydirection)
629 {
630         if (dpy == NULL)
631                 return;
632
633         switch (keydirection)
634         {
635         case keyDown:
636         
637                 if (debug)
638                         fprintf(stderr, "sending %04x key down\n", character);
639         
640                 //XTestFakeKeyEvent(dpy, (unsigned int) character, TRUE, 0);
641                 //bthid_send(character, 1);
642                 break;
643         
644         case keyUp:
645         
646                 if (debug)
647                         fprintf(stderr, "sending %04x key up\n", character);
648         
649                 //XTestFakeKeyEvent(dpy, (unsigned int) character, FALSE, 0);
650                 //bthid_send(character, 0);
651                 break;
652         
653         case keyDownUp:
654         
655                 if (debug)
656                         fprintf(stderr, "sending %04x key down\n", character);
657         
658                 //XTestFakeKeyEvent(dpy, (unsigned int) character, TRUE, 0);
659                 //bthid_send(character, 1);
660         
661                 if (debug)
662                         fprintf(stderr, "sending %04x key up\n", character);
663         
664                 //XTestFakeKeyEvent(dpy, (unsigned int) character, FALSE, 0);
665                 //bthid_send(character, 0);
666                 break;
667         }
668 }
669
670 //
671 // This routine does the basic setup needed for loading X server key tables and such
672 //
673
674 int setupKeyboardVariables(Display *display)
675 {
676         // If the dpy variable is set, we've already been called once. Just return.
677
678         if (dpy)
679                 return TRUE;
680
681         // Get the Keyboard Mapping table. This is indexed by keycode in one
682         // direction, and by the modifier index in the other. The loadKeyboardTable
683         // routine will take these two tables and convert the config file into a lookup
684         // table between stroke sequences and keycode/modifier keycode pairs.
685
686         // We set up a local static variable used by all of these routines. It is done this
687         // way for easy integration into Tk/TCL code, which quite often has no notion of
688         // the X display variable.
689
690         dpy = display;
691         
692         // Call to test for and set up the XTest extension
693
694         if (debug)
695                 fprintf(stderr, "Setting up XTest\n");
696
697         if (setupXTest() == FALSE)
698                 return FALSE;
699
700         // Load the modifer map
701
702         if (debug)
703                 fprintf(stderr, "Creating modifier table\n");
704         
705         if (createModifierTable() == FALSE)
706                 return FALSE;
707
708         if (debug)
709                 fprintf(stderr, "Loading KeySym table\n");
710
711         if (loadKeySymTable() == FALSE)
712                 return FALSE;
713
714         return TRUE;
715 }
716