1 #include <X11/keysym.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "xglk.h"
5 #include "xg_internal.h"
6 #include "xg_win_textgrid.h"
7 #include "xg_win_textbuf.h"
8
9 /* The first 256 commands are the standard character set.
10 The second 256 are special keyboard keys.
11 The third 256 are option-key combinations. */
12 #define NUMCOMMANDS (768)
13 #define NUMMACROS (256)
14 #define MACRO_MASK (0xff)
15
16 typedef struct keymap_struct {
17 cmdentry_t *keycmds[NUMCOMMANDS];
18 } keymap_t;
19
20 typedef struct binding_struct {
21 unsigned int key;
22 char *name;
23 } binding_t;
24
25 #define range_Printable (1)
26 #define range_Typable (2)
27
28 static char *macrolist[NUMMACROS];
29 static int modify_mode;
30
31 static keymap_t *global_map = NULL;
32 static keymap_t *msg_char_map = NULL;
33 static keymap_t *msg_line_map = NULL;
34 static keymap_t *win_textgrid_map = NULL;
35 static keymap_t *win_textgrid_char_map = NULL;
36 static keymap_t *win_textgrid_line_map = NULL;
37 static keymap_t *win_textbuffer_map = NULL;
38 static keymap_t *win_textbuffer_paging_map = NULL;
39 static keymap_t *win_textbuffer_char_map = NULL;
40 static keymap_t *win_textbuffer_line_map = NULL;
41
42 static char *xkey_get_key_name(int key);
43 static cmdentry_t *xkey_find_cmd_by_name(char *str);
44 static keymap_t *new_keymap(binding_t *bindlist);
45 static void keymap_add_multiple(keymap_t *map, int range, char *func);
46
47 static cmdentry_t mastertable[] = {
48 {xgc_insert, -1, 0, "insert-self"},
49 {xgc_getchar, -1, 0, "getchar-self"},
50 {xgc_enter, op_Enter, 0, "enter-line"},
51
52 {xgc_movecursor, op_ForeChar, 0, "forward-char"},
53 {xgc_movecursor, op_BackChar, 0, "backward-char"},
54 {xgc_movecursor, op_ForeWord, 0, "forward-word"},
55 {xgc_movecursor, op_BackWord, 0, "backward-word"},
56 {xgc_movecursor, op_ForeLine, 0, "forward-line"},
57 {xgc_movecursor, op_BackLine, 0, "backward-line"},
58 {xgc_movecursor, op_BeginLine, 0, "beginning-of-line"},
59 {xgc_movecursor, op_EndLine, 0, "end-of-line"},
60
61 {xgc_scroll, op_DownPage, 0, "scroll-down"},
62 {xgc_scroll, op_UpPage, 0, "scroll-up"},
63 {xgc_scroll, op_DownLine, 0, "scroll-down-line"},
64 {xgc_scroll, op_UpLine, 0, "scroll-up-line"},
65 {xgc_scroll, op_ToBottom, 0, "scroll-to-bottom"},
66 {xgc_scroll, op_ToTop, 0, "scroll-to-top"},
67
68 {xgc_delete, op_ForeChar, 0, "delete-next-char"},
69 {xgc_delete, op_BackChar, 0, "delete-char"},
70 {xgc_delete, op_ForeWord, 0, "delete-next-word"},
71 {xgc_delete, op_BackWord, 0, "delete-word"},
72
73 {xgc_cutbuf, op_Yank, 0, "yank-scrap"},
74 {xgc_cutbuf, op_YankReplace, 0, "yank-scrap-replace"},
75 {xgc_cutbuf, op_Copy, 0, "copy-region"},
76 {xgc_cutbuf, op_Kill, 0, "kill-line"},
77 {xgc_cutbuf, op_Wipe, 0, "kill-region"},
78 {xgc_cutbuf, op_Erase, 0, "erase-region"},
79 {xgc_cutbuf, op_Untype, 0, "kill-input"},
80
81 {xgc_history, op_BackLine, 0, "backward-history"},
82 {xgc_history, op_ForeLine, 0, "forward-history"},
83
84 {xgc_focus, op_ForeWin, 0, "focus-forward"},
85 {xgc_redraw, op_AllWindows, 0, "redraw-all-windows"},
86
87 {xgc_work_meta, op_Cancel, 1, "cancel"},
88 {xgc_work_meta, op_Meta, 0, "meta"},
89 {xgc_work_meta, op_ExplainKey, 0, "explain-key"},
90
91 {xgc_noop, -1, 0, "no-op"},
92
93 {NULL, 0, 0, NULL}
94 };
95
96 #define KEYSYM(ksym) (0x100 | ((ksym) & 0xff))
97 #define META(ksym) (0x200 | ((ksym) & 0xff))
98
99 static binding_t global_bindings[] = {
100
101 {'\007' /* ctrl-G */, "cancel"},
102 {META('\007') /* ctrl-G */, "cancel"},
103 {KEYSYM(XK_Escape), "meta"},
104 {KEYSYM(XK_Help), "explain-key"},
105 {META('x'), "explain-key"},
106
107 {KEYSYM(XK_Tab), "focus-forward"},
108 {'\014' /* ctrl-L */, "redraw-all-windows"},
109
110 {0, NULL}
111 };
112
113 static binding_t win_textbuffer_bindings[] = {
114
115 {'\001' /* ctrl-A */, "beginning-of-line"},
116 {'\005' /* ctrl-E */, "end-of-line"},
117 {'\002' /* ctrl-B */, "backward-char"},
118 {KEYSYM(XK_Left), "backward-char"},
119 {KEYSYM(XK_KP_Left), "backward-char"},
120 {'\006' /* ctrl-F */, "forward-char"},
121 {KEYSYM(XK_Right), "forward-char"},
122 {KEYSYM(XK_KP_Right), "forward-char"},
123 {META('f'), "forward-word"},
124 {META('b'), "backward-word"},
125
126 {'\026' /* ctrl-V */, "scroll-down"},
127 {KEYSYM(XK_Page_Down), "scroll-down"},
128 {KEYSYM(XK_KP_Page_Down), "scroll-down"},
129 {META('v'), "scroll-up"},
130 {KEYSYM(XK_Page_Up), "scroll-up"},
131 {KEYSYM(XK_KP_Page_Up), "scroll-up"},
132
133 {META('<'), "scroll-to-top"},
134 {META('>'), "scroll-to-bottom"},
135
136 {META('w'), "copy-region"},
137 {'\027' /* ctrl-W */, "copy-region"},
138
139 {0, NULL}
140 };
141
142 static binding_t win_textgrid_bindings[] = {
143
144 {'\001' /* ctrl-A */, "beginning-of-line"},
145 {'\005' /* ctrl-E */, "end-of-line"},
146 {'\002' /* ctrl-B */, "backward-char"},
147 {KEYSYM(XK_Left), "backward-char"},
148 {KEYSYM(XK_KP_Left), "backward-char"},
149 {'\006' /* ctrl-F */, "forward-char"},
150 {KEYSYM(XK_Right), "forward-char"},
151 {KEYSYM(XK_KP_Right), "forward-char"},
152 {META('f'), "forward-word"},
153 {META('b'), "backward-word"},
154
155 {META('w'), "copy-region"},
156 {'\027' /* ctrl-W */, "copy-region"},
157
158 {0, NULL}
159 };
160
161 static binding_t win_textbuffer_char_bindings[] = {
162 {0, NULL}
163 };
164
165 static binding_t win_textgrid_char_bindings[] = {
166 {0, NULL}
167 };
168
169 static binding_t msg_char_bindings[] = {
170 {0, NULL}
171 };
172
173 static binding_t win_textbuffer_line_bindings[] = {
174 {KEYSYM(XK_Down), "forward-history"},
175 {KEYSYM(XK_KP_Down), "forward-history"},
176 {'\016' /* ctrl-N */, "forward-history"},
177 {KEYSYM(XK_Up), "backward-history"},
178 {KEYSYM(XK_KP_Up), "backward-history"},
179 {'\020' /* ctrl-P */, "backward-history"},
180 {'\004' /* ctrl-D */, "delete-next-char"},
181 {KEYSYM(XK_Delete), "delete-char"},
182 {KEYSYM(XK_KP_Delete), "delete-char"},
183 {KEYSYM(XK_BackSpace), "delete-char"},
184 {'\177' /* delete */, "delete-char"},
185 {'\010' /* ctrl-H */, "delete-char"},
186 {'\n' /* newline */, "enter-line"},
187 {'\r' /* return */, "enter-line"},
188 {KEYSYM(XK_Return), "enter-line"},
189 {KEYSYM(XK_KP_Enter), "enter-line"},
190
191 {'\013' /* ctrl-K */, "kill-line"},
192 {'\025' /* ctrl-U */, "kill-input"},
193 {'\027' /* ctrl-W */, "kill-region"},
194 {'\031' /* ctrl-Y */, "yank-scrap"},
195
196 /*### macros */
197
198 {0, NULL}
199 };
200
201 static binding_t win_textgrid_line_bindings[] = {
202 {KEYSYM(XK_Down), "forward-history"},
203 {KEYSYM(XK_KP_Down), "forward-history"},
204 {'\016' /* ctrl-N */, "forward-history"},
205 {KEYSYM(XK_Up), "backward-history"},
206 {KEYSYM(XK_KP_Up), "backward-history"},
207 {'\020' /* ctrl-P */, "backward-history"},
208 {'\004' /* ctrl-D */, "delete-next-char"},
209 {KEYSYM(XK_Delete), "delete-char"},
210 {KEYSYM(XK_KP_Delete), "delete-char"},
211 {KEYSYM(XK_BackSpace), "delete-char"},
212 {'\177' /* delete */, "delete-char"},
213 {'\010' /* ctrl-H */, "delete-char"},
214 {'\n' /* newline */, "enter-line"},
215 {'\r' /* return */, "enter-line"},
216 {KEYSYM(XK_Return), "enter-line"},
217 {KEYSYM(XK_KP_Enter), "enter-line"},
218
219 {'\013' /* ctrl-K */, "kill-line"},
220 {'\025' /* ctrl-U */, "kill-input"},
221 {'\027' /* ctrl-W */, "kill-region"},
222 {'\031' /* ctrl-Y */, "yank-scrap"},
223
224 {0, NULL}
225 };
226
227 static binding_t msg_line_bindings[] = {
228 {'\001' /* ctrl-A */, "beginning-of-line"},
229 {'\005' /* ctrl-E */, "end-of-line"},
230 {'\002' /* ctrl-B */, "backward-char"},
231 {KEYSYM(XK_Left), "backward-char"},
232 {KEYSYM(XK_KP_Left), "backward-char"},
233 {'\006' /* ctrl-F */, "forward-char"},
234 {KEYSYM(XK_Right), "forward-char"},
235 {KEYSYM(XK_KP_Right), "forward-char"},
236 {META('f'), "forward-word"},
237 {META('b'), "backward-word"},
238
239 {'\004' /* ctrl-D */, "delete-next-char"},
240 {KEYSYM(XK_Delete), "delete-char"},
241 {KEYSYM(XK_BackSpace), "delete-char"},
242 {'\177' /* delete */, "delete-char"},
243 {'\010' /* ctrl-H */, "delete-char"},
244 {'\n' /* newline */, "enter-line"},
245 {'\r' /* return */, "enter-line"},
246 {KEYSYM(XK_Return), "enter-line"},
247 {KEYSYM(XK_KP_Enter), "enter-line"},
248
249 {0, NULL}
250 };
251
252 static binding_t win_textbuffer_paging_bindings[] = {
253 {'\n' /* newline */, "scroll-down"},
254 {'\r' /* return */, "scroll-down"},
255 {KEYSYM(XK_Return), "scroll-down"},
256 {KEYSYM(XK_KP_Enter), "scroll-down"},
257
258 {META('<'), "scroll-to-top"},
259 {META('>'), "scroll-to-bottom"},
260
261 {0, NULL}
262 };
263
init_xkey()264 int init_xkey()
265 {
266 int ix;
267
268 modify_mode = op_Cancel;
269
270 for (ix=0; ix<NUMMACROS; ix++) {
271 macrolist[ix] = NULL;
272 }
273
274 global_map = new_keymap(global_bindings);
275 if (!global_map)
276 return FALSE;
277
278 win_textbuffer_map = new_keymap(win_textbuffer_bindings);
279 win_textbuffer_paging_map = new_keymap(win_textbuffer_paging_bindings);
280 win_textbuffer_char_map = new_keymap(win_textbuffer_char_bindings);
281 win_textbuffer_line_map = new_keymap(win_textbuffer_line_bindings);
282 if (!win_textbuffer_map
283 || !win_textbuffer_paging_map
284 || !win_textbuffer_char_map
285 || !win_textbuffer_line_map)
286 return FALSE;
287 keymap_add_multiple(win_textbuffer_char_map, range_Typable, "getchar-self");
288 keymap_add_multiple(win_textbuffer_paging_map, range_Printable, "scroll-down");
289 keymap_add_multiple(win_textbuffer_line_map, range_Printable, "insert-self");
290
291 win_textgrid_map = new_keymap(win_textgrid_bindings);
292 win_textgrid_char_map = new_keymap(win_textgrid_char_bindings);
293 win_textgrid_line_map = new_keymap(win_textgrid_line_bindings);
294 if (!win_textgrid_map
295 || !win_textgrid_char_map
296 || !win_textgrid_line_map)
297 return FALSE;
298 keymap_add_multiple(win_textgrid_char_map, range_Typable, "getchar-self");
299 keymap_add_multiple(win_textgrid_line_map, range_Printable, "insert-self");
300
301 msg_char_map = new_keymap(msg_char_bindings);
302 msg_line_map = new_keymap(msg_line_bindings);
303 if (!msg_char_map || !msg_line_map)
304 return FALSE;
305 keymap_add_multiple(msg_char_map, range_Typable, "getchar-self");
306 keymap_add_multiple(msg_line_map, range_Printable, "insert-self");
307
308 return TRUE;
309 }
310
xkey_get_macro(int key)311 char *xkey_get_macro(int key)
312 {
313 key &= MACRO_MASK;
314 return macrolist[key];
315 }
316
new_keymap(binding_t * bindlist)317 static keymap_t *new_keymap(binding_t *bindlist)
318 {
319 keymap_t *res;
320 int ix;
321 int keynum;
322 cmdentry_t *cmd;
323 binding_t *bx;
324 char *cx;
325
326 res = (keymap_t *)malloc(sizeof(keymap_t));
327 if (!res)
328 return NULL;
329
330 for (ix=0; ix<NUMCOMMANDS; ix++) {
331 res->keycmds[ix] = NULL;
332 }
333
334 for (bx=bindlist; bx->name; bx++) {
335 ix = (bx->key);
336 cmd = xkey_find_cmd_by_name(bx->name);
337 if (cmd) {
338 keynum = ix;
339 res->keycmds[keynum] = cmd;
340 }
341 }
342
343 return res;
344 }
345
keymap_add_multiple(keymap_t * map,int range,char * func)346 static void keymap_add_multiple(keymap_t *map, int range, char *func)
347 {
348 cmdentry_t *cmd;
349 int ix;
350
351 cmd = xkey_find_cmd_by_name(func);
352
353 if (!cmd) {
354 return;
355 }
356
357 /* ### both of these are non-ideal */
358
359 switch (range) {
360 case range_Printable:
361 for (ix = 32; ix <= 255; ix++) {
362 if (ix >= 127 && ix < 160)
363 continue;
364 if (!map->keycmds[ix])
365 map->keycmds[ix] = cmd;
366 }
367 break;
368 case range_Typable:
369 for (ix = 0; ix <= 511; ix++) {
370 if (ix == KEYSYM(XK_Tab))
371 continue;
372 if (!map->keycmds[ix])
373 map->keycmds[ix] = cmd;
374 }
375 break;
376 }
377 }
378
xkey_set_macro(int key,char * str,int chown)379 void xkey_set_macro(int key, char *str, int chown)
380 {
381 char *cx;
382
383 key &= MACRO_MASK;
384
385 if (macrolist[key]) {
386 free(macrolist[key]);
387 macrolist[key] = NULL;
388 }
389
390 if (str) {
391 if (chown) {
392 macrolist[key] = str;
393 }
394 else {
395 cx = (char *)malloc(strlen(str)+1);
396 strcpy(cx, str);
397 macrolist[key] = cx;
398 }
399 }
400 }
401
402 #define TEST_KEY_MAP(mp, ky, rs) \
403 if ((mp) && ((rs) = (mp)->keycmds[ky])) \
404 return (rs);
405
406 /* check keymap for a single window -- or nonwindow. */
xkey_parse_key(int key,window_t * win)407 static cmdentry_t *xkey_parse_key(int key, window_t *win)
408 {
409 cmdentry_t *res;
410
411 if (!win) {
412 TEST_KEY_MAP(global_map, key, res);
413 if (xmsg_msgmode) {
414 if (xmsg_msgmode == xmsg_mode_Char) {
415 TEST_KEY_MAP(msg_char_map, key, res);
416 }
417 else if (xmsg_msgmode == xmsg_mode_Line) {
418 TEST_KEY_MAP(msg_line_map, key, res);
419 }
420 }
421 }
422 else {
423 switch (win->type) {
424 case wintype_TextGrid:
425 if (!xmsg_msgmode) {
426 if (win->char_request) {
427 TEST_KEY_MAP(win_textgrid_char_map, key, res);
428 }
429 else if (win->line_request) {
430 TEST_KEY_MAP(win_textgrid_line_map, key, res);
431 }
432 }
433 TEST_KEY_MAP(win_textgrid_map, key, res);
434 break;
435 case wintype_TextBuffer:
436 if (win_textbuffer_is_paging(win)) {
437 TEST_KEY_MAP(win_textbuffer_paging_map, key, res);
438 }
439 if (!xmsg_msgmode) {
440 if (win->char_request) {
441 TEST_KEY_MAP(win_textbuffer_char_map, key, res);
442 }
443 else if (win->line_request) {
444 TEST_KEY_MAP(win_textbuffer_line_map, key, res);
445 }
446 }
447 TEST_KEY_MAP(win_textbuffer_map, key, res);
448 break;
449 default:
450 break;
451 }
452 }
453
454 return NULL;
455 }
456
xkey_get_key_name(int key)457 static char *xkey_get_key_name(int key)
458 {
459 static char buf[32];
460 KeySym ksym;
461 char *prefix, *name;
462
463 if ((key & 0xff00) == 0x100) {
464 key &= 0xff;
465 ksym = (KeySym)((XK_Home & 0xff00) | key);
466 name = XKeysymToString(ksym);
467 if (!name)
468 name = "Unknown key";
469 strcpy(buf, name);
470 return buf;
471 }
472
473 if (key & 0xff00) {
474 key &= 0xff;
475 prefix = "meta-";
476 }
477 else {
478 prefix = "";
479 }
480
481 if (key < 32) {
482 sprintf(buf, "%sctrl-%c", prefix, key+'A'-1);
483 }
484 else {
485 sprintf(buf, "%s%c", prefix, key);
486 }
487
488 return buf;
489 }
490
xkey_find_cmd_by_name(char * str)491 static cmdentry_t *xkey_find_cmd_by_name(char *str)
492 {
493 cmdentry_t *retval;
494
495 for (retval = mastertable; retval->func; retval++) {
496 if (!strcmp(str, retval->name))
497 return retval;
498 }
499 return NULL;
500 }
501
xkey_perform_key(int key,unsigned int state)502 void xkey_perform_key(int key, unsigned int state)
503 {
504 cmdentry_t *command = NULL;
505 window_t *cmdwin = NULL;
506 int op;
507
508 if (modify_mode == op_Meta) {
509 modify_mode = op_Cancel;
510 if ((key & 0xFF00) == 0) {
511 key |= 0x200;
512 }
513 }
514
515 if (gli_focuswin) {
516 command = xkey_parse_key(key, gli_focuswin);
517 cmdwin = gli_focuswin;
518 }
519 if (!command) {
520 command = xkey_parse_key(key, NULL);
521 cmdwin = NULL;
522 }
523
524 if (modify_mode == op_ExplainKey) {
525 char buf[128];
526 char *cx, *cxmac;
527 modify_mode = op_Cancel;
528 cx = xkey_get_key_name(key);
529 cxmac = xkey_get_macro(key);
530 if (!command)
531 sprintf(buf, "Key <%s> is not bound", cx);
532 else if (!cxmac)
533 sprintf(buf, "Key <%s>: %s", cx, command->name);
534 else {
535 if (strlen(cxmac) < sizeof(buf) - 64)
536 sprintf(buf, "Key <%s>: %s \"%s\"", cx, command->name, cxmac);
537 else {
538 sprintf(buf, "Key <%s>: %s \"", cx, command->name);
539 strncat(buf, cxmac, sizeof(buf) - 64);
540 strcat(buf, "...\"");
541 }
542 }
543 xmsg_set_message(buf, FALSE);
544 return;
545 }
546
547 if (!command && gli_rootwin) {
548 /* look for a focuswin which knows this key */
549 window_t *win = gli_focuswin;
550 cmdentry_t *altcommand = NULL;
551 do {
552 win = gli_window_fixiterate(win);
553 if (win && win->type != wintype_Pair) {
554 altcommand = xkey_parse_key(key, win);
555 if (altcommand)
556 break;
557 }
558 } while (win != gli_focuswin);
559 if (win != gli_focuswin && altcommand) {
560 command = altcommand;
561 cmdwin = win;
562 gli_set_focus(win);
563 }
564 }
565
566 if (command) {
567 if (command->operand == (-1)) {
568 /* Translate a key or keysym to a Glk code. */
569 if (key & 0xff00) {
570 KeySym ksym;
571 key &= 0xff;
572 ksym = (KeySym)((XK_Home & 0xff00) | key);
573 switch (ksym) {
574 case XK_Left:
575 case XK_KP_Left:
576 op = keycode_Left;
577 break;
578 case XK_Right:
579 case XK_KP_Right:
580 op = keycode_Right;
581 break;
582 case XK_Up:
583 case XK_KP_Up:
584 op = keycode_Up;
585 break;
586 case XK_Down:
587 case XK_KP_Down:
588 op = keycode_Down;
589 break;
590 case XK_Page_Up:
591 case XK_KP_Page_Up:
592 op = keycode_PageUp;
593 break;
594 case XK_Page_Down:
595 case XK_KP_Page_Down:
596 op = keycode_PageDown;
597 break;
598 case XK_Home:
599 case XK_KP_Home:
600 case XK_Begin:
601 case XK_KP_Begin:
602 op = keycode_Home;
603 break;
604 case XK_End:
605 case XK_KP_End:
606 op = keycode_End;
607 break;
608 case XK_Return:
609 case XK_KP_Enter:
610 case XK_Linefeed:
611 op = keycode_Return;
612 break;
613 case XK_BackSpace:
614 case XK_Delete:
615 case XK_KP_Delete:
616 op = keycode_Delete;
617 break;
618 case XK_Escape:
619 op = keycode_Escape;
620 break;
621 case XK_F1:
622 case XK_KP_F1:
623 op = keycode_Func1;
624 break;
625 case XK_F2:
626 case XK_KP_F2:
627 op = keycode_Func2;
628 break;
629 case XK_F3:
630 case XK_KP_F3:
631 op = keycode_Func3;
632 break;
633 case XK_F4:
634 case XK_KP_F4:
635 op = keycode_Func4;
636 break;
637 case XK_F5:
638 op = keycode_Func5;
639 break;
640 case XK_F6:
641 op = keycode_Func6;
642 break;
643 case XK_F7:
644 op = keycode_Func7;
645 break;
646 case XK_F8:
647 op = keycode_Func8;
648 break;
649 case XK_F9:
650 op = keycode_Func9;
651 break;
652 case XK_F10:
653 op = keycode_Func10;
654 break;
655 case XK_F11:
656 op = keycode_Func11;
657 break;
658 case XK_F12:
659 op = keycode_Func12;
660 break;
661 default:
662 op = keycode_Unknown;
663 break;
664 }
665 }
666 else {
667 switch (key) {
668 case '\177':
669 op = keycode_Delete;
670 break;
671 default:
672 op = key;
673 break;
674 }
675 }
676 }
677 else {
678 op = command->operand;
679 }
680 (*(command->func))(cmdwin, op);
681
682 }
683 else {
684 char buf[128];
685 char *cx;
686 cx = xkey_get_key_name(key);
687 sprintf(buf, "Key <%s> not bound", cx);
688 xmsg_set_message(buf, FALSE);
689 }
690 }
691
xkey_guess_focus()692 void xkey_guess_focus()
693 {
694 window_t *altwin;
695
696 if (xmsg_msgmode) {
697 gli_set_focus(NULL);
698 return;
699 }
700
701 if (gli_focuswin
702 && (gli_focuswin->line_request || gli_focuswin->char_request)) {
703 return;
704 }
705
706 altwin = gli_focuswin;
707 do {
708 altwin = gli_window_fixiterate(altwin);
709 if (altwin
710 && (altwin->line_request || altwin->char_request)) {
711 break;
712 }
713 } while (altwin != gli_focuswin);
714
715 gli_set_focus(altwin);
716 }
717
xgc_work_meta(struct glk_window_struct * dummy,int op)718 void xgc_work_meta(struct glk_window_struct *dummy, int op)
719 {
720 switch (op) {
721 case op_Cancel:
722 xmsg_set_message("Cancelled.", FALSE);
723 modify_mode = op_Cancel;
724 break;
725 case op_Meta:
726 modify_mode = op_Meta;
727 break;
728 case op_ExplainKey:
729 xmsg_set_message("Type a key to explain.", FALSE);
730 modify_mode = op_ExplainKey;
731 break;
732 /*###case op_DefineMacro:
733 xmsg_set_message("Select some text, and type a macro command key to define.",
734 FALSE);
735 modify_mode = op_DefineMacro;
736 break; ###*/
737 }
738 }
739
740