1 /*
2 * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
3 * Copyright (c) 1996-2005 Michael T Pins. All rights reserved.
4 *
5 * Keyboard (re)mapping
6 */
7
8 #include <string.h>
9 #include <ctype.h>
10 #include "config.h"
11 #include "global.h"
12 #include "init.h"
13 #include "keymap.h"
14 #include "nn_term.h"
15
16 extern int data_bits;
17
18 /*
19 * KEY MAP LAYOUT:
20 * 128 normal ASCII chars
21 * 0200 -- unused
22 * 4 arrow keys #up/down/left/right
23 * 10 multi keys #0-#9
24 * 17 spare keys
25 * 95 national 8-bit characters (8859/x)
26 * 0377 is unused (since we must be able to test c<KEY_MAP_SIZE)
27 *
28 * The encoding of the keymap arrays are performed in
29 * keymap.c (initialization + key_name/parse_key)
30 */
31
32 /* in keymap.h, MULTI_KEYS include ARROW_KEYS for term.c */
33 #undef MULTI_KEYS
34
35 #define NORMAL_KEYS 129 /* include 0200 for convenience */
36 #define ARROW_KEYS 4
37 #define MULTI_KEYS 16
38 #define SPARE_KEYS 11
39 #define NATIONAL_KEYS 96
40 #define KEY_MAP_SIZE 255
41
42 /*
43 * standard keyboard mapping for more()
44 *
45 * redraw ^L, ^R
46 * continue space
47 * repeat message ^P
48 * help ?
49 * shell escape !
50 * version V
51 * extended command :
52 * quit Q
53 *
54 * save S, O
55 * save, no header W
56 * reply R
57 * follow up F
58 * mail (forward) M
59 * cancel C
60 * unsubscribe U
61 * group overview Y
62 * print article P
63 * kill handling K
64 *
65 * update, goto next group X
66 * no update, next group q, Z
67 * return to menu =
68 * prev article p
69 * goto group G
70 *
71 * line forward CR/NL
72 * half page forward d/^D
73 * half page back u/^U
74 * full page back BS, DEL, (up arrow)
75 * goto line g
76 * goto match /
77 * next match .
78 *
79 * select subject N, *
80 *
81 * header h
82 * digest header H
83 * top t
84 * last page $
85 * leave article l
86 * leave article to next L
87 * next article n
88 * kill subject k
89 *
90 * rot13 D
91 * compress c
92 */
93
94 int more_key_map[KEY_MAP_SIZE] = {
95
96 /* NUL ^@ */ K_UNBOUND,
97 /* SOH ^A */ K_UNBOUND,
98 /* STX ^B */ K_UNBOUND,
99 /* ETX ^C */ K_UNBOUND,
100 /* EOT ^D */ K_NEXT_HALF_PAGE,
101 /* ENQ ^E */ K_UNBOUND,
102 /* ACK ^F */ K_UNBOUND,
103 /* BEL ^G */ K_INVALID,
104 /* BS ^H */ K_PREV_PAGE,
105 /* TAB ^I */ K_SKIP_LINES,
106 /* NL ^J */ K_NEXT_LINE,
107 /* VT ^K */ K_UNBOUND,
108 /* FF ^L */ K_REDRAW,
109 /* CR ^M */ K_NEXT_LINE,
110 /* SO ^N */ K_UNBOUND,
111 /* SI ^O */ K_UNBOUND,
112 /* DLE ^P */ K_LAST_MESSAGE,
113 /* DC1 ^Q */ K_UNBOUND,
114 /* DC2 ^R */ K_REDRAW,
115 /* DC3 ^S */ K_UNBOUND,
116 /* DC4 ^T */ K_UNBOUND,
117 /* NAK ^U */ K_PREV_HALF_PAGE,
118 /* SYN ^V */ K_NEXT_PAGE,
119 /* ETB ^W */ K_UNBOUND,
120 /* CAN ^X */ K_UNBOUND,
121 /* EM ^Y */ K_UNBOUND,
122 /* SUB ^Z */ K_UNBOUND,
123 /* ESC ^[ */ K_UNBOUND,
124 /* FS ^\ */ K_UNBOUND,
125 /* GS ^] */ K_UNBOUND,
126 /* RS ^^ */ K_UNBOUND,
127 /* US ^_ */ K_UNBOUND,
128 /* SP */ K_CONTINUE,
129 /* ! */ K_SHELL,
130 /* " */ K_UNBOUND,
131 /* # */ K_UNBOUND,
132 /* $ */ K_LAST_PAGE,
133 /* % */ K_PREVIEW,
134 /* & */ K_UNBOUND,
135 /* ' */ K_UNBOUND,
136 /* ( */ K_UNBOUND,
137 /* ) */ K_UNBOUND,
138 /* * */ K_SELECT_SUBJECT,
139 /* + */ K_UNBOUND,
140 /* , */ K_UNBOUND,
141 /* - */ K_UNBOUND,
142 /* . */ K_NEXT_MATCH,
143 /* / */ K_GOTO_MATCH,
144 /* 0 */ K_UNBOUND,
145 /* 1 */ K_UNBOUND,
146 /* 2 */ K_UNBOUND,
147 /* 3 */ K_UNBOUND,
148 /* 4 */ K_UNBOUND,
149 /* 5 */ K_UNBOUND,
150 /* 6 */ K_UNBOUND,
151 /* 7 */ K_UNBOUND,
152 /* 8 */ K_UNBOUND,
153 /* 9 */ K_UNBOUND,
154 /* : */ K_EXTENDED_CMD,
155 /* ; */ K_UNBOUND,
156 /* < */ K_UNBOUND,
157 /* = */ K_BACK_TO_MENU,
158 /* > */ K_UNBOUND,
159 /* ? */ K_HELP,
160 /* @ */ K_UNBOUND,
161 /* A */ K_UNBOUND,
162 /* B */ K_UNBOUND,
163 /* C */ K_CANCEL,
164 /* D */ K_ROT13,
165 /* E */ K_SAVE_HEADER_ONLY,
166 /* F */ K_FOLLOW_UP,
167 /* G */ K_GOTO_GROUP,
168 /* H */ K_FULL_DIGEST,
169 /* I */ K_UNBOUND,
170 /* J */ K_UNBOUND,
171 /* K */ K_KILL_HANDLING,
172 /* L */ K_LEAVE_NEXT,
173 /* M */ K_MAIL_OR_FORWARD,
174 /* N */ K_NEXT_GROUP_NO_UPDATE,
175 /* O */ K_SAVE_SHORT_HEADER,
176 /* P */ K_PRINT,
177 /* Q */ K_QUIT,
178 /* R */ K_REPLY,
179 /* S */ K_SAVE_FULL_HEADER,
180 /* T */ K_UNBOUND,
181 /* U */ K_UNSUBSCRIBE,
182 /* V */ K_VERSION,
183 /* W */ K_SAVE_NO_HEADER,
184 /* X */ K_READ_GROUP_UPDATE,
185 /* Y */ K_GROUP_OVERVIEW,
186 /* Z */ K_BACK_TO_MENU,
187 /* [ */ K_UNBOUND,
188 /* \ */ K_UNBOUND,
189 /* ] */ K_UNBOUND,
190 /* ^ */ K_FIRST_PAGE,
191 /* _ */ K_UNBOUND,
192 /* ` */ K_UNBOUND,
193 /* a */ K_FORW_ARTICLE,
194 /* b */ K_BACK_ARTICLE,
195 /* c */ K_COMPRESS,
196 /* d */ K_NEXT_HALF_PAGE,
197 /* e */ K_SAVE_HEADER_ONLY,
198 /* f */ K_FOLLOW_UP,
199 /* g */ K_GOTO_LINE,
200 /* h */ K_HEADER_PAGE,
201 /* i */ K_UNBOUND,
202 /* j */ K_UNBOUND,
203 /* k */ K_NEXT_SUBJECT,
204 /* l */ K_LEAVE_ARTICLE,
205 /* m */ K_MAIL_OR_FORWARD,
206 /* n */ K_NEXT_ARTICLE,
207 /* o */ K_SAVE_SHORT_HEADER,
208 /* p */ K_PREVIOUS /* article */ ,
209 /* q */ K_NEXT_GROUP_NO_UPDATE,
210 /* r */ K_REPLY,
211 /* s */ K_SAVE_FULL_HEADER,
212 /* t */ K_FIRST_PAGE,
213 /* u */ K_PREV_HALF_PAGE,
214 /* v */ K_UNBOUND,
215 /* w */ K_SAVE_NO_HEADER,
216 /* x */ K_UNBOUND,
217 /* y */ K_UNBOUND,
218 /* z */ K_UNBOUND,
219 /* { */ K_UNBOUND,
220 /* | */ K_UNBOUND,
221 /* } */ K_UNBOUND,
222 /* ~ */ K_UNBOUND,
223 /* DEL */ K_PREV_PAGE,
224 /* 200 */ K_UNBOUND,
225 /* up */ K_PREV_PAGE,
226 /* down */ K_NEXT_PAGE,
227 /* left */ K_UNBOUND,
228 /* right */ K_UNBOUND,
229 /* #0 */ K_UNBOUND,
230 /* #1 */ K_UNBOUND,
231 /* #2 */ K_UNBOUND,
232 /* #3 */ K_UNBOUND,
233 /* #4 */ K_UNBOUND,
234 /* #5 */ K_UNBOUND,
235 /* #6 */ K_UNBOUND,
236 /* #7 */ K_UNBOUND,
237 /* #8 */ K_UNBOUND,
238 /* #9 */ K_UNBOUND,
239 /* mouse d1 */ K_M_CONTINUE,
240 /* mouse d2 */ K_NEXT_SUBJECT,
241 /* mouse d3 */ K_BACK_TO_MENU,
242 /* mouse u1 */ K_INVALID,
243 /* mouse u2 */ K_INVALID,
244 /* mouse u3 */ K_INVALID
245 };
246
247
248
249 /*
250 * standard keyboard mappings for menu()
251 *
252 * illegal command
253 * redraw ^L, ^R
254 * continue space
255 * continue no mark return, newline
256 * repeat message ^P
257 * help ?
258 * shell escape !
259 * version V
260 * alternative commands :
261 * quit Q
262 *
263 * save S, O
264 * save, no header W
265 * reply R
266 * follow up F
267 * mail (forward) M
268 * cancel C
269 * unsubscribe U
270 * group overview Y
271 * kill handling K
272 * junk articles J
273 *
274 * read, then next X
275 * read, then same Z
276 * no update, next N
277 * prev group P
278 * goto group G
279 * advance group A
280 * back group B
281 *
282 * article identifier a-z 0-9
283 * inverse @
284 * select current, next .
285 * next , (down arrow)
286 * prev / (up arrow)
287 * select subject *
288 * range -
289 * auto select +
290 *
291 * next page >
292 * prev page <
293 * first page ^
294 * last page $
295 *
296 * pre-view article %
297 *
298 * layout L
299 */
300
301
302 int menu_key_map[KEY_MAP_SIZE] = {
303
304 /* NUL ^@ */ K_UNBOUND,
305 /* SOH ^A */ K_UNBOUND,
306 /* STX ^B */ K_UNBOUND,
307 /* ETX ^C */ K_UNBOUND,
308 /* EOT ^D */ K_UNBOUND,
309 /* ENQ ^E */ K_UNBOUND,
310 /* ACK ^F */ K_UNBOUND,
311 /* BEL ^G */ K_INVALID,
312 /* BS ^H */ K_PREV_LINE,
313 /* TAB ^I */ K_UNBOUND,
314 /* NL ^J */ K_CONTINUE_NO_MARK,
315 /* VT ^K */ K_UNBOUND,
316 /* FF ^L */ K_REDRAW,
317 /* CR ^M */ K_CONTINUE_NO_MARK,
318 /* SO ^N */ K_UNBOUND,
319 /* SI ^O */ K_UNBOUND,
320 /* DLE ^P */ K_LAST_MESSAGE,
321 /* DC1 ^Q */ K_UNBOUND,
322 /* DC2 ^R */ K_REDRAW,
323 /* DC3 ^S */ K_UNBOUND,
324 /* DC4 ^T */ K_UNBOUND,
325 /* NAK ^U */ K_UNBOUND,
326 /* SYN ^V */ K_NEXT_PAGE,
327 /* ETB ^W */ K_UNBOUND,
328 /* CAN ^X */ K_UNBOUND,
329 /* EM ^Y */ K_UNBOUND,
330 /* SUB ^Z */ K_UNBOUND,
331 /* ESC ^[ */ K_UNBOUND,
332 /* FS ^\ */ K_UNBOUND,
333 /* GS ^] */ K_UNBOUND,
334 /* RS ^^ */ K_UNBOUND,
335 /* US ^_ */ K_UNBOUND,
336 /* SP */ K_CONTINUE,
337 /* ! */ K_SHELL,
338 /* " */ K_LAYOUT,
339 /* # */ K_UNBOUND,
340 /* $ */ K_LAST_PAGE,
341 /* % */ K_PREVIEW,
342 /* & */ K_UNBOUND,
343 /* ' */ K_UNBOUND,
344 /* ( */ K_OPEN_SUBJECT,
345 /* ) */ K_CLOSE_SUBJECT,
346 /* * */ K_SELECT_SUBJECT,
347 /* + */ K_AUTO_SELECT,
348 /* , */ K_NEXT_LINE,
349 /* - */ K_SELECT_RANGE,
350 /* . */ K_SELECT,
351 /* / */ K_PREV_LINE,
352 /* 0 */ K_ARTICLE_ID + 26,
353 /* 1 */ K_ARTICLE_ID + 27,
354 /* 2 */ K_ARTICLE_ID + 28,
355 /* 3 */ K_ARTICLE_ID + 29,
356 /* 4 */ K_ARTICLE_ID + 30,
357 /* 5 */ K_ARTICLE_ID + 31,
358 /* 6 */ K_ARTICLE_ID + 32,
359 /* 7 */ K_ARTICLE_ID + 33,
360 /* 8 */ K_ARTICLE_ID + 34,
361 /* 9 */ K_ARTICLE_ID + 35,
362 /* : */ K_EXTENDED_CMD,
363 /* ; */ K_UNBOUND,
364 /* < */ K_PREV_PAGE,
365 /* = */ K_GOTO_MATCH,
366 /* > */ K_NEXT_PAGE,
367 /* ? */ K_HELP,
368 /* @ */ K_SELECT_INVERT,
369 /* A */ K_ADVANCE_GROUP,
370 /* B */ K_BACK_GROUP,
371 /* C */ K_CANCEL,
372 /* D */ K_UNBOUND,
373 /* E */ K_SAVE_HEADER_ONLY,
374 /* F */ K_FOLLOW_UP,
375 /* G */ K_GOTO_GROUP,
376 /* H */ K_UNBOUND,
377 /* I */ K_UNBOUND,
378 /* J */ K_JUNK_ARTICLES,
379 /* K */ K_KILL_HANDLING,
380 /* L */ K_LEAVE_NEXT,
381 /* M */ K_MAIL_OR_FORWARD,
382 /* N */ K_NEXT_GROUP_NO_UPDATE,
383 /* O */ K_SAVE_SHORT_HEADER,
384 /* P */ K_PREVIOUS /* group */ ,
385 /* Q */ K_QUIT,
386 /* R */ K_REPLY,
387 /* S */ K_SAVE_FULL_HEADER,
388 /* T */ K_UNBOUND,
389 /* U */ K_UNSUBSCRIBE,
390 /* V */ K_VERSION,
391 /* W */ K_SAVE_NO_HEADER,
392 /* X */ K_READ_GROUP_UPDATE,
393 /* Y */ K_GROUP_OVERVIEW,
394 /* Z */ K_READ_GROUP_THEN_SAME,
395 /* [ */ K_UNBOUND,
396 /* \ */ K_UNBOUND,
397 /* ] */ K_UNBOUND,
398 /* ^ */ K_FIRST_PAGE,
399 /* _ */ K_UNBOUND,
400 /* ` */ K_UNBOUND,
401 /* a */ K_ARTICLE_ID + 0,
402 /* b */ K_ARTICLE_ID + 1,
403 /* c */ K_ARTICLE_ID + 2,
404 /* d */ K_ARTICLE_ID + 3,
405 /* e */ K_ARTICLE_ID + 4,
406 /* f */ K_ARTICLE_ID + 5,
407 /* g */ K_ARTICLE_ID + 6,
408 /* h */ K_ARTICLE_ID + 7,
409 /* i */ K_ARTICLE_ID + 8,
410 /* j */ K_ARTICLE_ID + 9,
411 /* k */ K_ARTICLE_ID + 10,
412 /* l */ K_ARTICLE_ID + 11,
413 /* m */ K_ARTICLE_ID + 12,
414 /* n */ K_ARTICLE_ID + 13,
415 /* o */ K_ARTICLE_ID + 14,
416 /* p */ K_ARTICLE_ID + 15,
417 /* q */ K_ARTICLE_ID + 16,
418 /* r */ K_ARTICLE_ID + 17,
419 /* s */ K_ARTICLE_ID + 18,
420 /* t */ K_ARTICLE_ID + 19,
421 /* u */ K_ARTICLE_ID + 20,
422 /* v */ K_ARTICLE_ID + 21,
423 /* w */ K_ARTICLE_ID + 22,
424 /* x */ K_ARTICLE_ID + 23,
425 /* y */ K_ARTICLE_ID + 24,
426 /* z */ K_ARTICLE_ID + 25,
427 /* { */ K_UNBOUND,
428 /* | */ K_UNBOUND,
429 /* } */ K_UNBOUND,
430 /* ~ */ K_UNSELECT_ALL,
431 /* DEL */ K_PREV_LINE,
432 /* 200 */ K_UNBOUND,
433 /* up */ K_PREV_LINE,
434 /* down */ K_NEXT_LINE,
435 /* left */ K_UNBOUND,
436 /* right */ K_UNBOUND,
437 /* #0 */ K_UNBOUND,
438 /* #1 */ K_UNBOUND,
439 /* #2 */ K_UNBOUND,
440 /* #3 */ K_UNBOUND,
441 /* #4 */ K_UNBOUND,
442 /* #5 */ K_UNBOUND,
443 /* #6 */ K_UNBOUND,
444 /* #7 */ K_UNBOUND,
445 /* #8 */ K_UNBOUND,
446 /* #9 */ K_UNBOUND,
447 /* mouse d1 */ K_M_SELECT,
448 /* mouse d2 */ K_M_PREVIEW,
449 /* mouse d3 */ K_NEXT_GROUP_NO_UPDATE,
450 /* mouse u1 */ K_M_SELECT_RANGE,
451 /* mouse u2 */ K_INVALID,
452 /* mouse u3 */ K_INVALID
453 };
454
455 int orig_menu_map[KEY_MAP_SIZE]; /* initially empty */
456
457
458 static struct command_name_map {
459 char *cmd_name;
460 int cmd_code;
461 int cmd_restriction;
462 } command_name_map[] = {
463
464 "advance-article", K_FORW_ARTICLE, K_ONLY_MORE,
465 "advance-group", K_ADVANCE_GROUP, 0,
466 "article", K_ARTICLE_ID, K_ONLY_MENU,
467 "as", K_EQUAL_KEY, 0,
468
469 "back-article", K_BACK_ARTICLE, K_ONLY_MORE,
470 "back-group", K_BACK_GROUP, 0,
471
472 "cancel", K_CANCEL, 0,
473 "close-subject", K_CLOSE_SUBJECT, K_ONLY_MENU,
474 "command", K_EXTENDED_CMD, 0,
475 "compress", K_COMPRESS, K_ONLY_MORE,
476 "continue", K_CONTINUE, 0,
477 "continue-no-mark", K_CONTINUE_NO_MARK, K_ONLY_MENU,
478
479 "decode", K_UUDECODE, 0,
480
481 "find", K_GOTO_MATCH, 0,
482 "find-next", K_NEXT_MATCH, K_ONLY_MORE,
483 "follow", K_FOLLOW_UP, 0,
484 "full-digest", K_FULL_DIGEST, K_ONLY_MORE,
485
486 "goto-group", K_GOTO_GROUP, 0,
487 "goto-menu", K_BACK_TO_MENU, K_ONLY_MORE,
488
489 "help", K_HELP, 0,
490
491 "junk-articles", K_JUNK_ARTICLES, K_ONLY_MENU,
492
493 "kill-select", K_KILL_HANDLING, 0,
494
495 "layout", K_LAYOUT, K_ONLY_MENU,
496 "leave-article", K_LEAVE_ARTICLE, K_ONLY_MORE,
497 "leave-next", K_LEAVE_NEXT, K_ONLY_MORE,
498 "line+1", K_NEXT_LINE, 0,
499 "line-1", K_PREV_LINE, K_ONLY_MENU,
500 "line=@", K_GOTO_LINE, K_ONLY_MORE,
501
502 "macro", K_MACRO, 0,
503 "mail", K_MAIL_OR_FORWARD, 0,
504 "message", K_LAST_MESSAGE, 0,
505 "mouse-continue", K_M_CONTINUE, K_ONLY_MORE,
506 "mouse-preview", K_M_PREVIEW, K_ONLY_MENU,
507 "mouse-select", K_M_SELECT, K_ONLY_MENU,
508 "mouse-select-range", K_M_SELECT_RANGE, K_ONLY_MENU,
509 "mouse-select-subject", K_M_SELECT_SUBJECT, K_ONLY_MENU,
510 "mouse-toggle", K_M_TOGGLE, 0,
511
512 "next-article", K_NEXT_ARTICLE, K_ONLY_MORE,
513 "next-group", K_NEXT_GROUP_NO_UPDATE, 0,
514 "next-subject", K_NEXT_SUBJECT, K_ONLY_MORE,
515 "nil", K_UNBOUND, 0,
516
517 "open-subject", K_OPEN_SUBJECT, K_ONLY_MENU,
518 "overview", K_GROUP_OVERVIEW, 0,
519
520 "page+1", K_NEXT_PAGE, 0,
521 "page+1/2", K_NEXT_HALF_PAGE, K_ONLY_MORE,
522 "page-1", K_PREV_PAGE, 0,
523 "page-1/2", K_PREV_HALF_PAGE, K_ONLY_MORE,
524 "page=$", K_LAST_PAGE, 0,
525 "page=0", K_HEADER_PAGE, 0,
526 "page=1", K_FIRST_PAGE, 0,
527 "page=@", K_GOTO_PAGE, K_ONLY_MORE,
528
529 "patch", K_PATCH, 0,
530 "post", K_POST, 0,
531 "prefix", K_PREFIX_KEY, 0,
532 "preview", K_PREVIEW, 0,
533 "previous", K_PREVIOUS, 0,
534 "print", K_PRINT, 0,
535
536 "quit", K_QUIT, 0,
537
538 "read-return", K_READ_GROUP_THEN_SAME, K_ONLY_MENU,
539 "read-skip", K_READ_GROUP_UPDATE, 0,
540 "redraw", K_REDRAW, 0,
541 "reply", K_REPLY, 0,
542 "rot13", K_ROT13, K_ONLY_MORE,
543
544 "save-body", K_SAVE_NO_HEADER, 0,
545 "save-full", K_SAVE_FULL_HEADER, 0,
546 "save-short", K_SAVE_SHORT_HEADER, 0,
547 "save-hdr-only", K_SAVE_HEADER_ONLY, 0,
548 "select", K_SELECT, K_ONLY_MENU,
549 "select-auto", K_AUTO_SELECT, K_ONLY_MENU,
550 "select-invert", K_SELECT_INVERT, K_ONLY_MENU,
551 "select-range", K_SELECT_RANGE, K_ONLY_MENU,
552 "select-subject", K_SELECT_SUBJECT, 0,
553 "shell", K_SHELL, 0,
554 "skip-lines", K_SKIP_LINES, 0,
555
556 "unselect-all", K_UNSELECT_ALL, K_ONLY_MENU,
557 "unshar", K_UNSHAR, 0,
558 "unsub", K_UNSUBSCRIBE, 0,
559
560 "version", K_VERSION, 0,
561
562 (char *) NULL, 0, 0
563 };
564
565 static int name_map_size;
566 #define max_cmd_name_length 16 /* recalculate if table is changed */
567
568 key_type global_key_map[KEY_MAP_SIZE];
569
570
571 void
init_key_map(void)572 init_key_map(void)
573 {
574 register int c;
575 register struct command_name_map *cnmp;
576
577 for (c = 0; c < KEY_MAP_SIZE; c++)
578 global_key_map[c] = c;
579 for (c = NORMAL_KEYS + ARROW_KEYS + MULTI_KEYS; c < KEY_MAP_SIZE; c++) {
580 menu_key_map[c] = K_UNBOUND;
581 more_key_map[c] = K_UNBOUND;
582 }
583
584 for (cnmp = command_name_map; cnmp->cmd_name; cnmp++);
585 name_map_size = cnmp - command_name_map;
586 }
587
588
589 int
lookup_command(char * command,int restriction)590 lookup_command(char *command, int restriction)
591 {
592 register struct command_name_map *cnmp;
593 register int i, j, k, t;
594
595 i = 0;
596 j = name_map_size - 1;
597
598 while (i <= j) {
599 k = (i + j) / 2;
600 cnmp = &command_name_map[k];
601
602 if ((t = strcmp(command, cnmp->cmd_name)) > 0)
603 i = k + 1;
604 else if (t < 0)
605 j = k - 1;
606 else {
607 switch (restriction) {
608 case K_ONLY_MENU:
609 case K_ONLY_MORE:
610 if (cnmp->cmd_restriction == restriction)
611 break;
612 /* FALLTHRU */
613 case 0:
614 if (cnmp->cmd_restriction == 0)
615 break;
616 return K_INVALID - 1;
617 default:
618 break;
619 }
620 return cnmp->cmd_code;
621 }
622 }
623
624 return K_INVALID;
625 }
626
627
628 int
cmd_completion(char * path,int index)629 cmd_completion(char *path, int index)
630 {
631 static char *head, *tail = NULL;
632 static int len;
633 static struct command_name_map *cmd, *help_cmd;
634
635 if (index < 0)
636 return 0;
637
638 if (path) {
639 head = path;
640 tail = path + index;
641 while (*head && isspace(*head))
642 head++;
643 help_cmd = cmd = command_name_map;
644 len = tail - head;
645
646 return 1;
647 }
648 if (index) {
649 list_completion((char *) NULL);
650
651 if (help_cmd->cmd_name == NULL)
652 help_cmd = command_name_map;
653
654 for (; help_cmd->cmd_name; help_cmd++) {
655 index = strncmp(help_cmd->cmd_name, head, len);
656 if (index < 0)
657 continue;
658 if (index > 0) {
659 help_cmd = command_name_map;
660 break;
661 }
662 if (list_completion(help_cmd->cmd_name) == 0)
663 break;
664 }
665 fl;
666 return 1;
667 }
668 for (; cmd->cmd_name; cmd++) {
669 if (len == 0)
670 index = 0;
671 else
672 index = strncmp(cmd->cmd_name, head, len);
673 if (index < 0)
674 continue;
675 if (index > 0)
676 break;
677 if (cmd->cmd_code == K_MACRO ||
678 cmd->cmd_code == K_ARTICLE_ID ||
679 cmd->cmd_code == K_PREFIX_KEY ||
680 cmd->cmd_code == K_EQUAL_KEY)
681 sprintf(tail, "%s ", cmd->cmd_name + len);
682 else
683 strcpy(tail, cmd->cmd_name + len);
684 cmd++;
685 return 1;
686 }
687 return 0;
688 }
689
690
691 char *
command_name(int cmd)692 command_name(int cmd)
693 {
694 register struct command_name_map *cnmp;
695
696 cmd &= ~GETC_COMMAND;
697
698 for (cnmp = command_name_map; cnmp->cmd_name; cnmp++)
699 if (cnmp->cmd_code == cmd)
700 return cnmp->cmd_name;
701
702 return "unknown";
703 }
704
705
706 /*
707 * convert key name into ascii code
708 *
709 * key names are:
710 * c character c
711 * ^C control-C
712 * 0xNN hex value (0..0x7f)
713 * 0NNN octal value (0..0177)
714 * NNN decimal value (0..127)
715 * up, down, left, rigth arrow keys
716 * #0..#9 function keys (initially undefined)
717 */
718
719 key_type
parse_key(char * str)720 parse_key(char *str)
721 {
722 int x;
723
724 if (str[1] == NUL)
725 return (data_bits < 8) ? (str[0] & 0177) : str[0];
726
727 if (str[0] == '^') {
728 if (str[1] == '?')
729 return 0177;
730 else
731 return CONTROL_(str[1]);
732 }
733
734 if (isdigit(str[0])) {
735 if (str[0] == '0') {
736 if (str[1] == 'x')
737 sscanf(str + 2, "%d", &x);
738 else
739 sscanf(str + 1, "%d", &x);
740 } else {
741 sscanf(str, "%d", &x);
742 }
743
744 return x;
745 }
746 if (str[0] == '#' && isdigit(str[1]))
747 return K_function(str[1] - '0');
748
749 if (str[0] == '#')
750 str++;
751
752 if (strcmp(str, "up") == 0)
753 return K_up_arrow;
754
755 if (strcmp(str, "down") == 0)
756 return K_down_arrow;
757
758 if (strcmp(str, "left") == 0)
759 return K_left_arrow;
760
761 if (strcmp(str, "right") == 0)
762 return K_right_arrow;
763
764 if (strcmp(str, "mouse_d1") == 0) /* thp */
765 return K_m_d1;
766 if (strcmp(str, "mouse_d2") == 0) /* thp */
767 return K_m_d2;
768 if (strcmp(str, "mouse_d3") == 0) /* thp */
769 return K_m_d3;
770 if (strcmp(str, "mouse_u1") == 0) /* thp */
771 return K_m_u1;
772 if (strcmp(str, "mouse_u2") == 0) /* thp */
773 return K_m_u2;
774 if (strcmp(str, "mouse_u3") == 0) /* thp */
775 return K_m_u3;
776
777 init_message("unknown key: %s", str);
778
779 return 0200;
780 }
781
782 char *
key_name(key_type c)783 key_name(key_type c)
784 {
785 static char buf[10];
786
787 if (c >= NORMAL_KEYS && c <= (key_type) (KEY_MAP_SIZE - NATIONAL_KEYS)) {
788 switch (c) {
789 case K_up_arrow:
790 return "up";
791 case K_down_arrow:
792 return "down";
793 case K_left_arrow:
794 return "left";
795 case K_right_arrow:
796 return "right";
797 case K_m_d1:
798 return "mouse_d1";
799 case K_m_d2:
800 return "mouse_d2";
801 case K_m_d3:
802 return "mouse_d3";
803 case K_m_u1:
804 return "mouse_u1";
805 case K_m_u2:
806 return "mouse_u2";
807 case K_m_u3:
808 return "mouse_u3";
809 default:
810 buf[0] = '#';
811 buf[1] = (c - K_function(0))
812 + (c >= (key_type) K_function(MULTI_KEYS) ? 'A' - K_function(MULTI_KEYS) : '0');
813 buf[2] = NUL;
814 goto out;
815 }
816 }
817 if (c == SP)
818 return "space";
819
820 if (c < SP) {
821 buf[0] = '^';
822 buf[1] = c + '@';
823 buf[2] = NUL;
824 goto out;
825 }
826 if (c == 0177) {
827 strcpy(buf, "^?");
828 goto out;
829 }
830 if (data_bits < 8 && c >= NORMAL_KEYS) {
831 sprintf(buf, "0x%02x", (uint)c);
832 goto out;
833 }
834 buf[0] = c;
835 buf[1] = NUL;
836
837 out:
838 return buf;
839 }
840
841
842 void
dump_global_map(void)843 dump_global_map(void)
844 {
845 register key_type c;
846
847 clrdisp();
848 so_printf("\1REMAPPED KEYS\1\n\n");
849 pg_init(2, 4);
850
851 for (c = 0; c < KEY_MAP_SIZE; c++)
852 if (c != global_key_map[c]) {
853 if (pg_next() < 0)
854 break;
855 tprintf("%s", key_name(c));
856 pg_indent(6);
857 tprintf("-> %s", key_name(global_key_map[c]));
858 }
859 pg_end();
860 }
861
862 int
dump_key_map(char * where)863 dump_key_map(char *where)
864 {
865 register struct command_name_map *cnmp;
866 register key_type c;
867 register int code, first_prt;
868 int *map, restriction;
869
870 if ((code = lookup_keymap(where)) < 0)
871 return -1;
872 map = keymaps[code].km_map;
873 restriction = keymaps[code].km_flag & (K_ONLY_MENU | K_ONLY_MORE);
874
875 clrdisp();
876 so_printf("\1KEY BINDINGS (%s)\1\n\n", where);
877
878 if (restriction == K_ONLY_MENU) {
879 tprintf("\rarticle: ");
880 for (c = 0; c < KEY_MAP_SIZE; c++)
881 if (map[c] & K_ARTICLE_ID)
882 tprintf("%s", key_name(c));
883 }
884 pg_init(4, 2);
885
886 for (cnmp = command_name_map; cnmp->cmd_name; cnmp++) {
887 if (cnmp->cmd_restriction && cnmp->cmd_restriction != restriction)
888 continue;
889 if (cnmp->cmd_code == K_UNBOUND)
890 continue;
891 if (cnmp->cmd_code == K_MACRO)
892 continue;
893
894 code = cnmp->cmd_code;
895 first_prt = 1;
896
897 for (c = 0; c < KEY_MAP_SIZE; c++)
898 if (map[c] == code) {
899 if (first_prt) {
900 if (pg_next() < 0)
901 goto out;
902 tprintf("%s", cnmp->cmd_name);
903 pg_indent(max_cmd_name_length);
904 first_prt = 0;
905 }
906 tprintf(" %s", key_name(c));
907 }
908 }
909
910 for (c = 0; c < KEY_MAP_SIZE; c++)
911 if (map[c] & K_MACRO) {
912 if (pg_next() < 0)
913 goto out;
914 tprintf("macro %d: %s", (map[c] & ~K_MACRO), key_name(c));
915 if (map == menu_key_map && orig_menu_map[c] != K_UNBOUND)
916 tprintf(" (%s)", command_name(orig_menu_map[c]));
917 } else if (map[c] & K_PREFIX_KEY) {
918 if (pg_next() < 0)
919 goto out;
920 tprintf("prefix %s: %s",
921 keymaps[(map[c] & ~K_PREFIX_KEY)].km_name, key_name(c));
922 }
923 out:
924 pg_end();
925 return 0;
926 }
927
928 #define MAX_KEYMAPS 17
929
930 struct key_map_def keymaps[MAX_KEYMAPS + 1] = {
931 "#", NULL, K_MULTI_KEY_MAP,
932 "key", NULL, K_GLOBAL_KEY_MAP,
933 "menu", menu_key_map, K_BIND_ORIG | K_ONLY_MENU,
934 "show", more_key_map, K_ONLY_MORE,
935 "both", menu_key_map, K_BOTH_MAPS | K_BIND_ORIG,
936 "more", more_key_map, K_ONLY_MORE,
937 "read", more_key_map, K_ONLY_MORE,
938 NULL,
939 };
940
941 int
lookup_keymap(char * name)942 lookup_keymap(char *name)
943 {
944 register struct key_map_def *m;
945
946 if (name[0] == '#')
947 return 0;
948
949 for (m = keymaps; m->km_name; m++) {
950 if (strcmp(name, m->km_name) == 0)
951 return m - keymaps;
952 }
953 return keymaps - m;
954 }
955
956 int
make_keymap(char * name)957 make_keymap(char *name)
958 {
959 register struct key_map_def *m;
960 register int *kp;
961 int ix;
962
963 ix = lookup_keymap(name);
964 if (ix >= 0)
965 return -1;
966 ix = -ix;
967 if (ix == MAX_KEYMAPS)
968 return -2;
969
970 m = &keymaps[ix];
971 m->km_name = copy_str(name);
972 m->km_map = newobj(int, KEY_MAP_SIZE);
973 m->km_flag = K_ONLY_MORE | K_ONLY_MENU;
974 for (kp = m->km_map; kp < &(m->km_map)[KEY_MAP_SIZE];)
975 *kp++ = K_UNBOUND;
976
977 return ix;
978 }
979
980 int
keymap_completion(char * buf,int ix)981 keymap_completion(char *buf, int ix)
982 {
983 static char *head, *tail = NULL;
984 static int len;
985 static struct key_map_def *map, *help_map;
986
987 if (ix < 0)
988 return 0;
989
990 if (buf) {
991 head = buf;
992 tail = buf + ix;
993 while (*head && isspace(*head))
994 head++;
995 help_map = map = keymaps;
996 len = tail - head;
997
998 return 1;
999 }
1000 if (ix) {
1001 list_completion((char *) NULL);
1002
1003 if (help_map->km_name == NULL)
1004 help_map = keymaps;
1005
1006 for (; help_map->km_name; help_map++) {
1007 if (strncmp(help_map->km_name, head, len))
1008 continue;
1009 if (list_completion(help_map->km_name) == 0)
1010 break;
1011 }
1012 fl;
1013 return 1;
1014 }
1015 for (; map->km_name; map++) {
1016 if (len && strncmp(map->km_name, head, len))
1017 continue;
1018 strcpy(tail, map->km_name + len);
1019 if (map != keymaps)
1020 strcat(tail, " ");
1021 map++;
1022 return 1;
1023 }
1024 return 0;
1025 }
1026