1 /* xkeycaps, Copyright (c) 1991, 1992, 1993, 1994, 1997, 1998
2 * by Jamie Zawinski <jwz@jwz.org>
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
10 * implied warranty.
11 */
12
13 #if defined(__STDC__) && defined(__unix)
14 #include <unistd.h>
15 #endif
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <time.h>
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23
24 #ifndef NO_UNAME
25 # include <sys/utsname.h>
26 #endif
27
28 #include <X11/X.h>
29 #include <X11/Xos.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <X11/Xproto.h>
33
34 #include <X11/StringDefs.h>
35 #include <X11/Intrinsic.h>
36 #include <X11/Shell.h>
37
38 #include <X11/Xmu/WinUtil.h>
39 #include <X11/Xmu/Error.h>
40
41 #include <X11/Xaw/Simple.h>
42 #include <X11/Xaw/Box.h>
43 #include <X11/Xaw/Form.h>
44 #include <X11/Xaw/Label.h>
45 #include <X11/Xaw/Paned.h>
46 #include <X11/Xaw/List.h>
47 #include <X11/Xaw/Viewport.h>
48 #include <X11/Xaw/Dialog.h>
49 #include <X11/Xaw/Command.h>
50 #include <X11/Xaw/Toggle.h>
51 #include <X11/Xaw/SimpleMenu.h>
52 #include <X11/Xaw/SmeBSB.h>
53 #include <X11/Xaw/MenuButton.h>
54 #include <X11/Xaw/Scrollbar.h>
55
56 #ifdef XAWBUG
57 /* At some point it seemed like the Toggle widget (really, the Command widget)
58 didn't provide a GetValues-hook to access the "state" property, so we had
59 to access that slot directly. Well, this isn't the case with MIT R5 pl25,
60 or with OpenWindows 3.0, so let's try living without it now.
61 */
62 # include <X11/IntrinsicP.h>
63 # include <X11/CoreP.h>
64 # include <X11/Xaw/SimpleP.h>
65 # include <X11/Xaw/CommandP.h>
66 #endif /* XAWBUG */
67
68 #include "KbdWidgetP.h"
69 #include "KeyWidgetP.h"
70
71 #include "xkeycaps.h"
72
73 #include "kbddef.h"
74
75 #include "vroot.h" /* This is standard in R5 but not R4 */
76
77 #ifndef NO_PWD
78 #include <pwd.h>
79 #endif
80
81 /* We can only do Vendor keysyms in X11r5, because earlier versions
82 didn't provide any way to map over the contents of an xrm database.
83 */
84 #ifdef XtSpecificationRelease
85 # if XtSpecificationRelease >= 5
86 # define DO_VENDOR_KEYSYMS
87 # endif
88 #endif
89
90
91
92 static int y_or_n_p P((KeyboardWidget widget,
93 char *name, char *name0, char *name1, char *name2));
94
95 static int y_or_n_p_with_args P((KeyboardWidget,
96 char *name,
97 char *name0, char *name1, char *name2,
98 char *arg0, char *arg1, char *arg2,
99 char *arg3, char *arg4, char *arg5));
100
101 static Widget make_button P((Widget parent, char *name, char *string,
102 Widget left, Widget top, XtCallbackProc callback,
103 XtPointer data, char *menu_name));
104
105
106 struct key_menus {
107 Widget popup;
108 Widget popup_kids [10];
109 struct edit_key_box *edit_key_box;
110 struct select_kbd_box *select_kbd_box;
111 };
112
113 #ifndef isupper
114 # define isupper(c) ((c) >= 'A' && (c) <= 'Z')
115 #endif
116 #ifndef _tolower
117 # define _tolower(c) ((c) - 'A' + 'a')
118 #endif
119
120 int
121 #ifdef __STDC__
string_equal(const char * s1,const char * s2)122 string_equal (const char *s1, const char *s2)
123 #else /* ! __STDC__ */
124 string_equal (s1, s2)
125 const char *s1, *s2;
126 #endif /* ! __STDC__ */
127 {
128 if (s1 == s2) return 1;
129 if (!s1 || !s2) return 0;
130 while (*s1 && *s2)
131 {
132 if ((isupper (*s1) ? _tolower (*s1) : *s1) !=
133 (isupper (*s2) ? _tolower (*s2) : *s2))
134 return 0;
135 s1++, s2++;
136 }
137 return ((*s1 || *s2) ? 0 : 1);
138 }
139
140
141
142
143 static Widget
144 #ifdef __STDC__
make_button(Widget parent,char * name,char * string,Widget left,Widget top,XtCallbackProc callback,XtPointer data,char * menu_name)145 make_button (Widget parent,
146 char *name, char *string,
147 Widget left, Widget top,
148 XtCallbackProc callback,
149 XtPointer data,
150 char *menu_name)
151 #else /* ! __STDC__ */
152 make_button (parent, name, string, left, top, callback, data, menu_name)
153 Widget parent;
154 char *name, *string;
155 Widget left, top;
156 XtCallbackProc callback;
157 XtPointer data;
158 char *menu_name;
159 #endif /* ! __STDC__ */
160 {
161 Widget w = make_label_1 (parent, name, string, left, top,
162 (menu_name
163 ? menuButtonWidgetClass
164 : commandWidgetClass),
165 callback, data);
166 if (menu_name)
167 {
168 Arg av [10];
169 int ac = 0;
170 XtSetArg (av [ac], XtNmenuName, menu_name); ac++;
171 XtSetValues (w, av, ac);
172 }
173 return w;
174 }
175
176
177 static Widget
178 #ifdef __STDC__
make_toggle(Widget parent,char * name,Widget left,Widget top,int state,XtCallbackProc callback,XtPointer data,char * label,Widget radio_group,XtPointer radio_data)179 make_toggle (Widget parent, char *name, Widget left, Widget top, int state,
180 XtCallbackProc callback,
181 XtPointer data, char *label, Widget radio_group,
182 XtPointer radio_data)
183 #else /* ! __STDC__ */
184 make_toggle (parent, name, left, top, state, callback, data, label,
185 radio_group, radio_data)
186 Widget parent;
187 char *name;
188 Widget left, top;
189 int state;
190 void (*callback) ();
191 XtPointer data;
192 char *label;
193 Widget radio_group;
194 XtPointer radio_data;
195 #endif /* ! __STDC__ */
196 {
197 Arg av [20];
198 int ac = 0;
199 Widget w;
200 XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
201 XtSetArg (av[ac], XtNright, XtChainLeft); ac++;
202 XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
203 XtSetArg (av[ac], XtNbottom, XtChainTop); ac++;
204 XtSetArg (av[ac], XtNjustify, XtJustifyLeft); ac++;
205 XtSetArg (av[ac], XtNstate, (state ? True : False)); ac++;
206 if (left) XtSetArg (av[ac], XtNfromHoriz, left), ac++;
207 if (top) XtSetArg (av[ac], XtNfromVert, top), ac++;
208 if (label) XtSetArg (av[ac], XtNlabel, label), ac++;
209 if (radio_group) XtSetArg (av[ac], XtNradioGroup, radio_group), ac++;
210 if (radio_data) XtSetArg (av[ac], XtNradioData, radio_data), ac++;
211 w = XtCreateManagedWidget (name, toggleWidgetClass, parent, av, ac);
212 if (callback) XtAddCallback (w, XtNcallback, callback, data);
213 return w;
214 }
215
216
217
218
219 static void
220 #ifdef __STDC__
button_quit(Widget widget,XtPointer client_data,XtPointer call_data)221 button_quit (Widget widget, XtPointer client_data, XtPointer call_data)
222 #else /* ! __STDC__ */
223 button_quit (widget, client_data, call_data)
224 Widget widget;
225 XtPointer client_data, call_data;
226 #endif /* ! __STDC__ */
227 {
228 exit (0);
229 }
230
231
232 static int modify_keyboard_modifiers P((KeyboardWidget, XModifierKeymap *));
233 static int modify_keyboard P((KeyboardWidget, int first_keycode,
234 int keysyms_per_keycode, KeySym *keysyms,
235 int num_codes, XModifierKeymap *modmap));
236
237 static void
238 #ifdef __STDC__
button_restore(Widget button,XtPointer client_data,XtPointer call_data)239 button_restore (Widget button, XtPointer client_data, XtPointer call_data)
240 #else /* ! __STDC__ */
241 button_restore (button, client_data, call_data)
242 Widget button;
243 XtPointer client_data, call_data;
244 #endif /* ! __STDC__ */
245 {
246 KeyboardWidget widget = *((KeyboardWidget *) client_data);
247 KeySym *keysyms;
248 KeyCode lowest = 255, highest = 0;
249 XModifierKeymap *modmap;
250 int per_code = widget->keyboard.default_keysyms_per_code;
251 int i, j, k;
252
253 if (0 != y_or_n_p (widget, "restoreQuery", "yes", "no", 0))
254 {
255 message (widget, "Aborted.");
256 return;
257 }
258 keysyms = (KeySym *) calloc (sizeof (KeySym), per_code * 256);
259 modmap = XNewModifiermap (2); /* It'll grow */
260 memset (modmap->modifiermap, 0, modmap->max_keypermod * 8);
261
262 for (i = 0; i < widget->keyboard.nrows; i++)
263 {
264 struct KeyWidget_row *row = &widget->keyboard.rows [i];
265 for (j = 0; j < row->nkeys; j++)
266 {
267 KeyWidget key = row->keys [j];
268 if (key->key.keycode)
269 {
270 if (key->key.keycode < lowest)
271 lowest = key->key.keycode;
272 if (key->key.keycode > highest)
273 highest = key->key.keycode;
274 for (k = 0; k < per_code; k++)
275 keysyms [key->key.keycode * per_code + k] =
276 key->key.default_keysyms [k];
277 if (key->key.default_mods)
278 for (k = 0; k < 8; k++)
279 if (key->key.default_mods & (1<<k))
280 modmap = XInsertModifiermapEntry (modmap,
281 key->key.keycode,
282 k);
283 }
284 }
285 }
286 if (highest <= lowest) exit (-69); /* can't happen */
287
288 if (! modify_keyboard (widget, lowest, per_code,
289 keysyms + (lowest * per_code),
290 highest - lowest, modmap))
291 message (widget, "Keyboard restored to default state.");
292 XFreeModifiermap (modmap);
293 free (keysyms);
294 }
295
296
297 static FILE *
298 #ifdef __STDC__
open_output_file(KeyboardWidget widget,char ** name)299 open_output_file(KeyboardWidget widget, char **name)
300 #else /* ! __STDC__ */
301 open_output_file(widget, name)
302 KeyboardWidget widget;
303 char **name;
304 #endif /* ! __STDC__ */
305 {
306 const char *home = getenv("HOME");
307 const char *base = ".xmodmap";
308 int L = strlen(home) + strlen(base) + 2;
309 char *target = 0;
310 struct stat st;
311 FILE *out = 0;
312
313 #ifndef NO_UNAME
314 struct utsname uts;
315 if (uname (&uts) >= 0)
316 L += strlen(uts.nodename) + 1;
317 else
318 uts.nodename[0] = 0;
319 #endif
320
321 target = (char *) malloc(L+1);
322 strcpy(target, home);
323 if (target[strlen(target)-1] != '/')
324 strcat(target, "/");
325
326 strcat(target, base);
327
328 #ifndef NO_UNAME
329 if (uts.nodename)
330 {
331 strcat(target, "-");
332 strcat(target, uts.nodename);
333 }
334 #endif
335
336 if (!stat(target, &st))
337 {
338 char *t2;
339 if (y_or_n_p_with_args(widget,
340 "overwriteQuery",
341 "ok", "cancel", 0,
342 target, 0, 0, 0, 0, 0))
343 goto DONE;
344
345 t2 = (char *) malloc (strlen(target) + 10);
346 strcpy (t2, target);
347 strcat (t2, ".BAK");
348 rename (target, t2);
349 free (t2);
350 }
351
352 out = fopen(target, "w");
353 DONE:
354 *name = 0;
355 if (out)
356 *name = target;
357 else
358 free (target);
359 return out;
360 }
361
362
363 void
364 #ifdef __STDC__
make_long_kbd_name(const char * vendor,const char * kbd_style,char * buf)365 make_long_kbd_name (const char *vendor, const char *kbd_style, char *buf)
366 #else /* ! __STDC__ */
367 make_long_kbd_name (vendor, kbd_style, buf)
368 const char *vendor;
369 const char *kbd_style;
370 char *buf;
371 #endif /* ! __STDC__ */
372 {
373 strcpy(buf, (vendor ? vendor : ""));
374 if (kbd_style && *kbd_style)
375 {
376 strcat(buf, " ");
377 strcat(buf, kbd_style);
378 }
379 }
380
381
382 static char *bit_names[] = { "Shift", "Lock", "Control", "Mod1",
383 "Mod2", "Mod3", "Mod4", "Mod5" };
384
385 static void
386 #ifdef __STDC__
button_write(Widget button,XtPointer client_data,XtPointer call_data)387 button_write (Widget button, XtPointer client_data, XtPointer call_data)
388 #else /* ! __STDC__ */
389 button_write (button, client_data, call_data)
390 Widget button;
391 XtPointer client_data, call_data;
392 #endif /* ! __STDC__ */
393 {
394 char *filename = 0;
395 FILE *out;
396 KeyboardWidget widget = *((KeyboardWidget *) client_data);
397 XModifierKeymap *current_modmap, *default_modmap;
398 int per_code = widget->keyboard.default_keysyms_per_code;
399 struct { KeyWidget key; int count; char *names[8]; }
400 all [256], differences [256];
401 int all_count = 0, diff_count = 0;
402 KeySym *keysyms;
403 int count, i, j, k;
404 int partial = y_or_n_p (widget, "writeQuery", "full", "partial", "abort");
405 time_t now = time ((time_t *) 0);
406 #ifdef NO_PWD
407 char *userid = 0;
408 #else
409 struct passwd *pw = (struct passwd *) getpwuid (getuid ());
410 char *userid = (pw ? pw->pw_name : 0);
411 #endif
412 KeyCode added [8][255];
413 KeyCode subtracted [8][255];
414 int added_count, subtracted_count;
415 int cmkpm, dmkpm;
416 int any_mod_changes = 0;
417
418 if (partial >= 2)
419 {
420 message (widget, "Aborted.");
421 return;
422 }
423
424 current_modmap = XGetModifierMapping (XtDisplay (widget));
425 default_modmap = XNewModifiermap (2); /* It'll grow */
426 memset (default_modmap->modifiermap, 0, default_modmap->max_keypermod * 8);
427
428 out = open_output_file(widget, &filename);
429 if (!out) return;
430
431 for (i = 0; i < widget->keyboard.nrows; i++)
432 {
433 struct KeyWidget_row *row = &widget->keyboard.rows [i];
434 for (j = 0; j < row->nkeys; j++)
435 {
436 KeyWidget key = row->keys [j];
437 if (key->key.keycode)
438 {
439 unsigned long bits = key->key.modifier_bits;
440 keysyms = XGetKeyboardMapping (XtDisplay (widget),
441 key->key.keycode,
442 1, &count);
443 if (! keysyms) count = 0;
444 all [all_count].key = key;
445 for (; count > 0; count--)
446 if (keysyms [count-1]) break;
447 if (count == 0)
448 {
449 all [all_count].names [0] = "NoSymbol";
450 count = 1;
451 }
452 else
453 for (k = 0; k < count; k++)
454 {
455 char *str = "NoSymbol";
456 if (keysyms [k])
457 {
458 str = XKeysymToString (keysyms [k]);
459 if (! str)
460 {
461 /* core leak, but this shouldn't ever happen
462 unless there's a bug in libX11.a, or the
463 user did something stupid with xmodmap.
464 */
465 str = (char *) malloc (255);
466 sprintf (str, "0x%02X", (int) keysyms [k]);
467 }
468 }
469 all [all_count].names [k] = str;
470 }
471 all [all_count].count = count;
472 if (! keysyms) count = 0;
473 if (count > per_code ||
474 ((!partial) && (bits != key->key.default_mods)) ||
475 (count > 0 && keysyms[0] != key->key.default_keysyms[0]) ||
476 (count > 1 && keysyms[1] != key->key.default_keysyms[1]) ||
477 (count > 2 && keysyms[2] != key->key.default_keysyms[2]) ||
478 (count > 3 && keysyms[3] != key->key.default_keysyms[3]) ||
479 (count > 4 && keysyms[4] != key->key.default_keysyms[4]) ||
480 (count > 5 && keysyms[5] != key->key.default_keysyms[5]) ||
481 (count > 6 && keysyms[6] != key->key.default_keysyms[6]) ||
482 (count > 7 && keysyms[7] != key->key.default_keysyms[7]))
483 differences [diff_count++] = all [all_count];
484 all_count++;
485 for (k = 0; k < 8; k++)
486 {
487 if (key->key.default_mods & (1<<k))
488 default_modmap =
489 XInsertModifiermapEntry (default_modmap,
490 key->key.keycode, k);
491 if (bits & (1<<k))
492 current_modmap =
493 XInsertModifiermapEntry (current_modmap,
494 key->key.keycode, k);
495 }
496 if (keysyms) XFree ((char *) keysyms);
497 }
498 }
499 }
500
501 /* I'd just like to take this moment to point out that C has all
502 the expressive power of two dixie cups and a string.
503 */
504 cmkpm = current_modmap->max_keypermod;
505 dmkpm = default_modmap->max_keypermod;
506 memset (added, 0, sizeof (added));
507 memset (subtracted, 0, sizeof (subtracted));
508
509 for (i = 0; i < 8; i++)
510 {
511 KeyCode kc1, kc2 = 0;
512 added_count = subtracted_count = 0;
513 if (partial)
514 {
515 for (j = 0; j < cmkpm; j++)
516 {
517 kc1 = current_modmap->modifiermap [i * cmkpm + j];
518 if (!kc1) continue;
519 for (k = 0; k < dmkpm; k++)
520 {
521 kc2 = default_modmap->modifiermap [i * dmkpm + k];
522 if (kc1 == kc2) break;
523 }
524 if (kc1 != kc2) added [i][added_count++] = kc1;
525 }
526 for (j = 0; j < dmkpm; j++)
527 {
528 kc1 = default_modmap->modifiermap [i * dmkpm + j];
529 if (!kc1) continue;
530 for (k = 0; k < cmkpm; k++)
531 {
532 kc2 = current_modmap->modifiermap [i * cmkpm + k];
533 if (kc1 == kc2) break;
534 }
535 if (kc1 != kc2) subtracted [i][subtracted_count++] = kc1;
536 }
537 if (added_count || subtracted_count) any_mod_changes = 1;
538 }
539 else
540 {
541 for (j = 0; j < cmkpm; j++)
542 {
543 kc1 = current_modmap->modifiermap [i * cmkpm + j];
544 if (kc1)
545 added [i][added_count++] = kc1;
546 }
547 }
548 }
549
550 {
551 char *t;
552 char s[1024];
553 make_long_kbd_name(widget->keyboard.vendor, widget->keyboard.kbd_style, s);
554 fprintf (out, "!\n! This is an `xmodmap' input file for %s%s keyboards.\n",
555 ((strlen(s) > 40) ? "\n! " : ""), s);
556
557 t = ctime (&now);
558 t [strlen (t) - 1] = 0; /* bastards */
559 fprintf (out, "! Automatically generated on %s", t);
560 }
561 if (userid)
562 fprintf (out, " by %s", userid);
563 fprintf (out, " with\n! %s.\n", short_version);
564 fprintf (out, "! http://www.jwz.org/xkeycaps/\n");
565 fprintf (out, "!\n");
566
567 if (partial && any_mod_changes)
568 {
569 fprintf (out, "! This file presupposes that the keyboard is in the ");
570 fprintf (out,
571 "default state, and\n! may malfunction if it is not.\n!\n");
572 }
573 else if (! partial)
574 {
575 if (diff_count)
576 fprintf (out, "! This file makes the following changes:\n!\n");
577 else
578 fprintf (out, "! This file encodes the default state.\n!\n");
579 }
580
581 /* If we're going to write out "remove" commands, do it before writing
582 out any "keycode" statements, since xmodmap is so lame. We only
583 generate "remove" statements in "partial" mode.
584 http://catalog.com/hopkins/images/smegmas.gif
585 */
586 any_mod_changes = 0;
587 if (partial)
588 for (i = 0; i < 8; i++)
589 {
590 char *str;
591 KeySym ks;
592 if (subtracted [i][0])
593 {
594 fprintf (out, "remove %-8s=", bit_names [i]);
595 for (j = 0; j < sizeof (subtracted [0]); j++)
596 {
597 KeyWidget kw;
598 if (! subtracted [i][j]) break;
599 any_mod_changes = 1;
600 /* note: we don't use the *current* keysym corresponding to the
601 keycode being removed here, but the *default* one...
602 */
603 kw = keycode_to_key (widget, subtracted [i][j]);
604 ks = kw->key.default_keysyms [0];
605 str = XKeysymToString (ks);
606 if (str)
607 fprintf (out, " %s", str);
608 else
609 fprintf (out, " 0x%04X", subtracted [i][j]);
610 }
611 fprintf (out, "\n");
612 }
613 }
614 if (any_mod_changes) fprintf (out, "\n");
615
616 /* Write out the differences. This happens in both "partial" and "full"
617 modes, but in "full" mode it's in the form of a descriptive comment
618 instead of xmodmap commands.
619 */
620 for (i = 0; i < diff_count; i++)
621 {
622 if (partial)
623 fprintf (out, "keycode 0x%02X =\t", differences[i].key->key.keycode);
624 else
625 fprintf (out, "! The \"%s\" key generates ",
626 differences[i].key->key.key_name);
627 for (j = 0; j < differences[i].count; j++)
628 {
629 fprintf (out, "%s", differences[i].names[j]);
630 if (j+1 == differences[i].count) continue;
631 if (partial)
632 {
633 fprintf (out, "\t");
634 if (strlen (differences[i].names[j]) < 8) putchar ('\t');
635 }
636 else
637 {
638 if (j+1 == differences[i].count-1)
639 fprintf (out, "%s", (j == 0) ? " and " : ", and ");
640 else
641 fprintf (out, ", ");
642 }
643 }
644 /* write the diffs of the modifier bits in the full-mode comment. */
645 if (!partial &&
646 differences[i].key->key.default_mods !=
647 differences[i].key->key.modifier_bits)
648 {
649 unsigned long bits = differences[i].key->key.modifier_bits;
650 int this_mod_count = 0;
651 if (! bits)
652 fprintf (out, ", and has no modifiers\n");
653 else
654 {
655 fprintf (out, ", and the ");
656 for (k = 0; k < 8; k++)
657 {
658 if (bits & (1<<k))
659 {
660 if (this_mod_count++) fprintf (out, "/");
661 fprintf (out, "%s", bit_names [k]);
662 }
663 }
664 fprintf (out, " modifier%s\n", (this_mod_count>1 ? "s" : ""));
665 }
666 }
667 else
668 fprintf (out, "\n");
669 }
670
671 /* In "full" mode, write out all the "keycode" commands. This is the
672 first actual xmodmap command text in full mode.
673 */
674 if (!partial)
675 {
676 fprintf (out, "\n");
677 for (i = 0; i < all_count; i++)
678 {
679 fprintf (out, "keycode 0x%02X =\t", all [i].key->key.keycode);
680 for (j = 0; j < all[i].count; j++)
681 {
682 fprintf (out, "%s", all[i].names[j]);
683 if (j == all[i].count - 1) continue;
684 fprintf (out, "\t");
685 if (strlen (all[i].names[j]) < 8) fprintf (out, "\t");
686 }
687 fprintf (out, "\n");
688 }
689 fprintf (out, "\n");
690 fprintf (out, "clear Shift\nclear Lock\nclear Control\nclear Mod1\n");
691 fprintf (out, "clear Mod2\nclear Mod3\nclear Mod4\nclear Mod5\n");
692 }
693
694 /* In partial mode, write out any "add" commands. This is after any
695 "keycode" commands have already been output (and any "remove" commands
696 before them.) In full mode, the "add" commands are the whole story.
697 */
698 fprintf (out, "\n");
699 for (i = 0; i < 8; i++)
700 {
701 char *str;
702 KeySym ks;
703 if (added [i][0])
704 {
705 fprintf (out, "add %-8s=", bit_names [i]);
706 for (j = 0; j < sizeof (added [0]); j++)
707 {
708 if (! added [i][j]) break;
709 ks = XKeycodeToKeysym (XtDisplay (widget), added [i][j], 0);
710 str = XKeysymToString (ks);
711 if (str)
712 fprintf (out, " %s", str);
713 else
714 fprintf (out, " 0x%04X", added [i][j]);
715 }
716 fprintf (out, "\n");
717 }
718 }
719 fclose (out);
720 y_or_n_p_with_args (widget, "wroteFileMessage",
721 "ok", 0, 0,
722 (filename ? filename : "???"), 0, 0, 0, 0, 0);
723 if (filename) free (filename);
724 }
725
726
727 static Window
728 #ifdef __STDC__
lowest_window(Display * dpy,Window window,Window limit,int x,int y)729 lowest_window (Display *dpy, Window window, Window limit, int x, int y)
730 #else /* ! __STDC__ */
731 lowest_window (dpy, window, limit, x, y)
732 Display *dpy;
733 Window window, limit;
734 int x, y;
735 #endif /* ! __STDC__ */
736 {
737 XWindowAttributes xgwa;
738 XGetWindowAttributes (dpy, window, &xgwa);
739
740 /* Ignore all windows which are not at or below `limit'. This prevents
741 us from assigning focus to windows which are part of the WM decoration,
742 since `limit' is the result of XmuClientWindow() -- it limits us to
743 descending the tree of the client proper.
744 */
745 if (window == limit) limit = 0;
746
747 if (xgwa.x <= x &&
748 xgwa.y <= y &&
749 xgwa.x + xgwa.width > x &&
750 xgwa.y + xgwa.height > y)
751 {
752 Window root, parent, *kids;
753 unsigned int nkids;
754 if (!XQueryTree (dpy, window, &root, &parent, &kids, &nkids))
755 abort ();
756
757 if (kids)
758 {
759 unsigned int i;
760 Window kid = 0;
761 for (i = 0; i < nkids; i++)
762 {
763 kid = lowest_window (dpy, kids[i], limit,
764 x - xgwa.x, y - xgwa.y);
765 if (kid) break;
766 }
767 XFree ((char *)kids);
768 if (kid) return kid;
769 }
770 /* Don't accept windows outside of the client tree. */
771 if (limit) return 0;
772 /* Don't accept windows which don't take KeyPress. */
773 if (! (xgwa.all_event_masks & KeyPressMask)) return 0;
774 return window;
775 }
776 else
777 return 0;
778 }
779
780 static void
781 #ifdef __STDC__
button_pick_window(Widget button,XtPointer client_data,XtPointer call_data)782 button_pick_window (Widget button, XtPointer client_data, XtPointer call_data)
783 #else /* ! __STDC__ */
784 button_pick_window (button, client_data, call_data)
785 Widget button;
786 XtPointer client_data, call_data;
787 #endif /* ! __STDC__ */
788 {
789 KeyboardWidget keyboard = *((KeyboardWidget *) client_data);
790 Widget topmost, target;
791 Display *dpy = XtDisplay (keyboard);
792 Window root = RootWindowOfScreen (keyboard->core.screen);
793 Window window = 0;
794 Window wm_window;
795 int click_x = 0, click_y = 0;
796 int buttons = 0;
797 int once = 0;
798 XEvent event;
799
800 message (keyboard, "Please select the window to type at:");
801
802 if (XGrabPointer (dpy, root, False, ButtonPressMask | ButtonReleaseMask,
803 GrabModeSync, GrabModeAsync, root,
804 keyboard->keyboard.select_cursor, CurrentTime))
805 {
806 XBell (dpy, 0);
807 message (keyboard, "Grab failed.");
808 return;
809 }
810
811 while (window == 0 || buttons != 0)
812 {
813 /* allow one more event */
814 XAllowEvents (dpy, SyncPointer, CurrentTime);
815 XWindowEvent (dpy, root, ButtonPressMask|ButtonReleaseMask, &event);
816 switch (event.type)
817 {
818 case ButtonPress:
819 once = 1;
820 if (window == 0 && event.xbutton.subwindow)
821 {
822 window = event.xbutton.subwindow; /* window selected */
823 click_x = event.xbutton.x;
824 click_y = event.xbutton.y;
825 }
826 buttons++;
827 break;
828 case ButtonRelease:
829 if (buttons > 0) buttons--;
830 break;
831 }
832 }
833 XUngrabPointer(dpy, CurrentTime);
834 XSync (dpy, 0);
835
836 wm_window = window;
837 if (window && window != root) window = XmuClientWindow (dpy, window);
838 topmost = (Widget) keyboard;
839 while (XtParent (topmost)) topmost = XtParent (topmost);
840 target = XtWindowToWidget (XtDisplay (topmost), window);
841 if (window == XtWindow (topmost)) target = topmost;
842 if (target || window == root) window = 0;
843 if (window)
844 {
845 char buf [255];
846 char buf2 [100];
847 char *string1 = 0, *string2 = 0, *string3 = 0;
848 char *name;
849 XClassHint classhint;
850
851 Window lowest = lowest_window (dpy, wm_window, window, click_x, click_y);
852 if (! lowest)
853 {
854 /* Maybe they clicked in the wrong place in the app. Let's try
855 again by picking the exact center of the frame and looking
856 there for something that accepts keyboard input.
857 */
858 XWindowAttributes xgwa;
859 XGetWindowAttributes (dpy, wm_window, &xgwa);
860 lowest = lowest_window (dpy, wm_window, window,
861 xgwa.x + (xgwa.width / 2),
862 xgwa.y + (xgwa.height / 2));
863 if (! lowest)
864 {
865 /* Still couldn't find one; give up. */
866 XBell (dpy, 0);
867 message (keyboard,
868 "No window there that accepts keyboard input!");
869 goto done;
870 }
871 }
872
873 classhint.res_name = classhint.res_class = 0;
874 if (! XGetClassHint (dpy, window, &classhint))
875 classhint.res_name = classhint.res_class = 0;
876
877 string1 = classhint.res_name;
878 string2 = classhint.res_class;
879 XFetchName (dpy, window, &string3);
880 name = string3;
881 if (string2 && string3 && string_equal (string2, string3)) string3 = 0;
882 if (string1 && string3 && string_equal (string1, string3)) string3 = 0;
883 if (string1 && string2 && string_equal (string1, string2)) string2 = 0;
884 if (!string2) string2 = string3, string3 = 0;
885 if (!string1) string1 = string2, string2 = 0;
886 if (string1 && string2 && string3)
887 sprintf (buf2, "%s / %s / %s", string1, string2, string3);
888 else if (string1 && string2)
889 sprintf (buf2, "%s / %s", string1, string2);
890 else if (string1)
891 sprintf (buf2, "%s", string1);
892 else
893 sprintf (buf2, "unnamed");
894
895 if (window == lowest)
896 sprintf (buf, "Keyboard focus locked on window 0x%X (%s)",
897 (int) window, buf2);
898 else
899 sprintf (buf, "Keyboard focus locked on window 0x%X <- 0x%X (%s)",
900 (int) lowest, (int) window, buf2);
901 message (keyboard, buf);
902
903 if (!classhint.res_class)
904 ;
905 else if (string_equal (classhint.res_class, "xterm"))
906 message2 (keyboard,
907 "Remember to select \"Allow SendEvents\" from the XTerm menu.");
908 else if (string_equal (classhint.res_class, "cmdtool") ||
909 string_equal (classhint.res_class, "shelltool") ||
910 string_equal (classhint.res_class, "textedit"))
911 message2 (keyboard,
912 "Did you remember to use the -defeateventsecurity option when launching it?");
913
914 if (classhint.res_name) XFree (classhint.res_name);
915 if (classhint.res_class) XFree (classhint.res_class);
916 if (name) XFree (name);
917 window = lowest;
918 }
919 else
920 message (keyboard, "Keyboard-focus cleared.");
921
922 done:
923 keyboard->keyboard.target_window = window;
924 }
925
926
927
928 static int
929 #ifdef __STDC__
modify_keyboard_modifiers(KeyboardWidget widget,XModifierKeymap * modmap)930 modify_keyboard_modifiers (KeyboardWidget widget, XModifierKeymap *modmap)
931 #else /* ! __STDC__ */
932 modify_keyboard_modifiers (widget, modmap)
933 KeyboardWidget widget;
934 XModifierKeymap *modmap;
935 #endif /* ! __STDC__ */
936 {
937 Display *display = XtDisplay ((Widget) widget);
938 int retries, timeout;
939 char buf [255];
940 for (retries = 4, timeout = 2; retries > 0; retries--, timeout *= 2)
941 {
942 int result;
943 result = XSetModifierMapping (display, modmap);
944 switch (result)
945 {
946 case MappingSuccess:
947 mappingNotify_event_expected = 1;
948 return 0;
949 case MappingBusy:
950 sprintf (buf, "please release all keys withing %d seconds", timeout);
951 /* Calling message() doesn't work because exposes don't get
952 processed while we're sleeping.
953 */
954 message (widget, buf);
955 fprintf (stderr, "%s: %s\n", progname, buf);
956 XSync (display, 0);
957 sleep (timeout);
958 continue;
959 case MappingFailed:
960 message (widget, "XSetModifierMapping() failed");
961 XBell (display, 0);
962 return -1;
963 default:
964 sprintf (buf, "unknown return code %d from XSetModifierMapping()",
965 result);
966 message (widget, buf);
967 XBell (display, 0);
968 return -1;
969 }
970 }
971 sprintf (buf, "XSetModifierMapping() failed");
972 message (widget, buf);
973 XBell (display, 0);
974 return -1;
975 }
976
977
978 /* We install this as an error handler around the call to
979 XChangeKeyboardMapping(), so that we can trap errors that that
980 operation generates. Gotta love this 1960's condition system...
981 */
982 static int XChangeKeyboardMapping_error = 0;
983
984 static int
985 #ifdef __STDC__
modify_keyboard_error_handler(Display * dpy,XErrorEvent * error)986 modify_keyboard_error_handler (Display *dpy, XErrorEvent *error)
987 #else /* ! __STDC__ */
988 modify_keyboard_error_handler (dpy, error)
989 Display *dpy;
990 XErrorEvent *error;
991 #endif /* ! __STDC__ */
992 {
993 switch (error->request_code)
994 {
995 case X_ChangeKeyboardMapping:
996 XChangeKeyboardMapping_error = 1;
997 return 0;
998 default:
999 XmuPrintDefaultErrorMessage (dpy, error, stderr);
1000 exit (-1);
1001 }
1002 }
1003
1004 static int
1005 #ifdef __STDC__
modify_keyboard(KeyboardWidget widget,int first_keycode,int keysyms_per_keycode,KeySym * keysyms,int num_codes,XModifierKeymap * modmap)1006 modify_keyboard (KeyboardWidget widget, int first_keycode,
1007 int keysyms_per_keycode, KeySym *keysyms,
1008 int num_codes, XModifierKeymap *modmap)
1009 #else /* ! __STDC__ */
1010 modify_keyboard (widget, first_keycode, keysyms_per_keycode, keysyms,
1011 num_codes, modmap)
1012 KeyboardWidget widget;
1013 int first_keycode;
1014 int keysyms_per_keycode;
1015 KeySym *keysyms;
1016 int num_codes;
1017 XModifierKeymap *modmap;
1018 #endif /* ! __STDC__ */
1019 {
1020 Display *display = XtDisplay ((Widget) widget);
1021 XErrorHandler old_handler;
1022 if (keysyms_per_keycode == 0) keysyms_per_keycode = 1;
1023 XSync (display, 0);
1024 mappingNotify_event_expected = 1;
1025 XChangeKeyboardMapping_error = 0;
1026 old_handler = XSetErrorHandler (modify_keyboard_error_handler);
1027 XChangeKeyboardMapping (display, first_keycode, keysyms_per_keycode,
1028 keysyms, num_codes);
1029 /* Is there a race condition here? Are we guarenteed that by calling
1030 XSync() we will get back an error generated by the previously-sent
1031 request?
1032 */
1033 XSync (XtDisplay ((Widget) widget), 0);
1034 XSetErrorHandler (old_handler);
1035 if (XChangeKeyboardMapping_error)
1036 {
1037 mappingNotify_event_expected = 0;
1038 message (widget, "XChangeKeyboardMapping() failed.");
1039 XBell (display, 0);
1040 return -1;
1041 }
1042 if (modmap)
1043 return modify_keyboard_modifiers (widget, modmap);
1044 return 0;
1045 }
1046
1047
1048 static void
1049 #ifdef __STDC__
restore_key_default(Widget parent,XtPointer client_data,XtPointer call_data)1050 restore_key_default (Widget parent, XtPointer client_data, XtPointer call_data)
1051 #else /* ! __STDC__ */
1052 restore_key_default (parent, client_data, call_data)
1053 Widget parent;
1054 XtPointer client_data, call_data;
1055 #endif /* ! __STDC__ */
1056 {
1057 KeyboardWidget widget = (KeyboardWidget) client_data;
1058 KeyWidget key = widget->keyboard.key_under_mouse;
1059 KeySym *keysyms = key->key.default_keysyms;
1060 int per_code = widget->keyboard.default_keysyms_per_code;
1061 KeyCode code = key->key.keycode;
1062 unsigned long bits = key->key.default_mods;
1063 XModifierKeymap *modmap;
1064 int i, error;
1065
1066 if (! code)
1067 {
1068 y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1069 return;
1070 }
1071
1072 modmap = XGetModifierMapping (XtDisplay (widget));
1073 for (i = 0; i < 8; i++)
1074 if (bits & (1<<i))
1075 modmap = XInsertModifiermapEntry (modmap, code, i);
1076 else
1077 modmap = XDeleteModifiermapEntry (modmap, code, i);
1078
1079 XSync (XtDisplay (widget), 0);
1080 error = modify_keyboard (widget, code, per_code, keysyms, 1, modmap);
1081 XFreeModifiermap (modmap);
1082
1083 if (! error)
1084 {
1085 char *k, buf [255], buf2 [255], *b = buf;
1086 for (i = 0; i < per_code; i++)
1087 {
1088 if (i) *b++ = ',', *b++ = ' ';
1089 k = XKeysymToString (keysyms [i]);
1090 if (keysyms [i] && !k)
1091 {
1092 sprintf (b, "0x%04X", (int) keysyms [i]);
1093 k = b;
1094 }
1095 else
1096 {
1097 if (! k) k = "NoSymbol";
1098 strcpy (b, k);
1099 }
1100 b += strlen (k);
1101 }
1102 sprintf (buf2, "KeyCode 0x%02X restored to default state (%s)",
1103 key->key.keycode, buf);
1104 message (widget, buf2);
1105 }
1106 XSync (XtDisplay (widget), 0);
1107 }
1108
1109
1110 static void
1111 #ifdef __STDC__
swap_key(Widget parent,XtPointer client_data,XtPointer call_data)1112 swap_key (Widget parent, XtPointer client_data, XtPointer call_data)
1113 #else /* ! __STDC__ */
1114 swap_key (parent, client_data, call_data)
1115 Widget parent;
1116 XtPointer client_data, call_data;
1117 #endif /* ! __STDC__ */
1118 {
1119 KeyboardWidget widget = (KeyboardWidget) client_data;
1120 XModifierKeymap *modmap = XGetModifierMapping (XtDisplay (widget));
1121 KeyWidget source_key = widget->keyboard.key_under_mouse;
1122 KeyWidget target_key;
1123 KeySym *source_keysyms;
1124 KeySym *target_keysyms;
1125 int source_count, target_count;
1126 unsigned long source_bits = source_key->key.modifier_bits;
1127 unsigned long target_bits;
1128 KeyCode source_code = source_key->key.keycode;
1129 KeyCode target_code;
1130 char buf [255];
1131 int i, error;
1132
1133 if (source_key->key.keycode == 0)
1134 {
1135 y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1136 return;
1137 }
1138
1139 sprintf (buf, "Click on the key to swap with 0x%02X (%s)",
1140 source_key->key.keycode,
1141 source_key->key.key_name);
1142 target_key = prompt_for_key (widget, buf);
1143 if (! target_key) return;
1144
1145 target_bits = target_key->key.modifier_bits;
1146 target_code = target_key->key.keycode;
1147
1148 if (target_code == 0)
1149 {
1150 y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1151 return;
1152 }
1153
1154 if (source_code == target_code)
1155 {
1156 XBell (XtDisplay (widget), 0);
1157 message (widget, "Those keys are the same!");
1158 return;
1159 }
1160
1161 for (i = 0; i < 8; i++)
1162 {
1163 if (source_bits & (1<<i))
1164 modmap = XInsertModifiermapEntry (modmap, target_code, i);
1165 else
1166 modmap = XDeleteModifiermapEntry (modmap, target_code, i);
1167
1168 if (target_bits & (1<<i))
1169 modmap = XInsertModifiermapEntry (modmap, source_code, i);
1170 else
1171 modmap = XDeleteModifiermapEntry (modmap, source_code, i);
1172 }
1173
1174 source_keysyms = XGetKeyboardMapping (XtDisplay (widget), source_code,
1175 1, &source_count);
1176 target_keysyms = XGetKeyboardMapping (XtDisplay (widget), target_code,
1177 1, &target_count);
1178
1179 error = modify_keyboard (widget, target_code,
1180 source_count, source_keysyms, 1, modmap);
1181 if (error) return;
1182 error = modify_keyboard (widget, source_code,
1183 target_count, target_keysyms, 1, 0);
1184 if (error) return;
1185
1186 sprintf (buf, "Keys 0x%02x (%s) and 0x%02x (%s) swapped.",
1187 source_key->key.keycode, source_key->key.key_name,
1188 target_key->key.keycode, target_key->key.key_name);
1189 message (widget, buf);
1190
1191 if (source_keysyms) XFree ((char *) source_keysyms);
1192 if (target_keysyms) XFree ((char *) target_keysyms);
1193 if (modmap) XFreeModifiermap (modmap);
1194 }
1195
1196
1197 static void
1198 #ifdef __STDC__
clone_key(Widget parent,XtPointer client_data,XtPointer call_data)1199 clone_key (Widget parent, XtPointer client_data, XtPointer call_data)
1200 #else /* ! __STDC__ */
1201 clone_key (parent, client_data, call_data)
1202 Widget parent;
1203 XtPointer client_data, call_data;
1204 #endif /* ! __STDC__ */
1205 {
1206 KeyboardWidget widget = (KeyboardWidget) client_data;
1207 XModifierKeymap *modmap = XGetModifierMapping (XtDisplay (widget));
1208 KeyWidget source_key = widget->keyboard.key_under_mouse;
1209 KeyWidget target_key;
1210 KeySym *source_keysyms;
1211 int source_count;
1212 unsigned long source_bits = source_key->key.modifier_bits;
1213 KeyCode source_code = source_key->key.keycode;
1214 KeyCode target_code;
1215 char buf [255];
1216 int i, error;
1217
1218 if (source_key->key.keycode == 0)
1219 {
1220 y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1221 return;
1222 }
1223
1224 sprintf (buf, "Click on the key to turn into a copy of 0x%02X (%s)",
1225 source_key->key.keycode,
1226 source_key->key.key_name);
1227 target_key = prompt_for_key (widget, buf);
1228 if (! target_key) return;
1229
1230 target_code = target_key->key.keycode;
1231
1232 if (target_code == 0)
1233 {
1234 y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1235 return;
1236 }
1237
1238 if (source_code == target_code)
1239 {
1240 XBell (XtDisplay (widget), 0);
1241 message (widget, "Those keys are the same!");
1242 return;
1243 }
1244 for (i = 0; i < 8; i++)
1245 {
1246 if (source_bits & (1<<i))
1247 modmap = XInsertModifiermapEntry (modmap, target_code, i);
1248 else
1249 modmap = XDeleteModifiermapEntry (modmap, target_code, i);
1250 }
1251
1252 source_keysyms = XGetKeyboardMapping (XtDisplay (widget), source_code,
1253 1, &source_count);
1254 error = modify_keyboard (widget, target_code,
1255 source_count, source_keysyms, 1, modmap);
1256 if (source_keysyms) XFree ((char *) source_keysyms);
1257 if (modmap) XFreeModifiermap (modmap);
1258 if (error) return;
1259
1260 sprintf (buf, "Keys 0x%02x (%s) and 0x%02x (%s) are now the same.",
1261 source_key->key.keycode, source_key->key.key_name,
1262 target_key->key.keycode, target_key->key.key_name);
1263 message (widget, buf);
1264 }
1265
1266
1267
1268 static void
1269 #ifdef __STDC__
disable_key(Widget parent,XtPointer client_data,XtPointer call_data)1270 disable_key (Widget parent, XtPointer client_data, XtPointer call_data)
1271 #else /* ! __STDC__ */
1272 disable_key (parent, client_data, call_data)
1273 Widget parent;
1274 XtPointer client_data, call_data;
1275 #endif /* ! __STDC__ */
1276 {
1277 KeyboardWidget widget = (KeyboardWidget) client_data;
1278 KeyWidget key = widget->keyboard.key_under_mouse;
1279 KeyCode code = key->key.keycode;
1280 KeySym keysym = 0;
1281 int i, error;
1282 char buf [255];
1283 XModifierKeymap *modmap = XGetModifierMapping (XtDisplay (widget));
1284 if (code == 0)
1285 {
1286 y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1287 return;
1288 }
1289 for (i = 0; i < 8; i++)
1290 modmap = XDeleteModifiermapEntry (modmap, code, i);
1291 error = modify_keyboard (widget, code, 1, &keysym, 1, modmap);
1292 XFreeModifiermap (modmap);
1293 if (! error)
1294 {
1295 sprintf (buf, "KeyCode 0x%02X (%s) disabled.", key->key.keycode,
1296 key->key.key_name);
1297 message (widget, buf);
1298 }
1299 XSync (XtDisplay (widget), 0);
1300 }
1301
1302
1303
1304 static struct edit_key_box * make_edit_key_dbox P((KeyboardWidget));
1305 static struct select_kbd_box * make_select_kbd_dbox P((KeyboardWidget));
1306 static void pop_up_key_dbox P((Widget, XtPointer, XtPointer));
1307
1308
1309 struct key_menus *
1310 #ifdef __STDC__
make_key_menus(KeyboardWidget * kbd)1311 make_key_menus (KeyboardWidget *kbd)
1312 #else /* ! __STDC__ */
1313 make_key_menus (kbd)
1314 KeyboardWidget *kbd;
1315 #endif /* ! __STDC__ */
1316 {
1317 KeyboardWidget widget = *kbd;
1318 Arg av [20];
1319 int ac = 0, i = 0;
1320 Widget menu, item;
1321 struct key_menus *key_menus = (struct key_menus *)
1322 malloc (sizeof (struct key_menus));
1323 memset (key_menus->popup_kids, 0, sizeof (key_menus->popup_kids));
1324
1325 XawSimpleMenuAddGlobalActions (XtWidgetToApplicationContext((Widget)widget));
1326
1327 XtSetArg (av[ac], XtNlabel, "keyMenu"); ac++;
1328 menu = XtCreatePopupShell ("keyMenu", simpleMenuWidgetClass,
1329 (Widget) widget, av, ac);
1330 XtAddCallback (menu, XtNpopupCallback, key_menu_pre_popup_hook,
1331 (XtPointer) widget);
1332 key_menus->popup = menu;
1333 ac = 0;
1334 item = XtCreateManagedWidget ("editKeysyms", smeBSBObjectClass, menu, av,ac);
1335 XtAddCallback (item, XtNcallback, pop_up_key_dbox, (XtPointer) widget);
1336 key_menus->popup_kids [i++] = item;
1337
1338 item = XtCreateManagedWidget ("swapKey", smeBSBObjectClass, menu, av, ac);
1339 XtAddCallback (item, XtNcallback, swap_key, (XtPointer) widget);
1340 key_menus->popup_kids [i++] = item;
1341
1342 item = XtCreateManagedWidget ("cloneKey", smeBSBObjectClass, menu, av, ac);
1343 XtAddCallback (item, XtNcallback, clone_key, (XtPointer) widget);
1344 key_menus->popup_kids [i++] = item;
1345
1346 item = XtCreateManagedWidget ("disableKey", smeBSBObjectClass, menu, av, ac);
1347 XtAddCallback (item, XtNcallback, disable_key, (XtPointer) widget);
1348 key_menus->popup_kids [i++] = item;
1349
1350 item = XtCreateManagedWidget ("restoreKey", smeBSBObjectClass, menu, av, ac);
1351 XtAddCallback (item, XtNcallback, restore_key_default, (XtPointer) widget);
1352 key_menus->popup_kids [i++] = item;
1353
1354 key_menus->edit_key_box = make_edit_key_dbox (widget);
1355 key_menus->select_kbd_box = make_select_kbd_dbox (widget);
1356 return key_menus;
1357 }
1358
1359 void
1360 #ifdef __STDC__
sensitize_menu(KeyboardWidget widget,Widget menu,Bool sensitive)1361 sensitize_menu (KeyboardWidget widget, Widget menu, Bool sensitive)
1362 #else /* ! __STDC__ */
1363 sensitize_menu (widget, menu, sensitive)
1364 KeyboardWidget widget;
1365 Widget menu;
1366 Bool sensitive;
1367 #endif /* ! __STDC__ */
1368 {
1369 Arg av [10];
1370 int ac = 0, i = 0;
1371 struct key_menus *key_menus = widget->keyboard.key_menus;
1372 if (menu != key_menus->popup) return;
1373 XtSetArg (av [ac], XtNsensitive, sensitive); ac++;
1374 for (i = 0; i < sizeof (key_menus->popup_kids); i++)
1375 if (! key_menus->popup_kids [i]) return;
1376 else XtSetValues (key_menus->popup_kids [i], av, ac);
1377 }
1378
1379
1380
1381 Widget
1382 #ifdef __STDC__
make_command_widgets(Widget parent,Widget * kbd)1383 make_command_widgets (Widget parent, Widget *kbd)
1384 #else /* ! __STDC__ */
1385 make_command_widgets (parent, kbd)
1386 Widget parent;
1387 Widget *kbd;
1388 #endif /* ! __STDC__ */
1389 {
1390 Widget box, top;
1391 Arg av [20];
1392 int ac = 0;
1393 XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
1394 XtSetArg (av[ac], XtNright, XtChainLeft); ac++;
1395 XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
1396 XtSetArg (av[ac], XtNbottom, XtChainTop); ac++;
1397 box = XtCreateManagedWidget ("buttons", formWidgetClass, parent, av, ac);
1398 top = 0;
1399 top = make_button (box, "quit", NULL, 0, top, button_quit, kbd, 0);
1400 top = make_button (box, "keyboard", NULL, 0, top, pop_up_kbd_dbox, kbd, 0);
1401 top = make_button (box, "focus", NULL, 0, top, button_pick_window, kbd, 0);
1402 top = make_button (box, "restore", NULL, 0, top, button_restore, kbd, 0);
1403 top = make_button (box, "write", NULL, 0, top, button_write, kbd, 0);
1404
1405 return box;
1406 }
1407
1408
1409
1410 /* These are used to compute the default sizes of the windows. Hack hack.
1411 */
1412 #define LONGEST_KEYSYM_NAME "Greek_upsilonaccentdieresis"
1413 #define MEDIUM_LENGTH_KEYSYM_NAME "Greek_IOTAdiaresis"
1414
1415 struct keyset_names {
1416 const char *name; /* The name of this keyset (for the dialog box) */
1417 unsigned int number; /* The top two bytes of corresponding keysym values */
1418 }
1419
1420 static all_keyset_names[] = {
1421 { "Latin1", 0x00 },
1422 { "Latin2", 0x01 },
1423 { "Latin3", 0x02 },
1424 { "Latin4", 0x03 },
1425 { "Katakana", 0x04 },
1426 { "Arabic", 0x05 },
1427 { "Cyrillic", 0x06 },
1428 { "Greek", 0x07 },
1429 { "Technical", 0x08 },
1430 { "Special", 0x09 },
1431 { "Publishing", 0x0A },
1432 { "APL", 0x0B },
1433 { "Hebrew", 0x0C },
1434 { "Thai", 0x0D },
1435 { "Korean", 0x0E },
1436 { "ISO", 0xFE }, /* "ISO 9995 Function and Modifier Keys" */
1437 { "Keyboard", 0xFF },
1438 #ifdef DO_VENDOR_KEYSYMS
1439 { "Vendor", 0xFFFF }, /* special-case hack */
1440 #endif
1441 { 0, 0 }
1442 };
1443
1444 static char **keysym_name_buffer = 0;
1445 static int keysym_name_buffer_size = 0;
1446
1447 static void
1448 #ifdef __STDC__
ensure_keysym_name_buffer(int size)1449 ensure_keysym_name_buffer (int size)
1450 #else /* ! __STDC__ */
1451 ensure_keysym_name_buffer (size)
1452 int size;
1453 #endif /* ! __STDC__ */
1454 {
1455 if (keysym_name_buffer_size >= size)
1456 return;
1457 if (keysym_name_buffer) free ((char *) keysym_name_buffer);
1458 keysym_name_buffer_size = size;
1459 keysym_name_buffer = (char **) malloc (sizeof (char *) * size);
1460 }
1461
1462
1463 #ifdef DO_VENDOR_KEYSYMS
1464 struct vendor_keysym {
1465 char *name;
1466 KeySym keysym;
1467 int index;
1468 };
1469
1470 static struct vendor_keysym *vendor_keysyms = 0;
1471 static int n_vendor_keysyms = 0;
1472
1473 static XrmDatabase vendor_keysym_db = 0;
1474
1475 static Bool
1476 #ifdef __STDC__
init_vendor_keysyms_mapper(XrmDatabase * db,XrmBindingList bindings,XrmQuarkList quarks,XrmRepresentation * type,XrmValue * value,XPointer closure)1477 init_vendor_keysyms_mapper (XrmDatabase *db,
1478 XrmBindingList bindings,
1479 XrmQuarkList quarks,
1480 XrmRepresentation *type,
1481 XrmValue *value,
1482 XPointer closure)
1483 #else /* ! __STDC__ */
1484 init_vendor_keysyms_mapper (db, bindings, quarks, type, value, closure)
1485 XrmDatabase *db;
1486 XrmBindingList bindings;
1487 XrmQuarkList quarks;
1488 XrmRepresentation *type;
1489 XrmValue *value;
1490 XPointer closure;
1491 #endif /* ! __STDC__ */
1492 {
1493 KeySym keysym;
1494 char c;
1495 int i;
1496 int *count = (int *) closure;
1497 if (quarks [1]) /* should only be one level deep. */
1498 abort ();
1499
1500 if (! value->addr || value->size <= 1)
1501 return False;
1502
1503 keysym = 0;
1504 for (i = 0; i < value->size - 1; i++)
1505 {
1506 c = ((char *) value->addr) [i];
1507 if ('0' <= c && c <= '9') keysym = (keysym<<4)+c-'0';
1508 else if ('a' <= c && c <= 'z') keysym = (keysym<<4)+c-'a'+10;
1509 else if ('A' <= c && c <= 'Z') keysym = (keysym<<4)+c-'A'+10;
1510 else
1511 {
1512 fprintf (stderr, "%s: unparsable entry in XKeysymDB: \"%s: %s\"\n",
1513 progname, XrmQuarkToString (quarks [0]),
1514 (char *) value->addr);
1515 return False;
1516 }
1517 }
1518
1519 if (n_vendor_keysyms <= *count)
1520 {
1521 n_vendor_keysyms *= 2;
1522 vendor_keysyms = (struct vendor_keysym *)
1523 realloc (vendor_keysyms, sizeof (struct vendor_keysym) *
1524 n_vendor_keysyms);
1525 }
1526 vendor_keysyms [*count].index = -1; /* we fill this in later */
1527 vendor_keysyms [*count].keysym = keysym;
1528 vendor_keysyms [*count].name = (char *) XrmQuarkToString (quarks [0]);
1529 (*count)++;
1530 return False;
1531 }
1532
1533
1534 static int
1535 #ifdef __STDC__
sort_vendor_keysyms_1(int left,int right)1536 sort_vendor_keysyms_1 (int left, int right)
1537 #else /* ! __STDC__ */
1538 sort_vendor_keysyms_1 (left, right)
1539 int left, right;
1540 #endif /* ! __STDC__ */
1541 {
1542 int L = left, R = right, middle;
1543 struct vendor_keysym swap;
1544 KeySym pivot = vendor_keysyms [left].keysym;
1545 while (L < R)
1546 {
1547 while (vendor_keysyms [L].keysym <= pivot && L <= right)
1548 L++;
1549 while (vendor_keysyms [R].keysym > pivot && R >= left)
1550 R--;
1551 if (L < R)
1552 {
1553 swap = vendor_keysyms [L];
1554 vendor_keysyms [L] = vendor_keysyms [R];
1555 vendor_keysyms [R] = swap;
1556 }
1557 }
1558 middle = R;
1559 swap = vendor_keysyms [left];
1560 vendor_keysyms [left] = vendor_keysyms [middle];
1561 vendor_keysyms [middle] = swap;
1562 if (left < middle - 1)
1563 middle = sort_vendor_keysyms_1 (left, middle - 1);
1564 if (middle + 1 < right)
1565 middle = sort_vendor_keysyms_1 (middle + 1, right);
1566 return middle;
1567 }
1568
1569
1570 static void
sort_vendor_keysyms(void)1571 sort_vendor_keysyms P((void))
1572 {
1573 int i;
1574 sort_vendor_keysyms_1 (0, n_vendor_keysyms - 1);
1575 for (i = 0; i < n_vendor_keysyms; i++)
1576 {
1577 if (i > 0 && vendor_keysyms [i].keysym < vendor_keysyms [i-1].keysym)
1578 abort ();
1579 vendor_keysyms [i].index = i;
1580 }
1581 }
1582
1583
1584 #ifndef NO_XInitKeysymDB
1585 extern XrmDatabase _XInitKeysymDB P((void));
1586 #endif
1587
1588 static void
1589 #ifdef __STDC__
init_vendor_keysyms(KeyboardWidget widget)1590 init_vendor_keysyms (KeyboardWidget widget)
1591 #else /* ! __STDC__ */
1592 init_vendor_keysyms (widget)
1593 KeyboardWidget widget;
1594 #endif /* ! __STDC__ */
1595 {
1596 static int done = 0;
1597 int count = 0;
1598 XrmName name = { 0 };
1599 XrmClass class = { 0 };
1600
1601 if (done) return;
1602 done = 1;
1603
1604 if (! vendor_keysym_db)
1605 {
1606 char *dbname = (char *) getenv ("XKEYSYMDB");
1607 #ifdef KEYSYMDB
1608 if (! dbname) dbname = KEYSYMDB;
1609 #endif /* KEYSYMDB */
1610
1611 #ifdef NO_XInitKeysymDB
1612 if (dbname)
1613 vendor_keysym_db = XrmGetFileDatabase (dbname);
1614 #else /* we have _XInitKeysymDB(), so let Xlib be clever for us. */
1615 vendor_keysym_db = _XInitKeysymDB ();
1616 #endif /* _XInitKeysymDB */
1617
1618 if (! vendor_keysym_db) /* still don't have it... */
1619 {
1620 if (dbname)
1621 y_or_n_p_with_args (widget, "noKeysymDBError", "ok", 0, 0,
1622 dbname, 0, 0, 0, 0, 0);
1623 else
1624 y_or_n_p (widget, "unknownKeysymDBError", "ok", 0, 0);
1625 return;
1626 }
1627 }
1628
1629 n_vendor_keysyms = 255; /* probably not more than this; it's realloc'd. */
1630 vendor_keysyms = (struct vendor_keysym *)
1631 malloc (n_vendor_keysyms * sizeof (struct vendor_keysym));
1632
1633 XrmEnumerateDatabase (vendor_keysym_db, &name, &class,
1634 XrmEnumOneLevel, init_vendor_keysyms_mapper,
1635 (XtPointer) &count);
1636
1637 if (count < n_vendor_keysyms) /* might as well shrink it */
1638 {
1639 n_vendor_keysyms = count;
1640 vendor_keysyms = (struct vendor_keysym *)
1641 realloc (vendor_keysyms, count * sizeof (struct vendor_keysym));
1642 }
1643 else if (! count)
1644 {
1645 free ((char *) vendor_keysyms);
1646 n_vendor_keysyms = 0;
1647 vendor_keysyms = 0;
1648 return;
1649 }
1650 /* Hash order isn't very pretty; sort them by keysym numeric value. */
1651 sort_vendor_keysyms ();
1652 }
1653
1654 static void
1655 #ifdef __STDC__
fill_keysym_name_buffer_with_vendor_keysyms(KeyboardWidget keyboard)1656 fill_keysym_name_buffer_with_vendor_keysyms (KeyboardWidget keyboard)
1657 #else /* ! __STDC__ */
1658 fill_keysym_name_buffer_with_vendor_keysyms (keyboard)
1659 KeyboardWidget keyboard;
1660 #endif /* ! __STDC__ */
1661 {
1662 int i;
1663 if (! vendor_keysyms) init_vendor_keysyms (keyboard);
1664 ensure_keysym_name_buffer (n_vendor_keysyms + 1);
1665 for (i = 0; i < n_vendor_keysyms; i++)
1666 keysym_name_buffer [i] = vendor_keysyms [i].name;
1667 keysym_name_buffer [i] = 0;
1668 }
1669
1670
1671 static int
1672 #ifdef __STDC__
vendor_keysym_to_small_index(KeyboardWidget keyboard,KeySym keysym)1673 vendor_keysym_to_small_index (KeyboardWidget keyboard, KeySym keysym)
1674 #else /* ! __STDC__ */
1675 vendor_keysym_to_small_index (keyboard, keysym)
1676 KeyboardWidget keyboard;
1677 KeySym keysym;
1678 #endif /* ! __STDC__ */
1679 {
1680 int i;
1681 char buf [255];
1682 if (! vendor_keysyms) init_vendor_keysyms (keyboard);
1683 for (i = 0; i < n_vendor_keysyms; i++)
1684 if (keysym == vendor_keysyms [i].keysym)
1685 return vendor_keysyms [i].index;
1686 sprintf (buf, "Unrecognised vendor keysym 0x%08X.", (int) keysym);
1687 XBell (XtDisplay ((Widget) keyboard), 0);
1688 message (keyboard, buf);
1689 fprintf (stderr, "%s: %s\n", progname, buf);
1690 return 0;
1691 }
1692
1693 #endif /* DO_VENDOR_KEYSYMS */
1694
1695
1696 struct edit_key_box {
1697 KeyboardWidget keyboard;
1698 Widget shell;
1699 Widget label;
1700 Widget keysym_buttons [8];
1701 Widget mod_buttons [8];
1702 Widget keyset_list, keysym_list;
1703 Widget autorepeat_widget;
1704 int autorepeat;
1705 };
1706
1707
1708 static void
1709 #ifdef __STDC__
keyset_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)1710 keyset_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
1711 #else /* ! __STDC__ */
1712 keyset_list_cb (widget, client_data, call_data)
1713 Widget widget;
1714 XtPointer client_data, call_data;
1715 #endif /* ! __STDC__ */
1716 {
1717 XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
1718 struct edit_key_box *box = (struct edit_key_box *) client_data;
1719 int set = 0;
1720 int i, j = 0;
1721 int set_start = 0;
1722
1723 set = -1;
1724 for (i = 0; i < sizeof(all_keyset_names)/sizeof(*all_keyset_names); i++)
1725 if (lr->list_index == i)
1726 {
1727 set = all_keyset_names[i].number;
1728 break;
1729 }
1730
1731 if (set != 0) set_start = 1; /* Latin1 is the only set that has NoSymbol */
1732
1733 #ifdef DO_VENDOR_KEYSYMS
1734 if (set == 0xFFFF) /* FFFF means "vendor keysym" */
1735 fill_keysym_name_buffer_with_vendor_keysyms (box->keyboard);
1736 else
1737 #endif
1738 if (set == -1)
1739 {
1740 ensure_keysym_name_buffer (256);
1741 keysym_name_buffer [0] = 0;
1742 }
1743 else
1744 {
1745 ensure_keysym_name_buffer (256);
1746 for (i = set_start; i < 256; i++)
1747 {
1748 char *name = XKeysymToString ((set << 8) | i);
1749 if (! name && i == 0) name = "NoSymbol";
1750 if (name)
1751 keysym_name_buffer [j++] = name;
1752 }
1753 keysym_name_buffer [j++] = 0;
1754 }
1755 XawListChange (box->keysym_list, keysym_name_buffer, 0, 0, True);
1756 }
1757
1758
1759 static void
1760 #ifdef __STDC__
keysym_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)1761 keysym_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
1762 #else /* ! __STDC__ */
1763 keysym_list_cb (widget, client_data, call_data)
1764 Widget widget;
1765 XtPointer client_data, call_data;
1766 #endif /* ! __STDC__ */
1767 {
1768 XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
1769 struct edit_key_box *box = (struct edit_key_box *) client_data;
1770 int i = (int) XawToggleGetCurrent (box->keysym_buttons [0]);
1771 if (i > 0)
1772 {
1773 Widget button = box->keysym_buttons [i-1];
1774 /* If the string is wider than the parent of the button, setting the
1775 label will leave it at the size it was before. So, first stretch
1776 it to the max width, and then let SetValues (maybe) resize it
1777 smaller. What a piece of junk. */
1778 XtResizeWidget (button,
1779 XtParent (button)->core.width,
1780 button->core.height,
1781 button->core.border_width);
1782 XtVaSetValues (button, XtNlabel, lr->string, 0);
1783 }
1784 }
1785
1786
1787 static void
1788 #ifdef __STDC__
autorepeat_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)1789 autorepeat_button_cb (Widget widget, XtPointer client_data,
1790 XtPointer call_data)
1791 #else /* ! __STDC__ */
1792 autorepeat_button_cb (widget, client_data, call_data)
1793 Widget widget;
1794 XtPointer client_data, call_data;
1795 #endif /* ! __STDC__ */
1796 {
1797 struct edit_key_box *box = (struct edit_key_box *) client_data;
1798 Arg av [10];
1799 int ac = 0;
1800 box->autorepeat = !box->autorepeat;
1801 XtSetArg (av [ac], XtNlabel, (box->autorepeat ? "Yes" : "No")); ac++;
1802 XtSetValues (widget, av, ac);
1803 }
1804
1805
1806 static void
1807 #ifdef __STDC__
abort_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)1808 abort_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
1809 #else /* ! __STDC__ */
1810 abort_button_cb (widget, client_data, call_data)
1811 Widget widget;
1812 XtPointer client_data, call_data;
1813 #endif /* ! __STDC__ */
1814 {
1815 struct edit_key_box *box = (struct edit_key_box *) client_data;
1816 XtPopdown (box->shell);
1817 message (box->keyboard, "Aborted.");
1818 }
1819
1820
1821 static int stop_the_insanity P((KeyboardWidget,
1822 int keycode, KeySym *keysyms, int count,
1823 unsigned long modbits,
1824 XModifierKeymap *modmap));
1825
1826
1827 static void
1828 #ifdef __STDC__
ok_button_cb(Widget button,XtPointer client_data,XtPointer call_data)1829 ok_button_cb (Widget button, XtPointer client_data, XtPointer call_data)
1830 #else /* ! __STDC__ */
1831 ok_button_cb (button, client_data, call_data)
1832 Widget button;
1833 XtPointer client_data, call_data;
1834 #endif /* ! __STDC__ */
1835 {
1836 struct edit_key_box *box = (struct edit_key_box *) client_data;
1837 KeyboardWidget widget = box->keyboard;
1838 KeyWidget key = widget->keyboard.key_under_mouse;
1839 KeyCode code = key->key.keycode;
1840 KeySym keysyms [8];
1841 int keysym_count;
1842 unsigned long modbits = 0;
1843 XModifierKeymap *modmap = XGetModifierMapping (XtDisplay (widget));
1844 int i, error;
1845 Arg av [10];
1846 int ac = 0;
1847 char *str;
1848
1849 ac = 0;
1850 XtSetArg (av [ac], XtNlabel, &str); ac++;
1851 for (i = 0; i < 8; i++)
1852 {
1853 XtGetValues (box->keysym_buttons [i], av, ac);
1854 if (str && !strcmp (str, "NoSymbol")) str = 0;
1855 if (! str)
1856 keysyms [i] = 0;
1857 else
1858 {
1859 keysyms [i] = XStringToKeysym (str);
1860 if (! keysyms [i])
1861 fprintf (stderr,
1862 "%s: ERROR: XStringToKeysym(\"%s\") returned 0\n",
1863 progname, str);
1864 }
1865 }
1866 for (keysym_count = 8; keysym_count > 0; keysym_count--)
1867 if (keysyms [keysym_count-1]) break;
1868
1869 for (i = 0; i < 8; i++)
1870 {
1871 #ifndef XAWBUG
1872 Boolean state = 0;
1873 XtVaGetValues (box->mod_buttons[i], XtNstate, &state, NULL);
1874 #else /* XAWBUG */
1875 int state = ((CommandWidget) (box->mod_buttons [i]))->command.set;
1876 #endif
1877 modbits |= ((!!state) << i);
1878 if (state)
1879 modmap = XInsertModifiermapEntry (modmap, code, i);
1880 else
1881 modmap = XDeleteModifiermapEntry (modmap, code, i);
1882 }
1883
1884 if (stop_the_insanity (widget, code, keysyms, keysym_count, modbits, modmap))
1885 return;
1886
1887 XSync (XtDisplay (widget), 0);
1888 error = modify_keyboard (widget, code, keysym_count,
1889 keysyms, 1, modmap);
1890 XFreeModifiermap (modmap);
1891
1892 if (!error && box->autorepeat != key->key.auto_repeat_p)
1893 {
1894 XKeyboardControl values;
1895 values.key = key->key.keycode;
1896 values.auto_repeat_mode =
1897 (box->autorepeat ? AutoRepeatModeOn : AutoRepeatModeOff);
1898 XChangeKeyboardControl (XtDisplay (widget), KBKey | KBAutoRepeatMode,
1899 &values);
1900 }
1901
1902 XtPopdown (box->shell);
1903
1904 if (! error) message (box->keyboard, "Modified.");
1905 }
1906
1907
1908 static void
1909 #ifdef __STDC__
move_scrollbar(Widget list,float percent)1910 move_scrollbar (Widget list, float percent)
1911 #else /* ! __STDC__ */
1912 move_scrollbar (list, percent)
1913 Widget list;
1914 float percent;
1915 #endif /* ! __STDC__ */
1916 {
1917 Widget vp = XtParent (list);
1918 Widget scrollbar = XtNameToWidget (vp, "vertical");
1919 float visible_fraction = (((float) vp->core.height) /
1920 ((float) list->core.height));
1921 if (visible_fraction < 1.0)
1922 percent -= (visible_fraction / 2.0);
1923 XawScrollbarSetThumb (scrollbar, 0.0, -1.0);
1924 XtCallCallbacks (scrollbar, XtNjumpProc, (XtPointer) &percent);
1925 }
1926
1927
1928 static void
1929 #ifdef __STDC__
keysym_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)1930 keysym_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
1931 #else /* ! __STDC__ */
1932 keysym_button_cb (widget, client_data, call_data)
1933 Widget widget;
1934 XtPointer client_data, call_data;
1935 #endif /* ! __STDC__ */
1936 {
1937 struct edit_key_box *box = (struct edit_key_box *) client_data;
1938 KeyboardWidget keyboard = box->keyboard;
1939 char *keysym_name = 0;
1940 KeySym real_keysym;
1941 int list_index = 0;
1942 int keyset = 0, keysym = 0, index = 0, list_size = 0;
1943 Arg av[10];
1944 int ac = 0;
1945 int i;
1946
1947 if (call_data == 0) /* we're being toggled off */
1948 return;
1949
1950 XtSetArg (av[ac], XtNlabel, &keysym_name); ac++;
1951 XtGetValues (widget, av, ac);
1952 real_keysym = XStringToKeysym (keysym_name);
1953 /* Get the one that's in the list */
1954 keysym_name = XKeysymToString (real_keysym);
1955
1956 if (real_keysym > 0xFFFF)
1957 {
1958 #ifdef DO_VENDOR_KEYSYMS
1959 int i;
1960 keysym = 0;
1961 for (i = 0; i < sizeof(all_keyset_names)/sizeof(*all_keyset_names); i++)
1962 if (!strcmp(all_keyset_names[i].name, "Vendor"))
1963 {
1964 keysym = i;
1965 break;
1966 }
1967 if (keysym == 0) abort();
1968 keysym = vendor_keysym_to_small_index (keyboard, real_keysym);
1969 #else
1970 XBell (XtDisplay (keyboard), 0);
1971 message (keyboard,
1972 "XKeyCaps was compiled without support for Vendor keysyms.");
1973 message2 (keyboard, "Consider upgrading to X11r5...");
1974 keyset = 0;
1975 keysym = 0;
1976 #endif
1977 }
1978 else
1979 {
1980 keyset = (real_keysym >> 8);
1981 keysym = (real_keysym & 0xff);
1982 }
1983
1984 list_size = (sizeof (all_keyset_names) / sizeof (all_keyset_names[0]));
1985
1986 list_index = -1;
1987 for (i = 0; i < sizeof(all_keyset_names)/sizeof(*all_keyset_names); i++)
1988 if (all_keyset_names[i].number == keyset)
1989 {
1990 list_index = i;
1991 break;
1992 }
1993
1994 if (list_index < 0)
1995 {
1996 XawListUnhighlight(box->keyset_list);
1997 move_scrollbar (box->keyset_list, 0.0);
1998 }
1999 else
2000 {
2001 XawListHighlight (box->keyset_list, list_index);
2002 move_scrollbar (box->keyset_list,
2003 (((float) list_index) / ((float) list_size)));
2004 }
2005 keyset_list_cb (box->keyset_list, box,
2006 XawListShowCurrent (box->keyset_list));
2007
2008 index = 256;
2009 for (list_size = 0; list_size < 256; list_size++)
2010 if (keysym_name_buffer [list_size] == keysym_name)
2011 index = list_size;
2012 else if (! keysym_name_buffer [list_size])
2013 break;
2014 if (! keysym_name) index = 0;
2015 if (index < 256)
2016 {
2017 XawListHighlight (box->keysym_list, index);
2018 move_scrollbar (box->keysym_list,
2019 (((float) index) / ((float) list_size)));
2020 }
2021 else
2022 {
2023 XawListUnhighlight (box->keysym_list);
2024 }
2025 }
2026
2027
2028 static void
2029 #ifdef __STDC__
undo_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)2030 undo_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2031 #else /* ! __STDC__ */
2032 undo_button_cb (widget, client_data, call_data)
2033 Widget widget;
2034 XtPointer client_data, call_data;
2035 #endif /* ! __STDC__ */
2036 {
2037 struct edit_key_box *box = (struct edit_key_box *) client_data;
2038 KeyboardWidget keyboard = box->keyboard;
2039 KeyWidget key = keyboard->keyboard.key_under_mouse;
2040 KeySym *keysyms;
2041 int syms_per_code = 0;
2042 char buf [255];
2043 Arg av[20];
2044 int ac = 0;
2045 int i;
2046
2047 keysyms = XGetKeyboardMapping (XtDisplay (widget), key->key.keycode,
2048 1, &syms_per_code);
2049
2050 sprintf (buf, "Definition of key 0x%02X (%s)", key->key.keycode,
2051 key->key.key_name);
2052 XtSetArg (av[ac], XtNlabel, buf); ac++;
2053 XtSetValues (box->label, av, ac);
2054 ac = 0;
2055
2056 for (i = 0; i < syms_per_code; i++)
2057 {
2058 char *sym;
2059 char buf [255];
2060 if (!keysyms || !keysyms[i])
2061 sym = "NoSymbol";
2062 else
2063 sym = XKeysymToString (keysyms [i]);
2064 if (! sym)
2065 {
2066 sprintf (buf, "0x%04X", (int) keysyms [i]);
2067 sym = buf;
2068 }
2069 ac = 0;
2070 XtSetArg (av[ac], XtNlabel, sym); ac++;
2071 XtSetValues (box->keysym_buttons [i], av, ac);
2072 }
2073 if (keysyms) XFree ((char *) keysyms);
2074 ac = 0;
2075 XtSetArg (av[ac], XtNlabel, "NoSymbol"); ac++;
2076 for (; i < 8; i++)
2077 XtSetValues (box->keysym_buttons [i], av, ac);
2078
2079 for (i = 0; i < 8; i++)
2080 {
2081 ac = 0;
2082 XtSetArg (av[ac], XtNstate,
2083 ((key->key.modifier_bits & 1<<i) ? True : False)); ac++;
2084 XtSetValues (box->mod_buttons [i], av, ac);
2085 }
2086
2087 XawToggleSetCurrent (box->keysym_buttons [0], (XtPointer) 1);
2088 keysym_button_cb (box->keysym_buttons [0], box, (void *) 1);
2089 box->autorepeat = !key->key.auto_repeat_p;
2090 autorepeat_button_cb (box->autorepeat_widget, box, 0);
2091 }
2092
2093
2094 static struct edit_key_box *
2095 #ifdef __STDC__
make_edit_key_dbox(KeyboardWidget widget)2096 make_edit_key_dbox (KeyboardWidget widget)
2097 #else /* ! __STDC__ */
2098 make_edit_key_dbox (widget)
2099 KeyboardWidget widget;
2100 #endif /* ! __STDC__ */
2101 {
2102 struct edit_key_box *box = (struct edit_key_box *)
2103 malloc (sizeof (struct edit_key_box));
2104 Arg av [20];
2105 int ac = 0;
2106 Widget toplevel, box1, box2;
2107 Widget keysym_box, button_box, keyset_box, keyset_syms_box, mod_box;
2108 Widget line_box, prev, prev_tog;
2109 Widget set_list, sym_list;
2110 Widget set_vp, sym_vp;
2111
2112 toplevel = XtCreatePopupShell ("editKey", transientShellWidgetClass,
2113 (Widget) widget, av, ac);
2114 box1 = XtCreateManagedWidget ("vertical", panedWidgetClass, toplevel, av,ac);
2115 box->label = make_label (box1, "label", 0, 0, 0);
2116 ac = 0;
2117 XtSetArg (av[ac], XtNorientation, "horizontal"); ac++;
2118 box2 = XtCreateManagedWidget ("horizontal", panedWidgetClass, box1, av, ac);
2119
2120 ac = 0;
2121 keysym_box = XtCreateManagedWidget ("keysymBox", formWidgetClass, box2,
2122 av, ac);
2123 prev = make_label (keysym_box, "symsOfCode", 0, 0, 0);
2124 prev = make_label (keysym_box, "spacer", "", 0, prev);
2125 ac = 0;
2126 prev_tog = 0;
2127 line_box = prev;
2128 #define TOG(var, name, index) \
2129 { ac = 0; \
2130 XtSetArg (av[ac], XtNorientation, "horizontal"); ac++; \
2131 XtSetArg (av [ac], XtNfromVert, line_box); ac++; \
2132 XtSetArg (av[ac], XtNtop, XtChainTop); ac++; \
2133 XtSetArg (av[ac], XtNbottom, XtChainTop); ac++; \
2134 line_box = XtCreateManagedWidget ("keysymLine", boxWidgetClass, \
2135 keysym_box, av, ac); \
2136 var = make_label (line_box, name, 0, 0, prev); \
2137 if (index) \
2138 var = make_toggle (line_box, "keysymValue" ,var, prev, 0, \
2139 keysym_button_cb, box, MEDIUM_LENGTH_KEYSYM_NAME, \
2140 prev_tog, (XtPointer) index); \
2141 else \
2142 var = make_button (line_box, "autoRepeatValue", "Yes", var, prev, \
2143 autorepeat_button_cb, box, 0); \
2144 prev_tog = prev = var; }
2145 TOG (box->keysym_buttons [0], "keysym1", 1);
2146 TOG (box->keysym_buttons [1], "keysym2", 2);
2147 TOG (box->keysym_buttons [2], "keysym3", 3);
2148 TOG (box->keysym_buttons [3], "keysym4", 4);
2149 TOG (box->keysym_buttons [4], "keysym5", 5);
2150 TOG (box->keysym_buttons [5], "keysym6", 6);
2151 TOG (box->keysym_buttons [6], "keysym7", 7);
2152 TOG (box->keysym_buttons [7], "keysym8", 8);
2153 prev = prev_tog = 0;
2154 line_box = make_label (keysym_box, "spacer2", "", 0, line_box);
2155 TOG (box->autorepeat_widget, "autoRepeat", 0);
2156 #undef TOG
2157
2158 ac = 0;
2159 mod_box = XtCreateManagedWidget ("modifierBox", formWidgetClass,
2160 box2, av, ac);
2161 prev = make_label (mod_box, "modifiers", 0, 0, 0);
2162 prev = make_label (mod_box, "spacer", "", 0, prev);
2163 #define TOG(var, name) \
2164 { var = make_toggle (mod_box, name, 0, prev, 0, 0, 0, 0, 0, 0); \
2165 prev = var; }
2166 TOG (box->mod_buttons [0], "modShift");
2167 TOG (box->mod_buttons [1], "modLock");
2168 TOG (box->mod_buttons [2], "modControl");
2169 TOG (box->mod_buttons [3], "mod1");
2170 TOG (box->mod_buttons [4], "mod2");
2171 TOG (box->mod_buttons [5], "mod3");
2172 TOG (box->mod_buttons [6], "mod4");
2173 TOG (box->mod_buttons [7], "mod5");
2174 #undef TOG
2175
2176 ac = 0;
2177 keyset_box = XtCreateManagedWidget("keysetBox", formWidgetClass,
2178 box2, av, ac);
2179 prev = make_label (keyset_box, "allKeySets", 0, 0, 0);
2180 ac = 0;
2181 XtSetArg (av[ac], XtNfromVert, prev); ac++;
2182 XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2183 XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2184 XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2185 XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2186 set_vp = XtCreateManagedWidget ("keysetsVp", viewportWidgetClass,
2187 keyset_box, av, ac);
2188 ac = 0;
2189 {
2190 static const char *list[sizeof(all_keyset_names) /
2191 sizeof(*all_keyset_names)];
2192 int i = 0;
2193 for (i = 0; i < sizeof(list)/sizeof(*list); i++)
2194 list[i] = all_keyset_names[i].name;
2195 XtSetArg (av[ac], XtNlist, list); ac++;
2196 }
2197
2198 set_list = XtCreateManagedWidget ("keysets", listWidgetClass, set_vp,av,ac);
2199 XtAddCallback (set_list, XtNcallback, keyset_list_cb, (XtPointer) box);
2200
2201 /* Gag! These lists won't size themselves correctly. */
2202 XtVaSetValues (set_list, XtNwidth, set_list->core.width + 20, 0);
2203
2204 ac = 0;
2205 keyset_syms_box = XtCreateManagedWidget ("keysetSymsBox", formWidgetClass,
2206 box2, av, ac);
2207 prev = make_label (keyset_syms_box, "keySymsOfSet", 0, 0, 0);
2208 ac = 0;
2209 XtSetArg (av[ac], XtNfromVert, prev); ac++;
2210 XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2211 XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2212 XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2213 XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2214 sym_vp = XtCreateManagedWidget ("keysymsVp", viewportWidgetClass,
2215 keyset_syms_box, av, ac);
2216 ensure_keysym_name_buffer (256);
2217
2218 #if 0
2219 memcpy (keysym_name_buffer, all_keyset_names, sizeof (all_keyset_names));
2220 #endif
2221
2222 keysym_name_buffer [0] = LONGEST_KEYSYM_NAME;
2223 keysym_name_buffer [1] = 0;
2224
2225 ac = 0;
2226 XtSetArg (av[ac], XtNlist, keysym_name_buffer); ac++;
2227 sym_list = XtCreateManagedWidget ("keysyms", listWidgetClass, sym_vp,av,ac);
2228 XtAddCallback (sym_list, XtNcallback, keysym_list_cb, (XtPointer) box);
2229
2230 /* Gag! These lists won't size themselves correctly. */
2231 XtVaSetValues (sym_list, XtNwidth, sym_list->core.width + 20, 0);
2232
2233 ac = 0;
2234 XtSetArg (av[ac], XtNskipAdjust, True); ac++;
2235 button_box = XtCreateManagedWidget ("buttons", boxWidgetClass, box1, av, ac);
2236
2237 prev = make_button (button_box, "undo", 0, 0, 0, undo_button_cb, box, 0);
2238 prev = make_button (button_box, "abort", 0, prev, 0, abort_button_cb, box,0);
2239 prev = make_button (button_box, "ok", 0, prev, 0, ok_button_cb, box, 0);
2240
2241 box->keyboard = widget;
2242 box->shell = toplevel;
2243 box->keyset_list = set_list;
2244 box->keysym_list = sym_list;
2245 return box;
2246 }
2247
2248 static void
2249 #ifdef __STDC__
pop_up_key_dbox(Widget parent,XtPointer client_data,XtPointer call_data)2250 pop_up_key_dbox (Widget parent, XtPointer client_data, XtPointer call_data)
2251 #else /* ! __STDC__ */
2252 pop_up_key_dbox (parent, client_data, call_data)
2253 Widget parent;
2254 XtPointer client_data, call_data;
2255 #endif /* ! __STDC__ */
2256 {
2257 KeyboardWidget widget = (KeyboardWidget) client_data;
2258 struct edit_key_box *edit_key_box =
2259 widget->keyboard.key_menus->edit_key_box;
2260
2261 if (widget->keyboard.key_under_mouse->key.keycode == 0)
2262 {
2263 y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
2264 return;
2265 }
2266
2267 {
2268 Widget topmost = parent;
2269 int x, y, w, h;
2270 XtRealizeWidget (edit_key_box->shell);
2271 w = edit_key_box->shell->core.width;
2272 h = edit_key_box->shell->core.height;
2273 while (topmost->core.parent)
2274 topmost = topmost->core.parent;
2275 if (topmost->core.width < w) x = topmost->core.x;
2276 else x = topmost->core.x + ((topmost->core.width - w) / 2);
2277 if (topmost->core.height < h) y = topmost->core.y;
2278 else y = topmost->core.y + ((topmost->core.height - h) / 2);
2279 XtMoveWidget (edit_key_box->shell, x, y);
2280 }
2281 XtPopup (edit_key_box->shell, XtGrabNonexclusive);
2282 undo_button_cb (edit_key_box->shell, edit_key_box, 0);
2283 }
2284
2285
2286
2287 static struct keyboard_set {
2288 int kbd_index;
2289 const char *vendor;
2290 char *type;
2291 char **maps; /* short names of maps */
2292 char **full_maps; /* long names (vendor+kbd+map) */
2293 int map_count;
2294 } *keyboard_sets;
2295
2296 int keyboard_set_count;
2297 int vendor_count;
2298 static char const **vendors;
2299 static char **keyboard_types; /* compared to keyboard_sets[i].type[j] */
2300 static char *longest_type; /* longest of all keyboard_sets[i].type */
2301 static char *longest_map; /* longest of all keyboard_sets[i].maps[j] */
2302
2303 struct select_kbd_box {
2304 KeyboardWidget keyboard;
2305 Widget shell;
2306 Widget label;
2307 Widget label2;
2308 Widget icon;
2309 Widget vendor_list, keyboard_list, keymap_list;
2310 struct keyboard_set *set;
2311 const char *map;
2312 };
2313
2314
2315 static char *default_maps[] = { "default", 0 };
2316
2317 static void
make_kbd_lists(void)2318 make_kbd_lists P((void))
2319 {
2320 int kbd_count = 0;
2321 int i, j;
2322
2323 i = 0;
2324 vendor_count = 0;
2325 while (all_kbds[i].vendor)
2326 {
2327 const char *v = all_kbds[i].vendor;
2328 vendor_count++;
2329 i++;
2330 while (all_kbds[i].vendor &&
2331 !strcmp(v, all_kbds[i].vendor))
2332 i++;
2333 }
2334
2335 vendors = (const char **) malloc (sizeof(*vendors) * (vendor_count+1));
2336 i = 0;
2337 j = 0;
2338 while (all_kbds[i].vendor)
2339 {
2340 const char *v = all_kbds[i].vendor;
2341 vendors[j++] = v;
2342 i++;
2343 while (all_kbds[i].vendor &&
2344 !strcmp(v, all_kbds[i].vendor))
2345 i++;
2346 }
2347 vendors[j] = 0;
2348
2349
2350 for (kbd_count = 0; all_kbds [kbd_count].short_name; kbd_count++)
2351 ;
2352 keyboard_sets = (struct keyboard_set *)
2353 malloc (sizeof (struct keyboard_set) * kbd_count);
2354 longest_type = 0;
2355 longest_map = 0;
2356
2357 i = 0;
2358 j = 0;
2359 while (i < kbd_count)
2360 {
2361 char last_style [255];
2362 char full [255];
2363
2364 char *tail;
2365 strcpy (last_style, all_kbds[i].kbd_style);
2366 make_long_kbd_name (all_kbds[i].vendor, last_style, full);
2367
2368 tail = (char *) strchr (last_style, '(');
2369 if (tail) *tail = 0;
2370
2371 tail = (char *) strchr (full, '(');
2372 keyboard_sets [j].kbd_index = i;
2373 keyboard_sets [j].map_count = 0;
2374 keyboard_sets [j].vendor = all_kbds[i].vendor;
2375
2376 if (tail)
2377 {
2378 int L;
2379 int count = 0;
2380 int k;
2381
2382 /* Edit out the parens (but not the trailing space) */
2383 *tail = 0;
2384 tail++;
2385 tail [strlen (tail) - 1] = 0;
2386
2387 L = strlen (full);
2388 count = 0;
2389 while (1)
2390 {
2391 char name[255];
2392 make_long_kbd_name(all_kbds[i+count].vendor,
2393 all_kbds[i+count].kbd_style,
2394 name);
2395 if (strlen (name) < L ||
2396 !!strncmp (full, name, L))
2397 break;
2398 count++;
2399 }
2400
2401 keyboard_sets [j].maps = (char **)
2402 malloc (sizeof (char *) * (count+1));
2403 keyboard_sets [j].full_maps = (char **)
2404 malloc (sizeof (char *) * (count+1));
2405 for (k = 0; k < count; k++)
2406 {
2407 char full[255];
2408 const char *map;
2409 char *map_name = 0;
2410 int ML;
2411 make_long_kbd_name(all_kbds [i+k].vendor,
2412 all_kbds [i+k].kbd_style,
2413 full);
2414 map = strchr(full, '(');
2415 if (!map) abort();
2416 map++;
2417 ML = strlen (map);
2418 map_name = (char *) malloc (ML);
2419 memcpy (map_name, map, ML);
2420 map_name [--ML] = 0;
2421 keyboard_sets [j].maps[k] = map_name;
2422 keyboard_sets [j].full_maps[k] = strdup(full);
2423 if (!longest_map || strlen (longest_map) < ML)
2424 longest_map = keyboard_sets [j].maps[k];
2425 }
2426 keyboard_sets [j].maps[k] = 0;
2427 i += count;
2428 keyboard_sets [j].map_count = count;
2429 }
2430 else
2431 {
2432 keyboard_sets [j].maps = default_maps;
2433 keyboard_sets [j].full_maps = (char **) malloc (sizeof (char *) * 2);
2434 keyboard_sets [j].full_maps [0] = strdup(full);
2435 keyboard_sets [j].full_maps [1] = 0;
2436 keyboard_sets [j].map_count = 1;
2437 i++;
2438 }
2439
2440 keyboard_sets [j].type = (char *) malloc (strlen (last_style) + 1);
2441 memcpy (keyboard_sets [j].type, last_style, strlen (last_style) + 1);
2442
2443 if (!longest_type ||
2444 strlen (longest_type) < strlen(keyboard_sets [j].type))
2445 longest_type = keyboard_sets [j].type;
2446
2447 j++;
2448 }
2449 keyboard_set_count = j;
2450
2451 {
2452 int max = 0;
2453 keyboard_types = (char **) malloc (sizeof (char *) * (j + 1));
2454 for (i = 0; i < j; i++)
2455 {
2456 keyboard_types [i] = keyboard_sets [i].type;
2457 if (keyboard_sets [i].map_count > max)
2458 max = keyboard_sets [i].map_count;
2459 }
2460 keyboard_types[i] = 0;
2461 }
2462 }
2463
2464 static void
2465 #ifdef __STDC__
kbd_abort_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)2466 kbd_abort_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2467 #else /* ! __STDC__ */
2468 kbd_abort_button_cb (widget, client_data, call_data)
2469 Widget widget;
2470 XtPointer client_data, call_data;
2471 #endif /* ! __STDC__ */
2472 {
2473 struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2474 Widget shell = box->shell;
2475 XtPopdown (shell);
2476 }
2477
2478 static void
2479 #ifdef __STDC__
kbd_ok_button_cb(Widget button,XtPointer client_data,XtPointer call_data)2480 kbd_ok_button_cb (Widget button, XtPointer client_data, XtPointer call_data)
2481 #else /* ! __STDC__ */
2482 kbd_ok_button_cb (button, client_data, call_data)
2483 Widget button;
2484 XtPointer client_data, call_data;
2485 #endif /* ! __STDC__ */
2486 {
2487 struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2488 KeyboardWidget kbd = box->keyboard;
2489 const char *map = box->map;
2490 kbd_abort_button_cb (button, client_data, call_data);
2491 replace_keyboard (kbd, map);
2492 }
2493
2494 static void
2495 #ifdef __STDC__
keymap_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)2496 keymap_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2497 #else /* ! __STDC__ */
2498 keymap_list_cb (widget, client_data, call_data)
2499 Widget widget;
2500 XtPointer client_data, call_data;
2501 #endif /* ! __STDC__ */
2502 {
2503 XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
2504 struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2505 struct keyboard_set *set = box->set;
2506 box->map = set->full_maps [lr->list_index];
2507 }
2508
2509 static int current_vendor_offset = 0;
2510
2511 static void
2512 #ifdef __STDC__
keyboard_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)2513 keyboard_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2514 #else /* ! __STDC__ */
2515 keyboard_list_cb (widget, client_data, call_data)
2516 Widget widget;
2517 XtPointer client_data, call_data;
2518 #endif /* ! __STDC__ */
2519 {
2520 XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
2521 struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2522 int kbd = lr->list_index + current_vendor_offset;
2523 int map = 0;
2524 int i = 0;
2525
2526 while (strcmp (keyboard_sets [i].type, keyboard_types [kbd]))
2527 i++;
2528 box->set = &keyboard_sets [i];
2529 XawListChange (box->keymap_list, (char **) box->set->maps, 0, 0, True);
2530 for (i = 0; i < box->set->map_count; i++)
2531 {
2532 char buf[255];
2533 make_long_kbd_name(box->keyboard->keyboard.vendor,
2534 box->keyboard->keyboard.kbd_style,
2535 buf);
2536 if (!strcmp (box->set->full_maps[i], buf))
2537 {
2538 map = i;
2539 break;
2540 }
2541 }
2542 XawListHighlight (box->keymap_list, map);
2543 lr->list_index = map;
2544 keymap_list_cb (widget, client_data, call_data);
2545 move_scrollbar (box->keymap_list,
2546 (((float) map) / ((float) box->set->map_count)));
2547 {
2548 int w, h;
2549 Pixmap p = get_keyboard_icon (XtDisplay (widget),
2550 &all_kbds [box->set->kbd_index], &w, &h);
2551 XtVaSetValues (box->icon, XtNbitmap, p, XtNheight, h, 0);
2552 }
2553 }
2554
2555
2556 static void
2557 #ifdef __STDC__
vendor_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)2558 vendor_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2559 #else /* ! __STDC__ */
2560 vendor_list_cb (widget, client_data, call_data)
2561 Widget widget;
2562 XtPointer client_data, call_data;
2563 #endif /* ! __STDC__ */
2564 {
2565 XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
2566 struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2567 int vendor = lr->list_index;
2568 const char *v = vendors[vendor];
2569 static char *list[255];
2570 int kbd;
2571 int i, j;
2572
2573 for (i = 0; i < keyboard_set_count; i++)
2574 if (!strcmp(v, keyboard_sets[i].vendor))
2575 break;
2576
2577 current_vendor_offset = i;
2578
2579 j = 0;
2580 while (keyboard_sets[i].type &&
2581 !strcmp(v, keyboard_sets[i].vendor))
2582 list[j++] = keyboard_sets[i++].type;
2583 list [j] = 0;
2584
2585 kbd = 0;
2586 if (box->set)
2587 {
2588 char *s1 = strdup (box->keyboard->keyboard.kbd_style);
2589 char *s2 = strchr (s1, '(');
2590 if (s2) *s2 = 0;
2591 for (i = 0; list[i]; i++)
2592 if (!strcmp (s1, list[i]))
2593 {
2594 kbd = i;
2595 break;
2596 }
2597 free (s1);
2598 }
2599
2600 XawListChange (box->keyboard_list, list, 0, 0, True);
2601 XawListHighlight (box->keyboard_list, kbd);
2602 lr->list_index = kbd;
2603
2604 keyboard_list_cb (widget, client_data, call_data);
2605 }
2606
2607
2608 static struct select_kbd_box *
2609 #ifdef __STDC__
make_select_kbd_dbox(KeyboardWidget widget)2610 make_select_kbd_dbox (KeyboardWidget widget)
2611 #else /* ! __STDC__ */
2612 make_select_kbd_dbox (widget)
2613 KeyboardWidget widget;
2614 #endif /* ! __STDC__ */
2615 {
2616 struct select_kbd_box *box = (struct select_kbd_box *)
2617 malloc (sizeof (struct select_kbd_box));
2618 Arg av [20];
2619 int ac = 0;
2620 Widget toplevel, box1, box2;
2621 Widget button_box, vendor_box, keyboard_box, keymap_box;
2622 Widget prev;
2623 Widget vendor_list, kbd_list, map_list;
2624 Widget vendor_vp, kbd_vp, map_vp;
2625
2626 make_kbd_lists ();
2627
2628 toplevel = XtCreatePopupShell ("selectKbd", transientShellWidgetClass,
2629 XtParent ((Widget) widget), av, ac);
2630 box1 = XtCreateManagedWidget ("vertical", panedWidgetClass, toplevel, av,ac);
2631 box->label = make_label (box1, "label", 0, 0, 0);
2632 box->label2 = make_label (box1, "label2", "", 0, 0);
2633 ac = 0;
2634 XtSetArg (av[ac], XtNorientation, "horizontal"); ac++;
2635 box2 = XtCreateManagedWidget ("horizontal", panedWidgetClass, box1, av, ac);
2636
2637 ac = 0;
2638 vendor_box = XtCreateManagedWidget ("vendorBox", formWidgetClass,
2639 box2, av, ac);
2640 prev = make_label (vendor_box, "vendors", 0, 0, 0);
2641 ac = 0;
2642 XtSetArg (av[ac], XtNfromVert, prev); ac++;
2643 XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2644 XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2645 XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2646 XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2647 vendor_vp = XtCreateManagedWidget ("vendorsVp", viewportWidgetClass,
2648 vendor_box, av, ac);
2649 ac = 0;
2650 XtSetArg (av[ac], XtNlist, vendors); ac++;
2651 vendor_list = XtCreateManagedWidget ("vendorsList", listWidgetClass,
2652 vendor_vp, av, ac);
2653 XtAddCallback (vendor_list, XtNcallback, vendor_list_cb, (XtPointer) box);
2654
2655 /* Gag! These lists won't size themselves correctly. */
2656 XtVaSetValues (vendor_list, XtNwidth, vendor_list->core.width + 20, 0);
2657
2658 ac = 0;
2659 keyboard_box = XtCreateManagedWidget ("keyboardBox", formWidgetClass,
2660 box2, av, ac);
2661 prev = make_label (keyboard_box, "keyboards", 0, 0, 0);
2662 ac = 0;
2663 XtSetArg (av[ac], XtNfromVert, prev); ac++;
2664 XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2665 XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2666 XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2667 XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2668 kbd_vp = XtCreateManagedWidget ("keyboardsVp", viewportWidgetClass,
2669 keyboard_box, av, ac);
2670 ac = 0;
2671
2672
2673 {
2674 static char *dummy[2];
2675 dummy[0] = longest_type;
2676 dummy[1] = 0;
2677 ac = 0;
2678 XtSetArg (av[ac], XtNlist, dummy); ac++;
2679 kbd_list = XtCreateManagedWidget ("keyboardsList", listWidgetClass, kbd_vp,
2680 av, ac);
2681 XtAddCallback (kbd_list, XtNcallback, keyboard_list_cb, (XtPointer) box);
2682
2683 /* Gag! These lists won't size themselves correctly. */
2684 XtVaSetValues (kbd_list, XtNwidth, kbd_list->core.width + 20, 0);
2685 }
2686
2687 ac = 0;
2688 keymap_box = XtCreateManagedWidget ("keymapBox", formWidgetClass,
2689 box2, av, ac);
2690 prev = make_label (keymap_box, "keymaps", 0, 0, 0);
2691 ac = 0;
2692 XtSetArg (av[ac], XtNfromVert, prev); ac++;
2693 XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2694 XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2695 XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2696 XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2697 map_vp = XtCreateManagedWidget ("keymapsVp", viewportWidgetClass,
2698 keymap_box, av, ac);
2699 {
2700 static char *dummy[2];
2701 dummy[0] = longest_map;
2702 dummy[1] = 0;
2703 ac = 0;
2704 XtSetArg (av[ac], XtNlist, dummy); ac++;
2705 map_list = XtCreateManagedWidget ("keymapsList", listWidgetClass, map_vp,
2706 av, ac);
2707 XtAddCallback (map_list, XtNcallback, keymap_list_cb, (XtPointer) box);
2708
2709 /* Gag! These lists won't size themselves correctly. */
2710 XtVaSetValues (map_list, XtNwidth, map_list->core.width + 20, 0);
2711 }
2712 ac = 0;
2713 XtSetArg (av[ac], XtNskipAdjust, True); ac++;
2714 button_box = XtCreateManagedWidget ("buttons", boxWidgetClass, box1, av, ac);
2715
2716 prev = make_button (button_box, "abort", 0, prev, 0, kbd_abort_button_cb,
2717 box, 0);
2718 prev = make_button (button_box, "ok", 0, prev, 0, kbd_ok_button_cb,
2719 box, 0);
2720 prev = make_label (button_box, "spacer", "", 0, prev);
2721 box->icon = make_label (button_box, "kbd_icon", 0, prev, 0);
2722
2723 box->keyboard = 0;
2724 box->shell = toplevel;
2725 box->vendor_list = vendor_list;
2726 box->keyboard_list = kbd_list;
2727 box->keymap_list = map_list;
2728 box->set = 0;
2729 box->map = 0;
2730 return box;
2731 }
2732
2733 void
2734 #ifdef __STDC__
pop_up_kbd_dbox(Widget parent,XtPointer client_data,XtPointer call_data)2735 pop_up_kbd_dbox (Widget parent, XtPointer client_data, XtPointer call_data)
2736 #else /* ! __STDC__ */
2737 pop_up_kbd_dbox (parent, client_data, call_data)
2738 Widget parent;
2739 XtPointer client_data, call_data;
2740 #endif /* ! __STDC__ */
2741 {
2742 KeyboardWidget widget = *((KeyboardWidget *) client_data);
2743 struct select_kbd_box *select_kbd_box =
2744 widget->keyboard.key_menus->select_kbd_box;
2745
2746 select_kbd_box->keyboard = widget;
2747 XtVaSetValues (select_kbd_box->label2, XtNlabel, choose_kbd_message, 0);
2748 choose_kbd_dubious_p = 0;
2749 choose_kbd_message [0] = 0;
2750
2751 {
2752 Widget topmost = parent;
2753 int x, y, w, h;
2754 XtRealizeWidget (select_kbd_box->shell);
2755 /* #### It'd be nice to wait here until it was mapped... */
2756 w = select_kbd_box->shell->core.width;
2757 h = select_kbd_box->shell->core.height;
2758 while (topmost->core.parent)
2759 topmost = topmost->core.parent;
2760 if (topmost->core.width < w) x = topmost->core.x;
2761 else x = topmost->core.x + ((topmost->core.width - w) / 2);
2762 if (topmost->core.height < h) y = topmost->core.y;
2763 else y = topmost->core.y + ((topmost->core.height - h) / 2);
2764 XtMoveWidget (select_kbd_box->shell, x, y);
2765 }
2766
2767 {
2768 XawListReturnStruct lr;
2769 int this_vendor = 0;
2770 int this_kbd = 0;
2771 int this_vendor_start = 0;
2772 int i, j;
2773 char buf[255];
2774 const char *last_vendor = 0;
2775
2776 make_long_kbd_name(widget->keyboard.vendor,
2777 widget->keyboard.kbd_style,
2778 buf);
2779 for (i = 0; i <= keyboard_set_count; i++)
2780 {
2781 if (last_vendor && !!strcmp(last_vendor, keyboard_sets[i].vendor))
2782 {
2783 this_vendor_start = i;
2784 this_vendor++;
2785 this_kbd = 0;
2786 }
2787 last_vendor = keyboard_sets[i].vendor;
2788
2789 for (j = 0; j < keyboard_sets[i].map_count; j++)
2790 if (!strcmp (keyboard_sets[i].full_maps[j], buf))
2791 {
2792 this_kbd = i - this_vendor_start;
2793 goto out;
2794 }
2795 }
2796 out:
2797 lr.list_index = this_vendor;
2798 XawListHighlight (select_kbd_box->vendor_list, this_vendor);
2799 move_scrollbar (select_kbd_box->vendor_list,
2800 (((float) this_vendor) / ((float) vendor_count)));
2801 vendor_list_cb ((Widget) widget,
2802 (void *) select_kbd_box,
2803 (void *) &lr);
2804
2805 lr.list_index = this_kbd;
2806 XawListHighlight (select_kbd_box->keyboard_list, this_kbd);
2807 /* move_scrollbar (select_kbd_box->keyboard_list,
2808 (((float) this_kbd) / ((float) keyboard_set_count)));
2809 */
2810 keyboard_list_cb ((Widget) widget,
2811 (void *) select_kbd_box,
2812 (void *) &lr);
2813 }
2814 XtPopup (select_kbd_box->shell, XtGrabNonexclusive);
2815 }
2816
2817
2818
2819 static void
2820 #ifdef __STDC__
yorn_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)2821 yorn_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2822 #else /* ! __STDC__ */
2823 yorn_button_cb (widget, client_data, call_data)
2824 Widget widget;
2825 XtPointer client_data, call_data;
2826 #endif /* ! __STDC__ */
2827 {
2828 *((int *) client_data) = 1;
2829 }
2830
2831
2832 static int
2833 #ifdef __STDC__
y_or_n_p_with_args(KeyboardWidget widget,char * name,char * name0,char * name1,char * name2,char * arg0,char * arg1,char * arg2,char * arg3,char * arg4,char * arg5)2834 y_or_n_p_with_args (KeyboardWidget widget,
2835 char *name,
2836 char *name0, char *name1, char *name2,
2837 char *arg0, char *arg1, char *arg2, char *arg3,
2838 char *arg4, char *arg5)
2839 #else /* ! __STDC__ */
2840 y_or_n_p_with_args (widget, name,
2841 name0, name1, name2,
2842 arg0, arg1, arg2, arg3, arg4, arg5)
2843 KeyboardWidget widget;
2844 char *name;
2845 char *name0, *name1, *name2;
2846 char *arg0, *arg1, *arg2, *arg3, *arg4, *arg5;
2847 #endif /* ! __STDC__ */
2848 {
2849 XtAppContext app = XtWidgetToApplicationContext ((Widget) widget);
2850 Widget topmost = (Widget) widget;
2851 Widget label;
2852 XEvent event;
2853 int x, y, w, h;
2854 Arg av [10];
2855 int ac = 0;
2856 Widget shell, box1, box2, prev;
2857 int ans [3];
2858
2859 shell = XtCreatePopupShell (name, transientShellWidgetClass,
2860 (Widget) widget, av, ac);
2861 box1 = XtCreateManagedWidget ("paned", panedWidgetClass, shell, av, ac);
2862 label = make_label (box1, "label", 0, 0, 0);
2863 if (arg0) /* format into the label if desired. */
2864 {
2865 char *old_string;
2866 char new_string [4000];
2867 ac = 0;
2868 XtSetArg (av [ac], XtNlabel, &old_string); ac++;
2869 XtGetValues (label, av, ac);
2870 if (!strcmp (old_string, XtName (label)))
2871 strcpy (new_string, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
2872 else
2873 sprintf (new_string, old_string, arg0, arg1, arg2, arg3, arg4, arg5);
2874 ac = 0;
2875 XtSetArg (av [ac], XtNlabel, new_string); ac++;
2876 XtSetValues (label, av, ac);
2877 }
2878 ac = 0;
2879 XtSetArg (av[ac], XtNorientation, "horizontal"); ac++;
2880 box2 = XtCreateManagedWidget ("buttons", boxWidgetClass, box1, av, ac);
2881 prev = 0;
2882 if (name0) prev = make_button (box2,name0,0,prev,0,yorn_button_cb,&ans[0],0);
2883 if (name1) prev = make_button (box2,name1,0,prev,0,yorn_button_cb,&ans[1],0);
2884 if (name2) prev = make_button (box2,name2,0,prev,0,yorn_button_cb,&ans[2],0);
2885 XtRealizeWidget (shell);
2886 w = shell->core.width;
2887 h = shell->core.height;
2888 while (topmost->core.parent)
2889 topmost = topmost->core.parent;
2890 if (topmost->core.width < w) x = topmost->core.x;
2891 else x = topmost->core.x + ((topmost->core.width - w) / 2);
2892 if (topmost->core.height < h) y = topmost->core.y;
2893 else y = topmost->core.y + ((topmost->core.height - h) / 2);
2894 XtMoveWidget (shell, x, y);
2895
2896 XtPopup (shell, XtGrabNonexclusive);
2897 memset (ans, 0, sizeof (ans));
2898 while (! (ans[0] || ans[1] || ans[2]))
2899 {
2900 XtAppNextEvent (app, &event);
2901 if (event.xany.type == KeymapNotify)
2902 keyboard_handle_keymap_notify ((Widget) widget, 0, &event, 0);
2903 else if (event.xany.type == MappingNotify)
2904 keyboard_handle_mapping_notify ((Widget) widget, 0, &event, 0);
2905 XtDispatchEvent (&event);
2906 }
2907 XtPopdown (shell);
2908 XtDestroyWidget (shell);
2909 if (ans[0]) return 0;
2910 if (ans[1]) return 1;
2911 if (ans[2]) return 2;
2912 exit (-69);
2913 }
2914
2915 static int
2916 #ifdef __STDC__
y_or_n_p(KeyboardWidget widget,char * name,char * name0,char * name1,char * name2)2917 y_or_n_p (KeyboardWidget widget,
2918 char *name, char *name0, char *name1, char *name2)
2919 #else /* ! __STDC__ */
2920 y_or_n_p (widget, name, name0, name1, name2)
2921 KeyboardWidget widget;
2922 char *name, *name0, *name1, *name2;
2923 #endif /* ! __STDC__ */
2924 {
2925 return y_or_n_p_with_args (widget, name, name0, name1, name2, 0,0,0,0,0,0);
2926 }
2927
2928
2929 KeyWidget
2930 #ifdef __STDC__
prompt_for_key(KeyboardWidget keyboard,char * msg)2931 prompt_for_key (KeyboardWidget keyboard, char *msg)
2932 #else /* ! __STDC__ */
2933 prompt_for_key (keyboard, msg)
2934 KeyboardWidget keyboard;
2935 char *msg;
2936 #endif /* ! __STDC__ */
2937 {
2938 XtAppContext app = XtWidgetToApplicationContext ((Widget) keyboard);
2939 KeyWidget key;
2940 XEvent event;
2941 message (keyboard, msg);
2942
2943 if (XGrabPointer (XtDisplay (keyboard), XtWindow (keyboard), True,
2944 ButtonPressMask | ButtonReleaseMask,
2945 GrabModeAsync, GrabModeAsync, 0,
2946 keyboard->keyboard.select_cursor,
2947 CurrentTime))
2948 {
2949 XBell (XtDisplay (keyboard), 0);
2950 message (keyboard, "Grab failed.");
2951 return 0;
2952 }
2953
2954 while (1)
2955 {
2956 XtAppNextEvent (app, &event);
2957
2958 if (event.xany.type == ButtonPress)
2959 {
2960 XUngrabPointer (XtDisplay (keyboard), CurrentTime);
2961 if ((key = keyboard->keyboard.key_under_mouse))
2962 return key;
2963 XBell (XtDisplay (keyboard), 0);
2964 message (keyboard, "You must click on a key.");
2965 return 0;
2966 }
2967 else if (event.xany.type == ButtonRelease ||
2968 event.xany.type == KeyPress ||
2969 event.xany.type == KeyRelease)
2970 {
2971 XUngrabPointer (XtDisplay (keyboard), CurrentTime);
2972 XBell (XtDisplay (keyboard), 0);
2973 XPutBackEvent (XtDisplay (keyboard), &event);
2974 message (keyboard, "Aborted.");
2975 return 0;
2976 }
2977 else
2978 {
2979 if (event.xany.type == KeymapNotify)
2980 keyboard_handle_keymap_notify ((Widget) keyboard, 0, &event, 0);
2981 else if (event.xany.type == MappingNotify)
2982 keyboard_handle_mapping_notify ((Widget) keyboard, 0, &event, 0);
2983 XtDispatchEvent (&event);
2984 }
2985 }
2986 }
2987
2988
2989 /* What a mess the X keyboard model is... */
2990
2991 #include <X11/keysym.h>
2992
2993 static char *
2994 #ifdef __STDC__
index_to_name(int index)2995 index_to_name (int index)
2996 #else /* ! __STDC__ */
2997 index_to_name (index)
2998 int index;
2999 #endif /* ! __STDC__ */
3000 {
3001 return (index == ShiftMapIndex ? "Shift" :
3002 index == LockMapIndex ? "Lock" :
3003 index == ControlMapIndex ? "Control" :
3004 index == Mod1MapIndex ? "1" :
3005 index == Mod2MapIndex ? "2" :
3006 index == Mod3MapIndex ? "3" :
3007 index == Mod4MapIndex ? "4" :
3008 index == Mod5MapIndex ? "5" :
3009 "???");
3010 }
3011
3012 static char *
3013 #ifdef __STDC__
keysym_to_name(KeySym keysym)3014 keysym_to_name (KeySym keysym)
3015 #else /* ! __STDC__ */
3016 keysym_to_name (keysym)
3017 KeySym keysym;
3018 #endif /* ! __STDC__ */
3019 {
3020 char *n = XKeysymToString (keysym);
3021 if (! n) /* ought not happen, but does if XKeysymDB isn't installed right */
3022 {
3023 n = (char *) malloc (20); /* leaks! */
3024 sprintf (n, "Unknown-KeySym-0x%X", (int) keysym);
3025 }
3026 return n;
3027 }
3028
3029 static int
3030 #ifdef __STDC__
stop_the_insanity(KeyboardWidget widget,int keycode,KeySym * keysyms,int count,unsigned long modbits,XModifierKeymap * modmap)3031 stop_the_insanity (KeyboardWidget widget,
3032 int keycode,
3033 KeySym *keysyms,
3034 int count,
3035 unsigned long modbits,
3036 XModifierKeymap *modmap)
3037 #else /* ! __STDC__ */
3038 stop_the_insanity (widget, keycode, keysyms, count, modbits, modmap)
3039 KeyboardWidget widget;
3040 int keycode;
3041 KeySym *keysyms;
3042 int count;
3043 unsigned long modbits;
3044 XModifierKeymap *modmap;
3045 #endif /* ! __STDC__ */
3046 {
3047 int i;
3048 KeySym type = 0; /* The canonical modifier keysym on this key */
3049 KeySym basic_keysym = 0; /* The non-canonical version */
3050 KeySym companion = 0; /* The "other" version of this key */
3051
3052 /* Check that the keysyms that are attached to this key are compatible:
3053 It is incorrect to put Control_[LR] and Meta_[LR] on the same key.
3054 */
3055 {
3056 KeySym conflict = 0;
3057 KeySym nonmod = 0;
3058 for (i = 0; i < count && !conflict; i++)
3059 switch ((int) keysyms [i])
3060 {
3061 #define check(k) \
3062 case k: \
3063 if (type && type != k) \
3064 conflict = keysyms [i]; \
3065 else \
3066 type = k, \
3067 basic_keysym = keysyms[i]; \
3068 break
3069 case XK_Meta_R: check (XK_Meta_L);
3070 case XK_Super_R: check (XK_Super_L);
3071 case XK_Hyper_R: check (XK_Hyper_L);
3072 case XK_Alt_R: check (XK_Alt_L);
3073 case XK_Control_R: check (XK_Control_L);
3074 case XK_Shift_R: check (XK_Shift_L);
3075 check (XK_Shift_Lock);
3076 check (XK_Caps_Lock);
3077 check (XK_Mode_switch);
3078 #undef check
3079 default:
3080 nonmod = keysyms [i];
3081 break;
3082 }
3083
3084 switch ((int) basic_keysym)
3085 {
3086 case XK_Meta_L: companion = XK_Meta_R; break;
3087 case XK_Super_L: companion = XK_Super_R; break;
3088 case XK_Hyper_L: companion = XK_Hyper_R; break;
3089 case XK_Alt_L: companion = XK_Alt_R; break;
3090 case XK_Control_L: companion = XK_Control_R; break;
3091 case XK_Shift_L: companion = XK_Shift_R; break;
3092 case XK_Meta_R: companion = XK_Meta_L; break;
3093 case XK_Super_R: companion = XK_Super_L; break;
3094 case XK_Hyper_R: companion = XK_Hyper_L; break;
3095 case XK_Alt_R: companion = XK_Alt_L; break;
3096 case XK_Control_R: companion = XK_Control_L; break;
3097 case XK_Shift_R: companion = XK_Shift_L; break;
3098 }
3099
3100 if (nonmod && type) /* all modifier syms and non-mod syms conflict. */
3101 {
3102 conflict = type;
3103 type = nonmod;
3104 }
3105 if (conflict)
3106 return (y_or_n_p_with_args (widget, "keysymConflictWarning",
3107 "ok", "cancel", 0,
3108 keysym_to_name (type),
3109 keysym_to_name (conflict),
3110 0, 0, 0, 0));
3111 }
3112
3113
3114 /* Check that the modifier bits are compatible with the keysyms:
3115 It is incorrect to put ModControl on a key with any keysym other
3116 than Control_L or Control_R.
3117 */
3118 {
3119 int losing = 0;
3120 int bad_index = 0;
3121 if (modbits & ControlMask && type != XK_Control_L)
3122 losing = 1, bad_index = ControlMapIndex;
3123 else if (modbits & ShiftMask && type != XK_Shift_L)
3124 losing = 1, bad_index = ShiftMapIndex;
3125 else if (modbits & LockMask && type != XK_Caps_Lock &&
3126 type != XK_Shift_Lock)
3127 losing = 1, bad_index = LockMapIndex;
3128
3129 if (losing)
3130 return (y_or_n_p_with_args (widget, "badModifiersWarning",
3131 "ok", "cancel", 0,
3132 index_to_name (bad_index),
3133 (bad_index == ShiftMapIndex ? "Shift_L" :
3134 bad_index == LockMapIndex ? "Caps_Lock" :
3135 bad_index == ControlMapIndex ? "Control_L" :
3136 "<<INTERNAL ERROR>>"),
3137 (bad_index == ShiftMapIndex ? "Shift_R" :
3138 bad_index == LockMapIndex ? "Shift_Lock" :
3139 bad_index == ControlMapIndex ? "Control_R" :
3140 "<<INTERNAL ERROR>>"),
3141 index_to_name (bad_index),
3142 0, 0));
3143 }
3144
3145 /* Do the opposite check - the previous code checked for the case of
3146 attaching ModControl to Meta_L, but this checks for attaching Mod1
3147 to Control_L. */
3148 if ((type == XK_Shift_L || type == XK_Control_L ||
3149 type == XK_Shift_Lock || type == XK_Caps_Lock) &&
3150 (modbits & (~ (ShiftMask | LockMask | ControlMask))))
3151 return (y_or_n_p_with_args (widget, "badModifiersWarning2",
3152 "ok", "cancel", 0,
3153 keysym_to_name (basic_keysym),
3154 (type == XK_Shift_L ? "Shift" :
3155 type == XK_Control_L ? "Control" :
3156 type == XK_Shift_Lock ? "Lock" :
3157 type == XK_Caps_Lock ? "Lock" :
3158 "<<INTERNAL ERROR>>"),
3159 (type == XK_Shift_L ? "Shift" :
3160 type == XK_Control_L ? "Control" :
3161 type == XK_Shift_Lock ? "Shift_Lock" :
3162 type == XK_Caps_Lock ? "Caps_Lock" :
3163 "<<INTERNAL ERROR>>"),
3164 0, 0, 0));
3165
3166 /* Check that the key is generating at most one modifier bit.
3167 The behavior of more than one modifier bit is undefined.
3168 If this is a modifier keysym, warn if it has no modifier bits
3169 at all (which has defined behavior, and may be what is desired,
3170 but which novices are likely to do by accident.)
3171 */
3172 {
3173 int bitcount = 0;
3174 int i;
3175 for (i = 0; i < 8; i++)
3176 if (modbits & (1<<i)) bitcount++;
3177 if (bitcount > 1)
3178 return (y_or_n_p (widget, "multipleModifiersWarning",
3179 "ok", "cancel", 0));
3180 else if (bitcount == 0 && type != 0)
3181 return (y_or_n_p_with_args (widget, "noModifiersWarning",
3182 "ok", "cancel", 0,
3183 keysym_to_name (type), 0, 0, 0, 0, 0));
3184 }
3185
3186
3187 /* Check that some other (incompatible) key is not generating the same
3188 modifiers as this key. */
3189 {
3190 Display *dpy = XtDisplay ((Widget) widget);
3191
3192 unsigned long conflict_code = 0;
3193 KeySym conflict_sym = 0;
3194 int conflict_bit = 0;
3195 int this_bit = 0;
3196
3197 int modifier_index, modifier_key;
3198 int mkpm = modmap->max_keypermod;
3199
3200 for (modifier_index = 0; modifier_index < 8; modifier_index++)
3201 /* Ignore modifier bits which this key does not generate. */
3202 if ((1 << modifier_index) & modbits)
3203 for (modifier_key = 0; modifier_key < mkpm; modifier_key++)
3204 {
3205 int column;
3206 KeySym last_sym = 0;
3207 for (column = 0; column < 4; column += 2)
3208 {
3209 KeyCode code2 = modmap->modifiermap [modifier_index * mkpm
3210 + modifier_key];
3211 KeySym sym = (code2
3212 ? XKeycodeToKeysym (dpy, code2, column)
3213 : 0);
3214 KeySym this = 0;
3215 if (!sym) continue;
3216 if (sym == last_sym) continue;
3217 last_sym = sym;
3218 switch ((int) sym)
3219 {
3220 case XK_Meta_R: this = XK_Meta_L; break;
3221 case XK_Super_R: this = XK_Super_R; break;
3222 case XK_Hyper_R: this = XK_Hyper_L; break;
3223 case XK_Alt_R: this = XK_Alt_L; break;
3224 case XK_Control_R: this = XK_Control_L; break;
3225 case XK_Shift_R: this = XK_Shift_L; break;
3226 default: this = sym; break;
3227 }
3228
3229 if (this != type && /* conflicting keysyms */
3230 /* but ignore conflicts with the previous version of
3231 this very key! */
3232 code2 != keycode)
3233 {
3234 conflict_code = code2;
3235 conflict_sym = sym;
3236 conflict_bit = modifier_index;
3237 goto DONE;
3238 }
3239 }
3240 }
3241 DONE:
3242 if (conflict_code)
3243 {
3244 KeyWidget kw = keycode_to_key (widget, conflict_code);
3245 return (y_or_n_p_with_args (widget, "modifiersConflictWarning",
3246 "ok", "cancel", 0,
3247 keysym_to_name (basic_keysym),
3248 index_to_name (conflict_bit),
3249 (char *) conflict_code,
3250 (kw ? kw->key.key_name : "???"),
3251 keysym_to_name (conflict_sym),
3252 0));
3253 }
3254
3255
3256 /* Check that the semantically equivalent keys do not generate
3257 different modifier bits than this one. */
3258
3259 conflict_sym = 0;
3260 conflict_bit = 0;
3261 conflict_code = 0;
3262
3263 for (modifier_index = 0; modifier_index < 8; modifier_index++)
3264 /* Ignore modifier bits which this key generates. */
3265 if ((1 << modifier_index) & modbits)
3266 this_bit = modifier_index;
3267 else if (conflict_code)
3268 ;
3269 else
3270 for (modifier_key = 0; modifier_key < mkpm; modifier_key++)
3271 {
3272 int column;
3273 for (column = 0; column < 4; column += 2)
3274 {
3275 KeyCode code2 = modmap->modifiermap [modifier_index * mkpm
3276 + modifier_key];
3277 KeySym sym = (code2
3278 ? XKeycodeToKeysym (dpy, code2, column)
3279 : 0);
3280 if (sym &&
3281 !conflict_code &&
3282 (sym == basic_keysym || sym == companion) &&
3283 code2 != keycode)
3284 {
3285 conflict_code = code2;
3286 conflict_sym = sym;
3287 conflict_bit = modifier_index;
3288 /* keep going to find this_bit */
3289 break;
3290 }
3291 }
3292 }
3293
3294 if (conflict_code)
3295 {
3296 KeyWidget kw = keycode_to_key (widget, conflict_code);
3297 return (y_or_n_p_with_args (widget, "modifiersConflictWarning2",
3298 "ok", "cancel", 0,
3299 keysym_to_name (basic_keysym),
3300 index_to_name (this_bit),
3301 (char *) conflict_code,
3302 (kw ? kw->key.key_name : "???"),
3303 keysym_to_name (conflict_sym),
3304 index_to_name (conflict_bit)
3305 ));
3306 }
3307 }
3308
3309 /* Should we also issue a message along the lines of
3310
3311 This key is not normally a `chording' key (that is, a key that is
3312 held down to modify some other keypress.) It is unlikely that
3313 attaching a modifier to it will do anything sensible. If you want
3314 this to be a {Control,Shift,Lock,Meta} key, change its keysym to
3315 ***_L or ***_R.
3316
3317 That wouldn't be appropriate for the default layout of the OpenWound
3318 keyboard, which attaches modifiers to random function keys (I imagine
3319 this has something to do with drag-and-drop, but I don't know how it
3320 works.)
3321
3322 Actually maybe a different message would be appropriate for Multi_key,
3323 since people sometimes misinterpret the description of that key as being
3324 a modifier key, when in fact it's a prefix key and shouldn't have any
3325 modifier bits on it.
3326
3327 */
3328
3329 return 0;
3330 }
3331