1 #include <config.h>
2
3 #if (SCREEN_LINES > 0)
4
5 #if defined(HAVE_SYS_IOCTL_H)
6 #include <sys/ioctl.h>
7 #endif
8
9 #if defined(HAVE_STDLIB_H)
10 #include <stdlib.h>
11 #endif
12
13 #include "xctype.h"
14 #include "xstring.h"
15 #include "xunistd.h"
16
17 RCSID("$Id: keybrd.c,v 1.11 2017/06/09 14:46:20 beebe Exp beebe $")
18
19 #include "ch.h"
20 #include "keybrd.h"
21 #include "yesorno.h"
22
23 #define LAST_SCREEN_LINE (-2) /* used in opt_help() and do_more() */
24
25 #if defined(MAX)
26 #undef MAX
27 #endif
28
29 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
30
31 #ifdef MIN
32 #undef MIN
33 #endif /* MIN */
34
35 #define MIN(a,b) ((a) < (b) ? (a) : (b))
36
37 #undef MAX_CHAR
38 #define MAX_CHAR 256
39
40 static keyboard_code_t keymap[MAX_CHAR];
41
42 extern int screen_lines; /* kbopen() and out_lines() reset */
43
44 extern FILE *tfopen ARGS((const char *filename_, const char *mode_));
45
46 static void beep ARGS((FILE *fpout));
47
48 int do_more ARGS((FILE *fpout_, int line_, int pause_after_,
49 const char *lines[]));
50
51 static int do_search ARGS((FILE *fpout_, int code_, int line_number_,
52 int pause_after_, const char *lines_[]));
53
54 static void erase_characters ARGS((FILE *fpout_, int how_many_));
55
56 static keyboard_code_t kbcode ARGS((void));
57
58 static int kbget ARGS((void));
59
60 static void kbinitmap ARGS((void));
61
62
63 static void
64 #if defined (HAVE_STDC)
beep(FILE * fpout)65 beep(FILE *fpout)
66 #else
67 beep(fpout)
68 FILE *fpout;
69 #endif
70 {
71 (void)fputc(CH_BELL,fpout);
72 (void)fflush(fpout);
73 }
74
75
76 #if defined(HAVE_STDC)
77 int
do_more(FILE * fpout,int line_number,int pause_after,const char * lines[])78 do_more(FILE *fpout,int line_number, int pause_after, const char *lines[])
79 #else /* K&R style */
80 int
81 do_more(fpout, line_number, pause_after, lines)
82 FILE *fpout;
83 int line_number;
84 int pause_after;
85 const char *lines[];
86 #endif
87 {
88 int code;
89
90 #if OS_PCDOS
91 #define MORE_HELP \
92 "More? f)orwd b)ackwd e)nd q)uit r)efresh t)op \\/)search \030 \031 PgUp \
93 PgDn Home End\n\r"
94 #else /* NOT OS_PCDOS */
95 #define MORE_HELP \
96 "More? f)orward b)ackward d)own e)nd q)uit r)efresh t)op u)p \\/)search\n\r"
97 #endif /* OS_PCDOS */
98
99 (void)fputs(MORE_HELP,fpout);
100 (void)fflush(fpout); /* make screen up-to-date */
101 for (;;) /* loop until a valid input code is received */
102 {
103 switch (code = kbcode())
104 {
105 case KEYBOARD_PGUP: /* backward screen */
106 return (MAX(0,line_number + 1 - 2*pause_after));
107
108 case KEYBOARD_DOWN: /* go down 1 line (scroll up 1 line) */
109 return (line_number + 2 - pause_after);
110
111 case KEYBOARD_END: /* end */
112 return (LAST_SCREEN_LINE);
113
114 case KEYBOARD_PGDN: /* forward screen */
115 return (line_number + 1);
116
117 case KEYBOARD_HELP:
118 (void)fputs(MORE_HELP,fpout);
119 break;
120
121 case KEYBOARD_EOF:
122 case KEYBOARD_QUIT:
123 return (EOF);
124
125 case KEYBOARD_AGAIN: /* refresh */
126 return (MAX(0,line_number + 1 - pause_after));
127
128 case KEYBOARD_HOME: /* top */
129 return (0);
130
131 case KEYBOARD_UP: /* go up 1 line (scroll down 1 line) */
132 return (line_number + 0 - pause_after);
133
134 case KEYBOARD_DOWN_PARAGRAPH:
135 /* Move down so that paragraph following the paragraph of
136 the current top-of-screen line is at top-of-screen */
137 line_number++;
138 if (line_number >= (screen_lines - 2))
139 line_number -= (screen_lines - 2);
140 while ((lines[line_number] != (char*)NULL) &&
141 (lines[line_number][0] != '\n'))
142 line_number++;
143 return ((lines[line_number] == (char*)NULL) ? LAST_SCREEN_LINE :
144 line_number + 1);
145
146 case KEYBOARD_UP_PARAGRAPH:
147 /* Move up so that paragraph of current top-of-screen line
148 has its first line at top of screen. */
149 line_number--;
150 if (line_number >= (screen_lines - 2))
151 line_number -= (screen_lines - 2);
152 while ((line_number >= 0) && (lines[line_number] != (char*)NULL) &&
153 (lines[line_number][0] != '\n'))
154 line_number--;
155 return (line_number + 1);
156
157 case KEYBOARD_SEARCH_BACKWARD:
158 case KEYBOARD_SEARCH_FORWARD:
159 return (do_search(fpout,code,line_number,pause_after,lines));
160
161 case KEYBOARD_UNKNOWN:
162 default: /* anything else produces */
163 beep(fpout); /* an error beep */
164 break;
165 } /* end switch (c...) */
166 } /* end for (;;) */
167 }
168
169
170 static int
171 #if defined(HAVE_STDC)
do_search(FILE * fpout,int code,int line_number,int pause_after,const char * lines[])172 do_search(FILE *fpout, int code, int line_number, int pause_after, const char *lines[])
173 #else
174 do_search(fpout, code, line_number, pause_after, lines)
175 FILE *fpout;
176 int code;
177 int line_number;
178 int pause_after;
179 const char *lines[];
180 #endif
181 {
182 int c;
183 int k;
184 int last_line_number = line_number;
185
186 /*@-modobserver@*/
187 static char search_string[80] = ""; /* preserved across calls */
188
189 (void)fputs((code == KEYBOARD_SEARCH_BACKWARD) ?
190 "Search backward: " :
191 "Search forward: ",fpout);
192 (void)fflush(fpout);
193 for (k = 0; ;)
194 {
195 c = kbget();
196 if ((c == CH_NUL) || (c == CH_ESCAPE) ||
197 (c == (int)'\r') || (c == (int)'\n'))
198 break; /* here's the loop exit */
199 else if ((c == CH_BACKSPACE) || (c == CH_DELETE))
200 {
201 erase_characters(fpout,1);
202 if (k > 0)
203 k--;
204 search_string[k] = '\0';
205 }
206 else if (c == CH_LINE_KILL) /* erase entire search string */
207 {
208 erase_characters(fpout,k);
209 k = 0;
210 search_string[k] = '\0';
211 }
212 else if (c == CH_REPRINT) /* reprint entire search string */
213 {
214 int m;
215
216 erase_characters(fpout,k);
217 for (m = 0; m < k; ++m)
218 (void)fputc((int)search_string[m],fpout);
219 (void)fflush(fpout);
220 }
221 else if (c == CH_WORD_ERASE) /* erase last non-blank word */
222 {
223 YESorNO saw_word;
224
225 saw_word = NO;
226 for (--k ; k >= 0; --k)
227 {
228 if (Isspace(search_string[k]) && (saw_word == YES))
229 {
230 k++; /* so that we keep this space */
231 break;
232 }
233 if (!Isspace(search_string[k]))
234 saw_word = YES;
235 erase_characters(fpout,1);
236 }
237 if (k < 0)
238 k = 0;
239 search_string[k] = '\0';
240 (void)fflush(fpout);
241 }
242 else if (k < ((int)sizeof(search_string) - 1))
243 {
244 search_string[k++] = (char)c;
245 (void)fputc(c,fpout); /* echo input character */
246 (void)fflush(fpout);
247 }
248 else /* search string too long: beep at user */
249 beep(fpout);
250 }
251 if (k > 0) /* got new search string */
252 search_string[k] = '\0';
253 else /* re-use last search string */
254 {
255 (void)fputs(search_string,fpout);
256 (void)fputc('\r',fpout);
257 (void)fputc('\n',fpout);
258 (void)fflush(fpout);
259 }
260 (void)fputc('\r',fpout);
261
262 for (k = (int)(strlen("Search backward: ") + strlen(search_string));
263 (k > 0); --k)
264 (void)fputc(' ',fpout); /* erase the search line */
265 (void)fputc('\r',fpout);
266
267 (void)fflush(fpout);
268
269 #if defined(DEBUG)
270 (void)sleep(1); /* DEBUG delay */
271 #endif
272
273 if (code == KEYBOARD_SEARCH_BACKWARD)
274 line_number = MAX(0,line_number - pause_after);
275 else
276 line_number++;
277 while ((line_number >= 0) &&
278 (lines[line_number] != (const char*)NULL))
279 {
280 if (stristr(lines[line_number],search_string) != (char*)NULL)
281 break;
282 else if (code == KEYBOARD_SEARCH_BACKWARD)
283 line_number--;
284 else
285 line_number++;
286 }
287 if ((line_number < 0) || (lines[line_number] == (const char*)NULL))
288 { /* then search failed */
289 beep(fpout);
290 line_number = MAX(0,last_line_number + 1 - pause_after);
291 }
292 return (line_number);
293 }
294
295
296 static void
297 #if defined(HAVE_STDC)
erase_characters(FILE * fpout,int how_many)298 erase_characters(FILE *fpout, int how_many)
299 #else
300 erase_characters(fpout, how_many)
301 FILE *fpout;
302 int how_many;
303 #endif
304 {
305 for ( ; how_many > 0; --how_many)
306 {
307 (void)fputc(CH_BACKSPACE,fpout);
308 (void)fputc(' ',fpout);
309 (void)fputc(CH_BACKSPACE,fpout);
310 }
311 (void)fflush(fpout);
312 }
313
314
315 #if OS_PCDOS
316
317 #if defined(HAVE_CONIO_H)
318 #include <conio.h> /* needed for getch() declaration */
319 #endif
320
321 int
get_screen_lines(VOID)322 get_screen_lines(VOID)
323 {
324 return (SCREEN_LINES);
325 }
326
327
328 void
kbclose(VOID)329 kbclose(VOID)
330 {
331 }
332
333
334 static keyboard_code_t
kbcode(VOID)335 kbcode(VOID)
336 {
337 int c;
338
339 c = kbget(); /* get from keyboard without echo */
340 if ((c == 0) || (c == 0xe0)) /* then have IBM PC function key */
341 {
342 c = kbget(); /* function key code */
343 switch (c) /* convert key code to character */
344 {
345 case 71: /* HOME */
346 return (KEYBOARD_HOME);
347
348 case 72: /* UP arrow */
349 return (KEYBOARD_UP);
350
351 case 73: /* PGUP */
352 return (KEYBOARD_PGUP);
353
354 case 79: /* END */
355 return (KEYBOARD_END);
356
357 case 80: /* DOWN arrow */
358 return (KEYBOARD_DOWN);
359
360 case 81: /* PGDN */
361 return (KEYBOARD_PGDN);
362
363 default:
364 return (KEYBOARD_UNKNOWN);
365 }
366 }
367 else if (c == EOF)
368 return (KEYBOARD_EOF);
369 else
370 return (keymap[(unsigned)c]);
371 }
372
373
374 static int
kbget(VOID)375 kbget(VOID)
376 {
377 return (getch());
378 }
379
380
381 void
kbopen(VOID)382 kbopen(VOID)
383 {
384 kbinitmap();
385 }
386 #endif /* OS_PCDOS */
387
388
389 #if OS_UNIX
390
391 static void reset_terminal ARGS((void));
392 static void set_terminal ARGS((void));
393
394 static FILE *fptty = (FILE*)NULL; /* for kbxxx() functions */
395 static YESorNO tty_init = NO; /* set to YES if tty_save set */
396
397
398 void
kbclose(VOID)399 kbclose(VOID)
400 {
401 reset_terminal();
402 if (fptty != (FILE*)NULL)
403 (void)fclose(fptty);
404 }
405
406
407 keyboard_code_t
kbcode(VOID)408 kbcode(VOID)
409 {
410 int c = kbget();
411
412 if (c == EOF)
413 return (KEYBOARD_EOF);
414 else if (c == CH_ESCAPE)
415 { /* handle some X Window System keys */
416 c = kbget();
417 if (c == (int)'[') /* ']' for balance */
418 {
419 c = kbget();
420 if (c == (int)'A') /* "\e[A" ("]" for balance) */
421 return (KEYBOARD_UP);
422 else if (c == (int)'B') /* "\e[B" ("]" for balance) */
423 return (KEYBOARD_DOWN);
424 else if (c == (int)'C') /* "\e[C" ("]" for balance) */
425 return (KEYBOARD_END);
426 else if (c == (int)'D') /* "\e[D" ("]" for balance) */
427 return (KEYBOARD_HOME);
428 else if ((c == (int)'5') && (kbget() == (int)'~')) /* "\e[5~" ("]" for balance) */
429 return (KEYBOARD_PGUP);
430 else if ((c == (int)'6') && (kbget() == (int)'~')) /* "\e[6~" ("]" for balance) */
431 return (KEYBOARD_PGDN);
432 }
433 return (KEYBOARD_UNKNOWN);
434 }
435 else
436 return (keymap[(unsigned)c]);
437 }
438
439
440 int
kbget(VOID)441 kbget(VOID)
442 {
443 if (fptty != (FILE*)NULL)
444 {
445 #if 0 /* fflush() discards typeahead -- no good for search string input */
446 (void)fflush(fptty);
447 #endif
448 return (getc(fptty));
449 }
450 else
451 return (EOF);
452 }
453
454
455 void
kbopen(VOID)456 kbopen(VOID)
457 {
458 kbinitmap();
459 if ((fptty = tfopen("/dev/tty","r")) != (FILE*)NULL)
460 {
461 set_terminal();
462 screen_lines = get_screen_lines();
463 }
464 }
465
466
467 #if defined(HAVE_TERMIO_H)
468 #include <termio.h>
469 static struct termio tty_save; /* SVID2 and XPG2 interface */
470
471 static void
reset_terminal(VOID)472 reset_terminal(VOID) /* restore saved modes */
473 {
474 if (tty_init == YES)
475 (void)ioctl((int)(fileno(fptty)),(int)TCSETAF,(char*)&tty_save);
476 }
477
478
479 static void
set_terminal(VOID)480 set_terminal(VOID) /* set to cbreak input mode */
481 {
482 struct termio tty; /* SVID2, XPG2 interface */
483
484 if (ioctl((int)(fileno(fptty)),(int)TCGETA,(char*)&tty) != -1)
485 {
486 tty_save = tty;
487 tty_init = YES;
488 tty.c_iflag &= ~(INLCR | ICRNL | ISTRIP | IXON | BRKINT);
489
490 #if defined(IUCLC)
491 tty.c_iflag &= ~IUCLC; /* absent from POSIX */
492 #endif /* defined(IUCLC) */
493
494 tty.c_lflag &= ~(ECHO | ICANON);
495 tty.c_cc[4] = 5; /* MIN */
496 tty.c_cc[5] = 2; /* TIME */
497 (void)ioctl((int)(fileno(fptty)),(int)TCSETAF,(char*)&tty);
498 }
499 }
500 #endif /* HAVE_TERMIO_H */
501
502
503 #if defined(HAVE_TERMIOS_H)
504 #include <termios.h>
505 static struct termios tty_save; /* XPG3, POSIX.1, FIPS 151-1 interface */
506
507 static void
reset_terminal(VOID)508 reset_terminal(VOID) /* restore saved modes */
509 {
510 if (tty_init == YES)
511 (void)tcsetattr((int)(fileno(fptty)),TCSANOW,&tty_save);
512 }
513
514
515 static void
set_terminal(VOID)516 set_terminal(VOID) /* set to cbreak input mode */
517 {
518 struct termios tty; /* XPG3, POSIX.1, FIPS 151-1 interface */
519
520 if (tcgetattr((int)(fileno(fptty)),&tty) != -1)
521 {
522 tty_save = tty;
523 tty_init = YES;
524 tty.c_iflag &= ~(INLCR | ICRNL | ISTRIP | IXON | BRKINT);
525
526 #if defined(IUCLC)
527 tty.c_iflag &= ~IUCLC; /* absent from POSIX */
528 #endif /* defined(IUCLC) */
529
530 tty.c_lflag &= ~(ECHO | ICANON);
531 tty.c_cc[VMIN] = 5; /* MIN */
532 tty.c_cc[VTIME] = 2; /* TIME */
533 (void)tcsetattr((int)(fileno(fptty)),TCSANOW,&tty);
534 }
535 }
536 #endif /* defined(HAVE_TERMIOS_H) */
537
538 #if defined(HAVE_SGTTY_H)
539 #include <sgtty.h>
540
541 static struct sgttyb tty_save; /* Berkeley style interface */
542
543
544 static void
reset_terminal(VOID)545 reset_terminal(VOID) /* restored saved terminal modes */
546 {
547 if (tty_init == YES)
548 (void)ioctl((int)(fileno(fptty)),(int)TIOCSETP,(char*)&tty_save);
549 }
550
551
552 static void
set_terminal(VOID)553 set_terminal(VOID) /* set terminal for cbreak input mode */
554 {
555 struct sgttyb tty;
556
557 /* Try to put file into cbreak mode for character-at-a-time input */
558 if (ioctl((int)(fileno(fptty)),(int)TIOCGETP,(char*)&tty) != -1)
559 {
560 tty_save = tty;
561 tty_init = YES;
562 tty.sg_flags &= ~(ECHO | LCASE);
563 tty.sg_flags |= CBREAK;
564 (void)ioctl((int)(fileno(fptty)),(int)TIOCSETP,(char*)&tty);
565 }
566 }
567 #endif /* defined(HAVE_SGTTY_H) */
568
569 int
get_screen_lines(VOID)570 get_screen_lines(VOID) /* this must come after terminal header includes! */
571 {
572
573 #if defined(HAVE_ISATTY)
574 if ((isatty(fileno(stdin)) == 0) || (isatty(fileno(stdout)) == 0))
575 return (0);
576 #endif
577
578 #if defined(TIOCGWINSZ)
579 if (fptty != (FILE*)NULL)
580 {
581 struct winsize window_size;
582
583 (void)ioctl((int)(fileno(fptty)),(int)TIOCGWINSZ,&window_size);
584
585 if (window_size.ws_row > 0)
586 return ((int)window_size.ws_row);
587 }
588 #else /* defined(TIOCGWINSZ) */
589 /* some systems store screen lines in environment variables */
590 {
591 char *p;
592 if (((p = getenv("ROWS")) != (char*)NULL) ||
593 ((p = getenv("LINES")) != (char*)NULL))
594 {
595 int n;
596
597 n = (int)atoi(p);
598
599 if (n > 0)
600 return (n);
601 }
602 }
603 #endif /* defined(TIOCGWINSZ) */
604
605 return (SCREEN_LINES);
606 }
607 #endif /* OS_UNIX */
608
609
610 #if OS_VAXVMS
611
612 #if defined(HAVE_SSDEF_H)
613 #include <ssdef.h>
614 #endif
615
616 #if defined(HAVE_DESCRIP_H)
617 #include <descrip.h>
618 #endif
619
620 #if defined(HAVE_IODEF_H)
621 #include <iodef.h>
622 #endif
623
624 #if defined(HAVE_TTDEF_H)
625 #include <ttdef.h>
626 #endif
627
628 #if defined(HAVE_TT2DEF_H)
629 #include <tt2def.h>
630 #endif
631
632 #if defined(__ALPHA)
633 int sys$assign(void *desc_,int *channel_,int n1_,int n2_);
634 int sys$qiow(int, int channel_, int flags_, int n1_, int n2_, int n3_,
635 int *ret_char_, int n4_, int n5_, int n6_, int n7_, int n8_);
636 int system(const char *s_);
637 #else
638 /* VAX VMS 6.1 has these header files */
639 #include <starlet.h> /* for sys$assign(), sys$qiow() */
640 #endif
641
642 extern int lib$screen_info ARGS((short *,short *,short *,short *,));
643 /* not defined in any system header */
644 /* file in VMS 6.x */
645
646 static int status; /* system service status */
647 static int tt_channel = -1; /* terminal channel for image QIO's */
648 static int iomask; /* QIO flag mask */
649 static $DESCRIPTOR(sys_in,"TT:"); /* terminal descriptor */
650
651 static struct
652 {
653 unsigned char class;
654 unsigned char type;
655 unsigned short buffer_size;
656 unsigned long tt;
657 unsigned long tt2;
658 } mode_buf,mode_save;
659
660 #define FAILED(status) (~(status) & 1) /* failure if LSB is 0 */
661
662 int
get_screen_lines(VOID)663 get_screen_lines(VOID)
664 {
665 short flags;
666 short dvtype;
667 short ncols;
668 short nrows = 0;
669
670 #if defined(__ALPHA) || defined(__VMS_VERSION)
671 /* I don't know what the OpenVMS replacement for lib$screen_info() is yet. */
672 /* It may be that scr$w_pagesize and scr$w_width in the struct scrdef1 */
673 /* in <scrdef.h> are the values we need for nrows and ncols. */
674 ncols = 80;
675 nrows = 24;
676 #else
677 (void)lib$screen_info(&flags,&dvtype,&ncols,&nrows);
678 #endif
679
680 return ((int)((nrows > 0) ? nrows : SCREEN_LINES));
681 }
682
683
684 void
kbclose(VOID)685 kbclose(VOID)
686 {
687 #if !defined(__ALPHA)
688 (void)sys$qiow(0,tt_channel,IO$_SETMODE,0,0,0, &mode_save,12,0,0,0,0);
689 #endif
690 }
691
692
693 keyboard_code_t
kbcode(VOID)694 kbcode(VOID)
695 {
696 int c = kbget();
697
698 return ((c == EOF) ? KEYBOARD_EOF : keymap[(unsigned)c]);
699 }
700
701
702 int
kbget(VOID)703 kbget(VOID)
704 {
705 #if defined(__ALPHA)
706 return (getchar());
707 #else
708 int c;
709
710 status = sys$qiow(0,tt_channel,iomask,0,0,0,&c,1,0,0,0,0);
711
712 return ((int)(FAILED(status) ? EOF : BYTE_VAL(c)));
713 #endif
714 }
715
716
717 void
kbopen(VOID)718 kbopen(VOID)
719 {
720 kbinitmap();
721 #if defined(__ALPHA)
722 /* assume stdin is open for now */
723 #else
724 status = sys$assign(&sys_in,&tt_channel,0,0);
725 if (!FAILED(status))
726 {
727 (void)sys$qiow(0,tt_channel,IO$_SENSEMODE,0,0,0,&mode_save,12,0,0,0,0);
728 mode_buf = mode_save;
729 mode_buf.tt &= ~TT$M_WRAP;
730 (void)sys$qiow(0,tt_channel,IO$_SETMODE,0,0,0,&mode_buf,12,0,0,0,0);
731 iomask = IO$_TTYREADALL | IO$M_NOECHO;
732 }
733 #endif
734 }
735 #endif /* OS_VAXVMS */
736
737
738 static void
kbinitmap(VOID)739 kbinitmap(VOID)
740 {
741 (void)Memset((void*)&keymap[0],(int)KEYBOARD_UNKNOWN,sizeof(keymap));
742
743 keymap[(unsigned)'b'] = KEYBOARD_PGUP;
744 keymap[(unsigned)'B'] = KEYBOARD_PGUP;
745 keymap[(unsigned)META('V')] = KEYBOARD_PGUP; /* Emacs scroll-down */
746
747 keymap[(unsigned)'\r'] = KEYBOARD_DOWN; /* the less and more pagers bind */
748 keymap[(unsigned)'\n'] = KEYBOARD_DOWN; /* these keys to KEYBOARD_DOWN */
749 keymap[(unsigned)'d'] = KEYBOARD_DOWN;
750 keymap[(unsigned)'D'] = KEYBOARD_DOWN;
751 keymap[(unsigned)CTL('N')] = KEYBOARD_DOWN; /* Emacs next-line*/
752
753 keymap[(unsigned)'e'] = KEYBOARD_END;
754 keymap[(unsigned)'E'] = KEYBOARD_END;
755 keymap[(unsigned)META('>')] = KEYBOARD_END; /* Emacs end-of-buffer */
756 keymap[(unsigned)'>'] = KEYBOARD_END;
757
758 keymap[(unsigned)'f'] = KEYBOARD_PGDN;
759 keymap[(unsigned)'F'] = KEYBOARD_PGDN;
760 keymap[(unsigned)' '] = KEYBOARD_PGDN;
761 keymap[(unsigned)CTL('V')] = KEYBOARD_PGDN; /* Emacs scroll-up */
762
763 keymap[(unsigned)'h'] = KEYBOARD_HELP;
764 keymap[(unsigned)'H'] = KEYBOARD_HELP;
765 keymap[(unsigned)'?'] = KEYBOARD_HELP;
766 keymap[(unsigned)CH_BACKSPACE] = KEYBOARD_HELP; /* Emacs help */
767
768 keymap[(unsigned)CH_ESCAPE] = KEYBOARD_QUIT; /* ESCape gets out */
769 keymap[(unsigned)'q'] = KEYBOARD_QUIT;
770 keymap[(unsigned)'Q'] = KEYBOARD_QUIT;
771
772 keymap[(unsigned)'.'] = KEYBOARD_AGAIN;
773 keymap[(unsigned)'r'] = KEYBOARD_AGAIN;
774 keymap[(unsigned)'R'] = KEYBOARD_AGAIN;
775 keymap[(unsigned)CTL('L')] = KEYBOARD_AGAIN; /* Emacs recenter */
776
777 keymap[(unsigned)'t'] = KEYBOARD_HOME;
778 keymap[(unsigned)'T'] = KEYBOARD_HOME;
779 keymap[(unsigned)META('<')] = KEYBOARD_HOME; /* Emacs beginning-of-buffer */
780 keymap[(unsigned)'<'] = KEYBOARD_HOME;
781
782 keymap[(unsigned)CTL('R')] = KEYBOARD_SEARCH_BACKWARD; /* Emacs */
783 keymap[(unsigned)'\\'] = KEYBOARD_SEARCH_BACKWARD;
784
785 keymap[(unsigned)CTL('S')] = KEYBOARD_SEARCH_FORWARD; /* Emacs */
786 keymap[(unsigned)'/'] = KEYBOARD_SEARCH_FORWARD;
787
788 keymap[(unsigned)'u'] = KEYBOARD_UP;
789 keymap[(unsigned)'U'] = KEYBOARD_UP;
790 keymap[(unsigned)CTL('P')] = KEYBOARD_UP; /* Emacs previous-line */
791
792 keymap[(unsigned)'['] = KEYBOARD_UP_PARAGRAPH;
793 keymap[(unsigned)']'] = KEYBOARD_DOWN_PARAGRAPH;
794
795 keymap[(unsigned)'{'] = KEYBOARD_UP_PARAGRAPH;
796 keymap[(unsigned)'}'] = KEYBOARD_DOWN_PARAGRAPH;
797 }
798
799 #endif /* (SCREEN_LINES > 0) */
800