1 /* xkeycaps, Copyright (c) 1991, 1992, 1993, 1996
2 * 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 #include <stdio.h>
14 #include "KbdWidgetP.h"
15 #include "KeyWidgetP.h"
16 #include "xkeycaps.h"
17
18 static void highlight_key P((KeyWidget widget));
19 static void dehighlight_key P((KeyWidget widget));
20 static void mouse_highlight_key P((KeyWidget widget));
21 static void mouse_dehighlight_key P((KeyWidget widget));
22 static void simulate_key_event P((KeyWidget widget, int down_p));
23
24
25
26 /* The goal of the mouse-tracking code in the following functions is for the
27 mouse with a button down to be just like your finger on the keyboard: so
28 long as a button is down, the key under it is depressed. If the mouse
29 moves to another key without the button going up first, the previous key
30 is released and the new key is depressed.
31
32 When a ButtonDown event comes in, the server gives you an implicit grab
33 of the mouse so that you will get the corresponding ButtonUp event no
34 matter what happens to focus or mouse-position in the meantime. This
35 is good, and totally necessary to our purposes. But, we want to be able
36 to track the mouse while the button is down. Initially, I did this by
37 selecting EnterNotify/LeaveNotify events on the child windows, but those
38 aren't generated while the parent window has a grab. So instead, the
39 parent window gets PointerMotion events, and looks at the "child" window
40 that the mouse is over to notice the crossings.
41
42 This loses slightly in that if you click down on the A key and move
43 quickly over to the L key, we won't necessarily notice that *all* of the
44 intervening keys went down; only the ones that we happened to get motion
45 events for. Others down/up pairs may be compressed out of existence.
46 */
47
48
49 static KeyWidget
50 #ifdef __STDC__
parse_key_action_args(char * name,XEvent * event,char ** argv,int argc,KeyboardWidget widget,int * mouse_p_ret)51 parse_key_action_args (char *name, XEvent *event, char **argv, int argc,
52 KeyboardWidget widget, int *mouse_p_ret)
53 #else /* ! __STDC__ */
54 parse_key_action_args (name, event, argv, argc, widget, mouse_p_ret)
55 char *name;
56 XEvent *event;
57 char **argv;
58 int argc;
59 KeyboardWidget widget;
60 int *mouse_p_ret;
61 #endif /* ! __STDC__ */
62 {
63 KeyWidget key = 0;
64 int mouse_p = 0;
65 int mod_p = 0;
66 int track_p = 0;
67 int highlighted_p = 0;
68 char *key_desc = 0;
69 int orig_argc = argc;
70
71 for (; argc > 0; argc--)
72 {
73 if (string_equal (argv[argc-1], "ifmod"))
74 mod_p = 1;
75 else if (string_equal (argv[argc-1], "unlessmod"))
76 mod_p = -1;
77 else if (string_equal (argv[argc-1], "iftracking"))
78 track_p = 1;
79 else if (string_equal (argv[argc-1], "unlesstracking"))
80 track_p = -1;
81 else if (string_equal (argv[argc-1], "ifhighlighted"))
82 highlighted_p = 1;
83 else if (string_equal (argv[argc-1], "unlesshighlighted"))
84 highlighted_p = -1;
85 else if (key_desc)
86 fprintf (stderr, "%s: too many args (%d) passed to %s action\n",
87 progname, orig_argc, name);
88 else
89 key_desc = argv[argc-1];
90 }
91
92 if (key_desc && string_equal (key_desc, "mouse"))
93 key = widget->keyboard.key_under_mouse, mouse_p = 1;
94 else if (key_desc && string_equal (key_desc, "highlighted"))
95 key = widget->keyboard.mouse_highlighted_key, mouse_p = 1;
96 else if (key_desc && string_equal (key_desc, "displayed"))
97 key = widget->keyboard.documented_key, mouse_p = 1;
98 else if (key_desc)
99 fprintf (stderr, "%s: unrecognised arg to %s: %s\n", progname,
100 name, key_desc);
101 else if (event->xany.type == ButtonPress ||
102 event->xany.type == ButtonRelease ||
103 event->xany.type == MotionNotify)
104 key = widget->keyboard.key_under_mouse, mouse_p = 1;
105 else if (event->xany.type == KeyPress ||
106 event->xany.type == KeyRelease)
107 key = keycode_to_key (widget, event->xkey.keycode);
108 else
109 fprintf (stderr, "%s: %d isn't a key or button press or release in %s\n",
110 progname, event->xany.type, name);
111
112 if (mod_p != 0) {
113 if (!key) return 0;
114 if (mod_p == 1 && !key->key.modifier_bits) return 0;
115 if (mod_p == -1 && key->key.modifier_bits) return 0;
116 }
117
118 if (track_p == 1 && !widget->keyboard.tracking_key) return 0;
119 if (track_p == -1 && widget->keyboard.tracking_key) return 0;
120
121 if (highlighted_p == 1 && key != widget->keyboard.mouse_highlighted_key)
122 return 0;
123 if (highlighted_p == -1 && key == widget->keyboard.mouse_highlighted_key)
124 return 0;
125
126 if (mouse_p_ret) *mouse_p_ret = mouse_p;
127 return key;
128 }
129
130
131 void
132 #ifdef __STDC__
highlight_key_action(Widget ww,XEvent * event,String * argv,Cardinal * argc)133 highlight_key_action (Widget ww, XEvent *event, String *argv, Cardinal *argc)
134 #else /* ! __STDC__ */
135 highlight_key_action (ww, event, argv, argc)
136 Widget ww;
137 XEvent *event;
138 String *argv;
139 Cardinal *argc;
140 #endif /* ! __STDC__ */
141 {
142 KeyboardWidget widget = (KeyboardWidget) ww;
143 int mouse_p;
144 KeyWidget key = parse_key_action_args ("HighlightKey", event,
145 argv, *argc, widget, &mouse_p);
146 if (! key) return;
147 if (mouse_p)
148 mouse_highlight_key (key);
149 else
150 highlight_key (key);
151 }
152
153
154 void
155 #ifdef __STDC__
unhighlight_key_action(Widget ww,XEvent * event,String * argv,Cardinal * argc)156 unhighlight_key_action (Widget ww, XEvent *event, String *argv, Cardinal *argc)
157 #else /* ! __STDC__ */
158 unhighlight_key_action (ww, event, argv, argc)
159 Widget ww;
160 XEvent *event;
161 String *argv;
162 Cardinal *argc;
163 #endif /* ! __STDC__ */
164 {
165 KeyboardWidget widget = (KeyboardWidget) ww;
166 int mouse_p;
167 KeyWidget key = parse_key_action_args ("UnhighlightKey", event,
168 argv, *argc, widget, &mouse_p);
169 if (! key) return;
170 if (mouse_p)
171 mouse_dehighlight_key (key);
172 else
173 dehighlight_key (key);
174 }
175
176
177 void
178 #ifdef __STDC__
toggle_key_action(Widget ww,XEvent * event,String * argv,Cardinal * argc)179 toggle_key_action (Widget ww, XEvent *event, String *argv, Cardinal *argc)
180 #else /* ! __STDC__ */
181 toggle_key_action (ww, event, argv, argc)
182 Widget ww;
183 XEvent *event;
184 String *argv;
185 Cardinal *argc;
186 #endif /* ! __STDC__ */
187 {
188 KeyboardWidget widget = (KeyboardWidget) ww;
189 int mouse_p;
190 KeyWidget key = parse_key_action_args ("ToggleKey", event, argv, *argc,
191 widget, &mouse_p);
192 if (! key) return;
193 if (mouse_p)
194 {
195 if (key->key.mouse_highlighted)
196 mouse_dehighlight_key (key);
197 else
198 mouse_highlight_key (key);
199 }
200 else
201 {
202 if (key->key.key_highlighted)
203 dehighlight_key (key);
204 else
205 highlight_key (key);
206 }
207 }
208
209
210 void
211 #ifdef __STDC__
simulate_KeyPress_action(Widget ww,XEvent * event,String * argv,Cardinal * argc)212 simulate_KeyPress_action (Widget ww, XEvent *event,
213 String *argv, Cardinal *argc)
214 #else /* ! __STDC__ */
215 simulate_KeyPress_action (ww, event, argv, argc)
216 Widget ww;
217 XEvent *event;
218 String *argv;
219 Cardinal *argc;
220 #endif /* ! __STDC__ */
221 {
222 KeyboardWidget widget = (KeyboardWidget) ww;
223 KeyWidget key = parse_key_action_args ("SimulateKeyPress", event, argv,
224 *argc, widget, 0);
225 if (key) simulate_key_event (key, 1);
226 }
227
228
229 void
230 #ifdef __STDC__
simulate_KeyRelease_action(Widget ww,XEvent * event,String * argv,Cardinal * argc)231 simulate_KeyRelease_action (Widget ww, XEvent *event,
232 String *argv, Cardinal *argc)
233 #else /* ! __STDC__ */
234 simulate_KeyRelease_action (ww, event, argv, argc)
235 Widget ww;
236 XEvent *event;
237 String *argv;
238 Cardinal *argc;
239 #endif /* ! __STDC__ */
240 {
241 KeyboardWidget widget = (KeyboardWidget) ww;
242 KeyWidget key = parse_key_action_args ("SimulateKeyRelease", event,
243 argv, *argc, widget, 0);
244 if (key) simulate_key_event (key, 0);
245 }
246
247
248 void
249 #ifdef __STDC__
describe_key_action(Widget ww,XEvent * event,String * argv,Cardinal * argc)250 describe_key_action (Widget ww, XEvent *event, String *argv, Cardinal *argc)
251 #else /* ! __STDC__ */
252 describe_key_action (ww, event, argv, argc)
253 Widget ww;
254 XEvent *event;
255 String *argv;
256 Cardinal *argc;
257 #endif /* ! __STDC__ */
258 {
259 KeyboardWidget widget = (KeyboardWidget) ww;
260 KeyWidget key = parse_key_action_args ("DescribeKey", event,
261 argv, *argc, widget, 0);
262 if (! key) return;
263
264 /* If the event invoking this is a KeyPress or KeyRelease, and the
265 key in question is a modifier key, don't do the optimization of
266 not redisplaying because we're already displaying that key. This
267 is so that the "DescribeKey(displayed)" action can be bound to
268 KeyDown and KeyUp, and will change the display when modifier keys
269 are pressed and released.
270 */
271 if ((event->xany.type == KeyPress || event->xany.type == KeyRelease)
272 && (widget->keyboard.modifier_vector [event->xkey.keycode / 8]
273 & (1 << (event->xkey.keycode % 8))))
274 widget->keyboard.documented_key = 0;
275
276 if (key != widget->keyboard.documented_key)
277 {
278 describe_key (key);
279 widget->keyboard.documented_key = key;
280 }
281 }
282
283
284 void
285 #ifdef __STDC__
track_key_action(Widget ww,XEvent * event,String * argv,Cardinal * argc)286 track_key_action (Widget ww, XEvent *event, String *argv, Cardinal *argc)
287 #else /* ! __STDC__ */
288 track_key_action (ww, event, argv, argc)
289 Widget ww;
290 XEvent *event;
291 String *argv;
292 Cardinal *argc;
293 #endif /* ! __STDC__ */
294 {
295 KeyboardWidget widget = (KeyboardWidget) ww;
296 KeyWidget key = parse_key_action_args ("TrackKey", event,
297 argv, *argc, widget, 0);
298 if (!key) return;
299 if (event->xany.type != ButtonPress && event->xany.type != ButtonRelease)
300 {
301 fprintf (stderr, "%s: TrackKey action invoked on a non-button event\n",
302 progname);
303 return;
304 }
305 widget->keyboard.tracking_key |= (1 << (event->xbutton.button - 1));
306 }
307
308 void
309 #ifdef __STDC__
untrack_key_action(Widget ww,XEvent * event,String * argv,Cardinal * argc)310 untrack_key_action (Widget ww, XEvent *event, String *argv, Cardinal *argc)
311 #else /* ! __STDC__ */
312 untrack_key_action (ww, event, argv, argc)
313 Widget ww;
314 XEvent *event;
315 String *argv;
316 Cardinal *argc;
317 #endif /* ! __STDC__ */
318 {
319 KeyboardWidget widget = (KeyboardWidget) ww;
320 parse_key_action_args ("UntrackKey", event, argv, *argc, widget, 0);
321 if (event->xany.type != ButtonPress && event->xany.type != ButtonRelease)
322 {
323 fprintf (stderr,
324 "%s: UntrackKey action invoked on a non-button event\n",
325 progname);
326 return;
327 }
328 /* widget->keyboard.tracking_key &= ~(1 << (event->xbutton.button - 1)); */
329 widget->keyboard.tracking_key = 0;
330 }
331
332
333 void
334 #ifdef __STDC__
key_menu_pre_popup_hook(Widget menu,XtPointer client_data,XtPointer call_data)335 key_menu_pre_popup_hook (Widget menu, XtPointer client_data,
336 XtPointer call_data)
337 #else /* ! __STDC__ */
338 key_menu_pre_popup_hook (menu, client_data, call_data)
339 Widget menu;
340 XtPointer client_data, call_data;
341 #endif /* ! __STDC__ */
342 {
343 KeyboardWidget widget = (KeyboardWidget) client_data;
344 KeyWidget key = widget->keyboard.key_under_mouse;
345 Arg av[10];
346 int ac = 0;
347 char buf1 [255]; /* so that the "!=" test in SimpleMenu succeeds... */
348 char buf2 [255];
349 static int toggle = 0;
350 char *b = (toggle ? buf1 : buf2);
351 message (widget, ""); /* clear the message area */
352 if (key)
353 {
354 toggle = !toggle;
355 sprintf (b, " Key %s (0x%02X) ", key->key.key_name,
356 key->key.keycode);
357 XtSetArg (av[ac], XtNlabel, b); ac++;
358 }
359 else
360 XtSetArg (av[ac], XtNlabel, "-- No Key --"), ac++;
361 XtSetValues (menu, av, ac);
362 sensitize_menu (widget, menu, (key ? True : False));
363 }
364
365
366
367 /* This is called before every action is invoked. It does two things:
368 it keeps the variable key_under_mouse up to date, and, if in TrackKey
369 mode, it simulates ButtonPress and ButtonRelease events when the mouse
370 moves from one key to another.
371 */
372
373 void
374 #ifdef __STDC__
keyboard_track_motion_hook(Widget action_widget,XtPointer client_data,String action_name,XEvent * event,String * ac,Cardinal * av)375 keyboard_track_motion_hook (Widget action_widget, XtPointer client_data,
376 String action_name, XEvent *event,
377 String *ac, Cardinal *av)
378 #else /* ! __STDC__ */
379 keyboard_track_motion_hook (action_widget, client_data,
380 action_name, event, ac, av)
381 Widget action_widget;
382 XtPointer client_data;
383 String action_name;
384 XEvent *event;
385 String *ac;
386 Cardinal *av;
387 #endif /* ! __STDC__ */
388 {
389 if (action_widget != (Widget) client_data) /* not the KeyboardWidget */
390 return;
391 if (event->xany.type != MotionNotify)
392 return;
393 {
394 KeyboardWidget widget = (KeyboardWidget) action_widget;
395 Display *dpy = XtDisplay (widget);
396 KeyWidget last_key_under_mouse = widget->keyboard.key_under_mouse;
397 Window root, child;
398 int root_x, root_y, x, y;
399 unsigned int mask;
400
401 /* This call to XQueryPointer is just to tell the server that it's
402 ok to start sending motion events again. When MotionHintMask
403 is used, we only get one MotionNotify event until something
404 interesting happens again.
405 */
406 XQueryPointer (dpy, XtWindow (widget), &root, &child,
407 &root_x, &root_y, &x, &y, &mask);
408
409 widget->keyboard.key_under_mouse = window_to_key (dpy, child);
410
411 if (widget->keyboard.tracking_key &&
412 widget->keyboard.key_under_mouse
413 && widget->keyboard.key_under_mouse != last_key_under_mouse
414 && !widget->keyboard.key_under_mouse->key.modifier_bits)
415 /* If we're in tracking-mode and the mouse has entered a key that it
416 wasn't within before, then simulate a ButtonUp event on the key
417 the mouse was last over, and then simulate a ButtonDown event on
418 the key the mouse is over now. But don't do that if the key the
419 mouse is over now is a modifier key, because that breaks the
420 "ifmod" arguments to actions.
421
422 We simulate these events so that the correct sets of actions get
423 invoked. Remember that the user may have changed the actions.
424 */
425 {
426 XEvent sim_event;
427
428 /* Put back a ButtonDown event for the current key first.
429 */
430 sim_event.xany.type = ButtonPress;
431 sim_event.xbutton.send_event = 1;
432 sim_event.xbutton.display = dpy;
433 sim_event.xbutton.window = XtWindow (widget); /* the KeyboardWidget */
434 sim_event.xbutton.root = event->xmotion.root;
435 sim_event.xbutton.subwindow =
436 (widget->keyboard.key_under_mouse
437 ? XtWindow (widget->keyboard.key_under_mouse)
438 : 0);
439 sim_event.xbutton.time = event->xmotion.time;
440 sim_event.xbutton.x = event->xmotion.x;
441 sim_event.xbutton.y = event->xmotion.y;
442 sim_event.xbutton.x_root = event->xmotion.x_root;
443 sim_event.xbutton.y_root = event->xmotion.y_root;
444 sim_event.xbutton.state = event->xmotion.state;
445 sim_event.xbutton.button = widget->keyboard.tracking_key;
446 sim_event.xbutton.same_screen = 1;
447 XPutBackEvent (dpy, &sim_event);
448
449 /* Now put back a ButtonUp event for the previous key.
450 We do it in this order because we're pushing on the front.
451 */
452 sim_event.xany.type = ButtonRelease;
453 sim_event.xbutton.subwindow =
454 (last_key_under_mouse ? XtWindow (last_key_under_mouse) : 0);
455 sim_event.xbutton.x = (last_key_under_mouse
456 ? last_key_under_mouse->core.x : 0);
457 sim_event.xbutton.y = (last_key_under_mouse
458 ? last_key_under_mouse->core.y : 0);
459 sim_event.xbutton.x_root = -1; /* This is hard, blow it off. */
460 sim_event.xbutton.y_root = -1;
461 XPutBackEvent (dpy, &sim_event);
462 }
463 }
464 }
465
466
467
468 static unsigned long simulated_modifier_state = 0;
469 static unsigned long real_modifier_state = 0;
470
471
472 #define key_highlighted_p(KEY) \
473 (((KEY)->key.mouse_highlighted > 0) || ((KEY)->key.key_highlighted > 0))
474
475 static void
476 #ifdef __STDC__
mouse_highlight_key(KeyWidget widget)477 mouse_highlight_key (KeyWidget widget)
478 #else /* ! __STDC__ */
479 mouse_highlight_key (widget)
480 KeyWidget widget;
481 #endif /* ! __STDC__ */
482 {
483 KeyboardWidget keyboard = (KeyboardWidget) widget->core.parent;
484 if (!key_highlighted_p (widget)) {
485 KeyHighlight (widget);
486 #if 0
487 printf (" simulated: 0x%02x | 0x%02x = 0x%02x\n",
488 simulated_modifier_state, widget->key.modifier_bits,
489 simulated_modifier_state | widget->key.modifier_bits);
490 #endif
491 simulated_modifier_state |= widget->key.modifier_bits;
492 widget->key.mouse_highlighted++;
493 keyboard->keyboard.mouse_highlighted_key = widget;
494 }
495 }
496
497
498 static void
499 #ifdef __STDC__
mouse_dehighlight_key(KeyWidget widget)500 mouse_dehighlight_key (KeyWidget widget)
501 #else /* ! __STDC__ */
502 mouse_dehighlight_key (widget)
503 KeyWidget widget;
504 #endif /* ! __STDC__ */
505 {
506 KeyboardWidget keyboard = (KeyboardWidget) widget->core.parent;
507
508 widget->key.mouse_highlighted--;
509 if (key_highlighted_p (widget)) return;
510 if (widget->key.mouse_highlighted < 0)
511 {
512 printf ("%s: ERROR: more ButtonUps than ButtonDowns on \"%s\"\n",
513 progname, widget->key.key_name);
514 widget->key.mouse_highlighted = 0;
515 }
516 KeyDehighlight (widget);
517
518 keyboard->keyboard.mouse_highlighted_key = 0;
519 #if 0
520 printf (" simulated: 0x%02x & ~0x%02x = 0x%02x\n",
521 simulated_modifier_state, widget->key.modifier_bits,
522 simulated_modifier_state & ~widget->key.modifier_bits);
523 #endif
524 simulated_modifier_state &= ~widget->key.modifier_bits;
525 }
526
527
528 static void
529 #ifdef __STDC__
highlight_key(KeyWidget widget)530 highlight_key (KeyWidget widget)
531 #else /* ! __STDC__ */
532 highlight_key (widget)
533 KeyWidget widget;
534 #endif /* ! __STDC__ */
535 {
536 KeyboardWidget keyboard = (KeyboardWidget) widget->core.parent;
537
538 /* printf ("%s: KeyPress %s\n", progname, widget->key.key_name);*/
539
540 if (!key_highlighted_p (widget)) {
541 KeyHighlight (widget);
542 #if 0
543 printf (" real : 0x%02x | 0x%02x = 0x%02x\n",
544 real_modifier_state, widget->key.modifier_bits,
545 real_modifier_state | widget->key.modifier_bits);
546 #endif
547 real_modifier_state |= widget->key.modifier_bits;
548 }
549 if (widget->key.key_highlighted)
550 /* We really shouldn't ever see more than one KeyPress on a given keycode
551 without an intervening KeyRelease, but we can if the keyboard focus
552 moves away from our window between the KeyPress and KeyRelease. Cope
553 with this by not incrementing the key-press-count to >1. This could
554 also happen if two keys on the keyboard had the same keycode, which
555 would make for a terribly bogus keyboard.
556 */
557 printf ("%s: ERROR: more KeyPresses than KeyReleases on \"%s\"\n",
558 progname, widget->key.key_name);
559 else
560 widget->key.key_highlighted++;
561
562 keyboard->keyboard.key_state_vector [widget->key.keycode / 8]
563 |= (1 << (widget->key.keycode % 8));
564 }
565
566 static void
567 #ifdef __STDC__
dehighlight_key(KeyWidget widget)568 dehighlight_key (KeyWidget widget)
569 #else /* ! __STDC__ */
570 dehighlight_key (widget)
571 KeyWidget widget;
572 #endif /* ! __STDC__ */
573 {
574 KeyboardWidget keyboard = (KeyboardWidget) widget->core.parent;
575 widget->key.key_highlighted--;
576
577 /* printf ("%s: KeyRelease %s\n", progname, widget->key.key_name); */
578
579 keyboard->keyboard.key_state_vector [widget->key.keycode / 8] &=
580 ~(1 << (widget->key.keycode % 8));
581
582 if (widget->key.key_highlighted < 0)
583 {
584 printf ("%s: ERROR: more KeyReleases than KeyPresses on \"%s\"\n",
585 progname, widget->key.key_name);
586 widget->key.key_highlighted = 0;
587 }
588 if (key_highlighted_p (widget)) return;
589
590 KeyDehighlight (widget);
591 #if 0
592 printf (" real : 0x%02x & ~0x%02x = 0x%02x\n",
593 real_modifier_state, widget->key.modifier_bits,
594 real_modifier_state & ~widget->key.modifier_bits);
595 #endif
596 real_modifier_state &= ~widget->key.modifier_bits;
597 }
598
599
600
601 void
602 #ifdef __STDC__
key_to_event(KeyWidget key,XEvent * event,int down_p)603 key_to_event (KeyWidget key, XEvent *event, int down_p)
604 #else /* ! __STDC__ */
605 key_to_event (key, event, down_p)
606 KeyWidget key;
607 XEvent *event;
608 int down_p;
609 #endif /* ! __STDC__ */
610 {
611 event->xkey.type = down_p ? KeyPress : KeyRelease;
612 event->xkey.display = XtDisplay (key);
613 event->xkey.time = CurrentTime;
614 event->xkey.x = event->xkey.y = 0;
615 event->xkey.x_root = event->xkey.y_root = 0;
616 event->xkey.state = (simulated_modifier_state | real_modifier_state);
617 event->xkey.keycode = key->key.keycode;
618 }
619
620
621 static void
622 #ifdef __STDC__
simulate_key_event(KeyWidget widget,int down_p)623 simulate_key_event (KeyWidget widget, int down_p)
624 #else /* ! __STDC__ */
625 simulate_key_event (widget, down_p)
626 KeyWidget widget;
627 int down_p;
628 #endif /* ! __STDC__ */
629 {
630 KeyboardWidget keyboard = (KeyboardWidget) widget->core.parent;
631 XEvent event;
632 Window window;
633 int revert_to;
634 if (! widget->key.keycode) return;
635 XGetInputFocus (XtDisplay (widget), &window, &revert_to);
636
637 /* If this widget (or any parent of it) has the keyboard focus, then send
638 the events to the window the user has picked.
639 */
640 if (window == PointerRoot)
641 window = keyboard->keyboard.target_window;
642 else
643 {
644 Widget parent;
645 for (parent = (Widget) widget; parent; parent = XtParent (parent))
646 if (XtWindow (parent) == window)
647 {
648 window = keyboard->keyboard.target_window;
649 break;
650 }
651 }
652 if (!window) return;
653 key_to_event (widget, &event, down_p);
654 event.xkey.window = window;
655 #ifdef HAVE_XTRAP
656 if (keyboard->keyboard.trap_data)
657 xkeycaps_xtrap_simulate_event (keyboard, &event);
658 else
659 #endif /* HAVE_XTRAP */
660 if (! XSendEvent (XtDisplay (widget), window, True,
661 down_p ? KeyPressMask : KeyReleaseMask,
662 &event))
663 {
664 fprintf (stderr, "%s: Couldn't simulate a keypress: ", progname);
665 if (window == None) fprintf (stderr, "No focus window\n");
666 else
667 fprintf (stderr, "focus window doesn't accept XSendEvent input\n");
668 }
669 XSync (XtDisplay (widget), 0);
670 if (XSendEvent_BadWindow &&
671 keyboard->keyboard.target_window == XSendEvent_BadWindow)
672 {
673 char buf [255];
674 sprintf (buf,
675 "Window 0x%X seems to have gone away. Keyboard focus cleared.",
676 (int) XSendEvent_BadWindow);
677 message (keyboard, buf);
678 XBell (XtDisplay ((Widget) widget), 0);
679 XSendEvent_BadWindow = 0;
680 keyboard->keyboard.target_window = 0;
681 }
682 }
683
684
685 int mappingNotify_event_expected = 0;
686
687 static Bool
688 #ifdef __STDC__
mapping_event_p(Display * dpy,XEvent * event,char * closure)689 mapping_event_p (Display *dpy, XEvent *event, char *closure)
690 #else /* ! __STDC__ */
691 mapping_event_p (dpy, event, closure)
692 Display *dpy;
693 XEvent *event;
694 char *closure;
695 #endif /* ! __STDC__ */
696 {
697 if (event->xany.type == MappingNotify) *closure = 1;
698 return False;
699 }
700
701 void
702 #ifdef __STDC__
keyboard_handle_mapping_notify(Widget widget,XtPointer client_data,XEvent * event,Boolean * cont)703 keyboard_handle_mapping_notify (Widget widget, XtPointer client_data,
704 XEvent *event, Boolean *cont)
705 #else /* ! __STDC__ */
706 keyboard_handle_mapping_notify (widget, client_data, event, cont)
707 Widget widget;
708 XtPointer client_data;
709 XEvent *event;
710 Boolean *cont;
711 #endif /* ! __STDC__ */
712 {
713 char events_queued_p = 0;
714 XRefreshKeyboardMapping (&event->xmapping);
715 init_modifier_mapping ((KeyboardWidget) widget);
716 XSync (XtDisplay (widget), 0);
717 if (XCheckIfEvent (XtDisplay (widget), event,
718 mapping_event_p, &events_queued_p))
719 exit (-69); /* can't happen. */
720
721 if (!events_queued_p)
722 /* refresh, in case the documented key has been modified */
723 {
724 if (((KeyboardWidget) widget)->keyboard.documented_key)
725 describe_key (((KeyboardWidget) widget)->keyboard.documented_key);
726 if (! mappingNotify_event_expected)
727 message ((KeyboardWidget) widget,
728 "MappingNotify event received; keyboard state refreshed.");
729 else
730 mappingNotify_event_expected = 0;
731 }
732 }
733
734 void
735 #ifdef __STDC__
keyboard_handle_keymap_notify(Widget w,XtPointer client_data,XEvent * event,Boolean * cont)736 keyboard_handle_keymap_notify (Widget w, XtPointer client_data, XEvent *event,
737 Boolean *cont)
738 #else /* ! __STDC__ */
739 keyboard_handle_keymap_notify (w, client_data, event, cont)
740 Widget w;
741 XtPointer client_data;
742 XEvent *event;
743 Boolean *cont;
744 #endif /* ! __STDC__ */
745 {
746 /* To prevent getting out of sync with the real state of the
747 keyboard during those unfortunate moments when we don't have
748 the keyboard focus, we select KeymapNotify, which gives us
749 the same data as XQueryKeymap would, but sends it just after
750 any FocusIn or EnterNotify event would have been generated.
751 Unfortunately, this means that this event will be generated
752 every time the cursor move from inside of a key to the top-
753 level keyboard window (since a particular kind of EnterNotify
754 event would be generated there.) This shouldn't be too big
755 a deal: it's just another 40 or so bytes, and a call to bcmp.
756 */
757 KeyboardWidget widget = (KeyboardWidget) w;
758 int i, j;
759
760 #ifdef HAVE_XTRAP
761 if (((KeyboardWidget) widget)->keyboard.trap_data)
762 return; /* if we're in XTrap mode, this function is redundant */
763 #endif
764
765 if (widget->core.being_destroyed)
766 return;
767
768 if (! memcmp (event->xkeymap.key_vector,
769 ((KeyboardWidget) widget)->keyboard.key_state_vector,
770 32))
771 return; /* Nothing's changed, bug out. */
772
773 for (i = 0; i < widget->keyboard.nrows; i++)
774 for (j = 0; j < widget->keyboard.rows[i].nkeys; j++)
775 {
776 KeyWidget key = widget->keyboard.rows[i].keys[j];
777 int down = ((event->xkeymap.key_vector [key->key.keycode / 8])
778 & (1 << (key->key.keycode % 8)));
779 if (! key->key.keycode) continue;
780 if (down && !key->key.key_highlighted)
781 /* Down now, wasn't before */
782 highlight_key (key);
783 else if (!down && key->key.key_highlighted)
784 /* Not down now, was before */
785 dehighlight_key (key);
786 }
787 #if 0
788 /* This sometimes fails because the event contains random noise in the
789 bits which correspond to a keycode for which there is no physical key.
790 Presumably this is because X events are padded with uninitialized data.
791 */
792 if (bcmp (event->xkeymap.key_vector, kbd->key_state_vector, 32))
793 fprintf (stderr,
794 "%s: KeymapNotify handling is way broken...\n",
795 progname);
796 #endif
797 }
798
799
800
801
802 KeyWidget
803 #ifdef __STDC__
window_to_key(Display * dpy,Window window)804 window_to_key (Display *dpy, Window window)
805 #else /* ! __STDC__ */
806 window_to_key (dpy, window)
807 Display *dpy;
808 Window window;
809 #endif /* ! __STDC__ */
810 {
811 KeyWidget key = (KeyWidget) XtWindowToWidget (dpy, window);
812 if (! key) return 0;
813 if (! XtIsSubclass ((Widget) key, keyWidgetClass)) return 0;
814 return key;
815 }
816
817
818 KeyWidget
819 #ifdef __STDC__
keycode_to_key(KeyboardWidget keyboard,KeyCode code)820 keycode_to_key (KeyboardWidget keyboard, KeyCode code)
821 #else /* ! __STDC__ */
822 keycode_to_key (keyboard, code)
823 KeyboardWidget keyboard;
824 KeyCode code;
825 #endif /* ! __STDC__ */
826 {
827 int i, j;
828 if (! code) return 0;
829 for (i = 0; i < keyboard->keyboard.nrows; i++)
830 for (j = 0; j < keyboard->keyboard.rows[i].nkeys; j++)
831 if (keyboard->keyboard.rows[i].keys[j]->key.keycode == code)
832 return keyboard->keyboard.rows[i].keys[j];
833 return 0;
834 }
835
836
837 static void
838 #ifdef __STDC__
clear_modifier_flags(KeyboardWidget widget)839 clear_modifier_flags (KeyboardWidget widget)
840 #else /* ! __STDC__ */
841 clear_modifier_flags (widget)
842 KeyboardWidget widget;
843 #endif /* ! __STDC__ */
844 {
845 int i, j;
846 memset (widget->keyboard.modifier_vector, 0, 32);
847 for (i = 0; i < widget->keyboard.nrows; i++)
848 for (j = 0; j < widget->keyboard.rows[i].nkeys; j++)
849 if (widget->keyboard.rows[i].keys[j])
850 widget->keyboard.rows[i].keys[j]->key.modifier_bits = 0;
851 }
852
853
854 void
855 #ifdef __STDC__
init_modifier_mapping(KeyboardWidget widget)856 init_modifier_mapping (KeyboardWidget widget)
857 #else /* ! __STDC__ */
858 init_modifier_mapping (widget)
859 KeyboardWidget widget;
860 #endif /* ! __STDC__ */
861 {
862 Display *dpy = XtDisplay (widget);
863 XModifierKeymap *modifier_map;
864 int modifier_index, modifier_key, i, j;
865 XKeyboardState kbd_state;
866 /* XKeyboardControl kbd_control;*/
867 int mkpm;
868
869 clear_modifier_flags (widget);
870 modifier_map = XGetModifierMapping (dpy);
871 /* Look at the defined modifier keys, and annotate our key structures
872 with which modifier bits they set. This will be done each time the
873 user runs xmodmap as well.
874 */
875 mkpm = modifier_map->max_keypermod;
876 for (modifier_index = 0; modifier_index < 8; modifier_index++)
877 for (modifier_key = 0; modifier_key < mkpm; modifier_key++)
878 {
879 int index = modifier_index * mkpm + modifier_key;
880 int keycode = modifier_map->modifiermap [index];
881 KeyWidget key = keycode_to_key (widget, keycode);
882 if (! key) continue;
883 key->key.modifier_bits |= (1 << modifier_index);
884 widget->keyboard.modifier_vector [keycode / 8]
885 |= (1 << (keycode % 8));
886 }
887 XFreeModifiermap (modifier_map);
888
889 # if 0
890 kbd_control.auto_repeat_mode = 0;
891 XChangeKeyboardControl (dpy, KBAutoRepeatMode, &kbd_control);
892 # endif
893
894 XGetKeyboardControl (dpy, &kbd_state);
895 for (i = 0; i < widget->keyboard.nrows; i++)
896 for (j = 0; j < widget->keyboard.rows[i].nkeys; j++)
897 {
898 KeyWidget key = widget->keyboard.rows[i].keys[j];
899 if (key)
900 key->key.auto_repeat_p
901 = !!((kbd_state.auto_repeats [key->key.keycode / 8])
902 & (1 << (key->key.keycode % 8)));
903 }
904 }
905