OSDN Git Service

Replace sprintf() simply. Does part of the work to resolve https://github.com/hengba...
[hengbandforosx/hengbandosx.git] / src / main-cap.cpp
1 /* File: main-cap.c */
2
3 /* Purpose: Support for "term.c" using "termcap" calls */
4
5 #include "io/exit-panic.h"
6 #include "system/angband.h"
7 #include "term/z-form.h"
8
9 #ifdef USE_CAP
10
11 /*
12  * This file is a total hack, but is often very helpful.  :-)
13  *
14  * This file allows use of the terminal without requiring the
15  * "curses" routines.  In fact, if "USE_HARDCODE" is defined,
16  * this file will attempt to use various hard-coded "vt100"
17  * escape sequences to also avoid the use of the "termcap"
18  * routines.  I do not know if this will work on System V.
19  *
20  * This file is intended for use only on those machines which are
21  * unable, for whatever reason, to compile the "main-gcu.c" file,
22  * but which seem to be able to support the "termcap" library, or
23  * which at least seem able to support "vt100" terminals.
24  *
25  * Large portions of this file were stolen from "main-gcu.c"
26  *
27  * This file incorrectly handles output to column 80, I think.
28  */
29
30 /*
31  * Require a "system"
32  */
33 #if !defined(USE_TERMCAP) && !defined(USE_HARDCODE)
34 #define USE_TERMCAP
35 #endif
36
37 /*
38  * Hack -- try to guess which systems use what commands
39  * Hack -- allow one of the "USE_Txxxxx" flags to be pre-set.
40  * Mega-Hack -- try to guess when "POSIX" is available.
41  * If the user defines two of these, we will probably crash.
42  */
43 #ifdef _POSIX_VERSION
44 #define USE_TPOSIX
45 #else
46 #define USE_TCHARS
47 #endif
48
49 /*
50  * POSIX stuff
51  */
52 #ifdef USE_TPOSIX
53 #include <sys/ioctl.h>
54 #include <termios.h>
55 #endif
56
57 /*
58  * One version needs these files
59  */
60 #ifdef USE_TERMIO
61 #include <sys/ioctl.h>
62 #include <termio.h>
63 #endif
64
65 /*
66  * The other needs these files
67  */
68 #ifdef USE_TCHARS
69 #include <sys/file.h>
70 #include <sys/ioctl.h>
71 #include <sys/param.h>
72 #include <sys/resource.h>
73 #include <sys/types.h>
74 #endif
75
76 /*
77  * XXX XXX Hack -- POSIX uses "O_NONBLOCK" instead of "O_NDELAY"
78  *
79  * They should both work due to the "(i != 1)" test in the code
80  * which checks for the result of the "read()" command.
81  */
82 #ifndef O_NDELAY
83 #define O_NDELAY O_NONBLOCK
84 #endif
85
86 #ifdef USE_TERMCAP
87
88 /*
89  * Termcap string information
90  */
91
92 static char blob[1024]; /* The "termcap" entry */
93 static char area[1024]; /* The string extraction buffer */
94 static char *next = area; /* The current "index" into "area" */
95 static char *desc; /* The terminal name */
96
97 #endif
98
99 /*
100  * Pointers into the "area"
101  */
102
103 static char *cm; /* Move cursor */
104 static char *ch; /* Move cursor to horizontal location */
105 static char *cv; /* Move cursor to vertical location */
106 static char *ho; /* Move cursor to top left */
107 static char *ll; /* Move cursor to bottom left */
108 static char *cs; /* Set scroll area */
109 static char *cl; /* Clear screen */
110 static char *cd; /* Clear to end of display */
111 static char *ce; /* Clear to end of line */
112 static char *cr; /* Move to start of line */
113 static char *so; /* Turn on standout */
114 static char *se; /* Turn off standout */
115 static char *md; /* Turn on bold */
116 static char *me; /* Turn off bold */
117 static char *vi; /* Cursor - invisible */
118 static char *ve; /* Cursor - normal */
119 static char *vs; /* Cursor - bright */
120
121 /*
122  * State variables
123  */
124
125 static int rows; /* Screen size (Y) */
126 static int cols; /* Screen size (X) */
127 static int curx; /* Cursor location (X) */
128 static int cury; /* Cursor location (Y) */
129 static int curv; /* Cursor visibility */
130
131 /*
132  * Extern functions
133  */
134 extern char *getenv();
135 extern char *tgoto();
136 extern char *tgetstr();
137
138 /*
139  * Write some chars to the terminal
140  */
141 static void ewrite(char *str)
142 {
143     int numtowrite, numwritten;
144
145     /* See how much work we have */
146     numtowrite = strlen(str);
147
148     /* Write until done */
149     while (numtowrite > 0) {
150         /* Try to write the chars */
151         numwritten = write(1, str, numtowrite);
152
153         /* Handle FIFOs and EINTR */
154         if (numwritten < 0) {
155             numwritten = 0;
156         }
157
158         /* See what we completed */
159         numtowrite -= numwritten;
160         str += numwritten;
161
162         /* Hack -- sleep if not done */
163         if (numtowrite > 0) {
164             sleep(1);
165         }
166     }
167 }
168
169 #ifdef USE_TERMCAP
170
171 static char write_buffer[128];
172 static char *write_buffer_ptr;
173
174 static void output_one(char c)
175 {
176     *write_buffer_ptr++ = c;
177 }
178
179 static void tp(char *s)
180 {
181     /* Dump the string into us */
182     write_buffer_ptr = write_buffer;
183
184     /* Write the string with padding */
185     tputs(s, 1, output_one);
186
187     /* Finish the string */
188     *write_buffer_ptr = '\0';
189
190     /* Dump the recorded buffer */
191     ewrite(write_buffer);
192 }
193
194 #endif
195
196 #ifdef USE_HARDCODE
197
198 static void tp(char *s)
199 {
200     ewrite(s);
201 }
202
203 #endif
204
205 /*
206  * Clear the screen
207  */
208 static void do_cl(void)
209 {
210     if (cl) {
211         tp(cl);
212     }
213 }
214
215 /*
216  * Clear to the end of the line
217  */
218 static void do_ce(void)
219 {
220     if (ce) {
221         tp(ce);
222     }
223 }
224
225 /*
226  * Set the cursor visibility (0 = invis, 1 = normal, 2 = bright)
227  */
228 static void curs_set(int vis)
229 {
230     char *v = nullptr;
231
232     if (!vis) {
233         v = vi;
234     } else if (vis > 1) {
235         v = vs ? vs : ve;
236     } else {
237         v = ve ? ve : vs;
238     }
239
240     if (v) {
241         tp(v);
242     }
243 }
244
245 /*
246  * Restrict scrolling to within these rows
247  */
248 static void do_cs(int y1, int y2)
249 {
250
251 #ifdef USE_TERMCAP
252     if (cs) {
253         tp(tgoto(cs, y2, y1));
254     }
255 #endif
256
257 #ifdef USE_HARDCODE
258     char temp[64];
259     strnfmt(temp, sizeof(temp), cs, y1, y2);
260     tp(temp);
261 #endif
262 }
263
264 /*
265  * Go to the given screen location directly
266  */
267 static void do_cm(int x, int y)
268 {
269
270 #ifdef USE_TERMCAP
271     if (cm) {
272         tp(tgoto(cm, x, y));
273     }
274 #endif
275
276 #ifdef USE_HARDCODE
277     char temp[64];
278     strnfmt(temp, sizeof(temp), cm, y + 1, x + 1);
279     tp(temp);
280 #endif
281 }
282
283 /*
284  * Go to the given screen location in a "clever" manner
285  *
286  * XXX XXX XXX This function could use some work!
287  */
288 static void do_move(int x1, int y1, int x2, int y2)
289 {
290     /* Hack -- unknown start location */
291     if ((x1 == x2) && (y1 == y2)) {
292         do_cm(x2, y2);
293     }
294
295     /* Left edge */
296     else if (x2 == 0) {
297         if ((y2 <= 0) && ho) {
298             tp(ho);
299         } else if ((y2 >= rows - 1) && ll) {
300             tp(ll);
301         } else if ((y2 == y1) && cr) {
302             tp(cr);
303         } else {
304             do_cm(x2, y2);
305         }
306     }
307
308     /* Default -- go directly there */
309     else {
310         do_cm(x2, y2);
311     }
312 }
313
314 /*
315  * Help initialize this file (see below)
316  */
317 errr init_cap_aux(void)
318 {
319
320 #ifdef USE_TERMCAP
321
322     /* Get the terminal name (if possible) */
323     desc = getenv("TERM");
324     if (!desc) {
325         return 1;
326     }
327
328     /* Get the terminal info */
329     if (tgetent(blob, desc) != 1) {
330         return 2;
331     }
332
333     /* Get the (initial) columns and rows, or default */
334     if ((cols = tgetnum("co")) == -1) {
335         cols = 80;
336     }
337     if ((rows = tgetnum("li")) == -1) {
338         rows = 24;
339     }
340
341     /* Find out how to move the cursor to a given location */
342     cm = tgetstr("cm", &next);
343     if (!cm) {
344         return 10;
345     }
346
347     /* Find out how to move the cursor to a given position */
348     ch = tgetstr("ch", &next);
349     cv = tgetstr("cv", &next);
350
351     /* Find out how to "home" the screen */
352     ho = tgetstr("ho", &next);
353
354     /* Find out how to "last-line" the screen */
355     ll = tgetstr("ll", &next);
356
357     /* Find out how to do a "carriage return" */
358     cr = tgetstr("cr", &next);
359     if (!cr) {
360         cr = "\r";
361     }
362
363     /* Find out how to clear the screen */
364     cl = tgetstr("cl", &next);
365     if (!cl) {
366         return 11;
367     }
368
369     /* Find out how to clear to the end of display */
370     cd = tgetstr("cd", &next);
371
372     /* Find out how to clear to the end of the line */
373     ce = tgetstr("ce", &next);
374
375     /* Find out how to scroll (set the scroll region) */
376     cs = tgetstr("cs", &next);
377
378     /* Find out how to hilite */
379     so = tgetstr("so", &next);
380     se = tgetstr("se", &next);
381     if (!so || !se) {
382         so = se = nullptr;
383     }
384
385     /* Find out how to bold */
386     md = tgetstr("md", &next);
387     me = tgetstr("me", &next);
388     if (!md || !me) {
389         md = me = nullptr;
390     }
391
392     /* Check the cursor visibility stuff */
393     vi = tgetstr("vi", &next);
394     vs = tgetstr("vs", &next);
395     ve = tgetstr("ve", &next);
396
397 #endif
398
399 #ifdef USE_HARDCODE
400
401     /* Assume some defualt information */
402     rows = 24;
403     cols = 80;
404
405     /* Clear screen */
406     cl = "\033[2J\033[H"; /* --]--]-- */
407
408     /* Clear to end of line */
409     ce = "\033[K"; /* --]-- */
410
411     /* Hilite on/off */
412     so = "\033[7m"; /* --]-- */
413     se = "\033[m"; /* --]-- */
414
415     /* Scroll region */
416     cs = "\033[%d;%dr"; /* --]-- */
417
418     /* Move cursor */
419     cm = "\033[%d;%dH"; /* --]-- */
420
421 #endif
422
423     /* Success */
424     return 0;
425 }
426
427 /*
428  * Save the "normal" and "angband" terminal settings
429  */
430
431 #ifdef USE_TPOSIX
432
433 static struct termios norm_termios;
434
435 static struct termios game_termios;
436
437 #endif
438
439 #ifdef USE_TERMIO
440
441 static struct termio norm_termio;
442
443 static struct termio game_termio;
444
445 #endif
446
447 #ifdef USE_TCHARS
448
449 static struct sgttyb norm_ttyb;
450 static struct tchars norm_tchars;
451 static struct ltchars norm_ltchars;
452 static int norm_local_chars;
453
454 static struct sgttyb game_ttyb;
455 static struct tchars game_tchars;
456 static struct ltchars game_ltchars;
457 static int game_local_chars;
458
459 #endif
460
461 /*
462  * Are we active?  Not really needed.
463  */
464 static int active = false;
465
466 /*
467  * The main screen (no sub-screens)
468  */
469 static term term_screen_body;
470
471 /*
472  * Place the "keymap" into its "normal" state
473  */
474 static void keymap_norm(void)
475 {
476
477 #ifdef USE_TPOSIX
478
479     /* restore the saved values of the special chars */
480     (void)tcsetattr(0, TCSAFLUSH, &norm_termios);
481
482 #endif
483
484 #ifdef USE_TERMIO
485
486     /* restore the saved values of the special chars */
487     (void)ioctl(0, TCSETA, (char *)&norm_termio);
488
489 #endif
490
491 #ifdef USE_TCHARS
492
493     /* restore the saved values of the special chars */
494     (void)ioctl(0, TIOCSETP, (char *)&norm_ttyb);
495     (void)ioctl(0, TIOCSETC, (char *)&norm_tchars);
496     (void)ioctl(0, TIOCSLTC, (char *)&norm_ltchars);
497     (void)ioctl(0, TIOCLSET, (char *)&norm_local_chars);
498
499 #endif
500 }
501
502 /*
503  * Place the "keymap" into the "game" state
504  */
505 static void keymap_game(void)
506 {
507
508 #ifdef USE_TPOSIX
509
510     /* restore the saved values of the special chars */
511     (void)tcsetattr(0, TCSAFLUSH, &game_termios);
512
513 #endif
514
515 #ifdef USE_TERMIO
516
517     /* restore the saved values of the special chars */
518     (void)ioctl(0, TCSETA, (char *)&game_termio);
519
520 #endif
521
522 #ifdef USE_TCHARS
523
524     /* restore the saved values of the special chars */
525     (void)ioctl(0, TIOCSETP, (char *)&game_ttyb);
526     (void)ioctl(0, TIOCSETC, (char *)&game_tchars);
527     (void)ioctl(0, TIOCSLTC, (char *)&game_ltchars);
528     (void)ioctl(0, TIOCLSET, (char *)&game_local_chars);
529
530 #endif
531 }
532
533 /*
534  * Save the normal keymap
535  */
536 static void keymap_norm_prepare(void)
537 {
538
539 #ifdef USE_TPOSIX
540
541     /* Get the normal keymap */
542     tcgetattr(0, &norm_termios);
543
544 #endif
545
546 #ifdef USE_TERMIO
547
548     /* Get the normal keymap */
549     (void)ioctl(0, TCGETA, (char *)&norm_termio);
550
551 #endif
552
553 #ifdef USE_TCHARS
554
555     /* Get the normal keymap */
556     (void)ioctl(0, TIOCGETP, (char *)&norm_ttyb);
557     (void)ioctl(0, TIOCGETC, (char *)&norm_tchars);
558     (void)ioctl(0, TIOCGLTC, (char *)&norm_ltchars);
559     (void)ioctl(0, TIOCLGET, (char *)&norm_local_chars);
560
561 #endif
562 }
563
564 /*
565  * Save the keymaps (normal and game)
566  */
567 static void keymap_game_prepare(void)
568 {
569
570 #ifdef USE_TPOSIX
571
572     /* Acquire the current mapping */
573     tcgetattr(0, &game_termios);
574
575     /* Force "Ctrl-C" to interupt */
576     game_termios.c_cc[VINTR] = (char)3;
577
578     /* Force "Ctrl-Z" to suspend */
579     game_termios.c_cc[VSUSP] = (char)26;
580
581     /* Hack -- Leave "VSTART/VSTOP" alone */
582
583     /* Disable the standard control characters */
584     game_termios.c_cc[VQUIT] = (char)-1;
585     game_termios.c_cc[VERASE] = (char)-1;
586     game_termios.c_cc[VKILL] = (char)-1;
587     game_termios.c_cc[VEOF] = (char)-1;
588     game_termios.c_cc[VEOL] = (char)-1;
589
590     /* Normally, block until a character is read */
591     game_termios.c_cc[VMIN] = 1;
592     game_termios.c_cc[VTIME] = 0;
593
594     /* Hack -- Turn off "echo" and "canonical" mode */
595     game_termios.c_lflag &= ~(ECHO | ICANON);
596
597     /* Turn off flow control */
598     game_termios.c_iflag &= ~IXON;
599
600 #endif
601
602 #ifdef USE_TERMIO
603
604     /* Acquire the current mapping */
605     (void)ioctl(0, TCGETA, (char *)&game_termio);
606
607     /* Force "Ctrl-C" to interupt */
608     game_termio.c_cc[VINTR] = (char)3;
609
610     /* Force "Ctrl-Z" to suspend */
611     game_termio.c_cc[VSUSP] = (char)26;
612
613     /* Hack -- Leave "VSTART/VSTOP" alone */
614
615     /* Disable the standard control characters */
616     game_termio.c_cc[VQUIT] = (char)-1;
617     game_termio.c_cc[VERASE] = (char)-1;
618     game_termio.c_cc[VKILL] = (char)-1;
619     game_termio.c_cc[VEOF] = (char)-1;
620     game_termio.c_cc[VEOL] = (char)-1;
621
622     /* Normally, block until a character is read */
623     game_termio.c_cc[VMIN] = 1;
624     game_termio.c_cc[VTIME] = 0;
625
626     /* Hack -- Turn off "echo" and "canonical" mode */
627     game_termio.c_lflag &= ~(ECHO | ICANON);
628
629     /* Turn off flow control */
630     game_termio.c_iflag &= ~IXON;
631
632 #endif
633
634 #ifdef USE_TCHARS
635
636     /* Get the default game characters */
637     (void)ioctl(0, TIOCGETP, (char *)&game_ttyb);
638     (void)ioctl(0, TIOCGETC, (char *)&game_tchars);
639     (void)ioctl(0, TIOCGLTC, (char *)&game_ltchars);
640     (void)ioctl(0, TIOCLGET, (char *)&game_local_chars);
641
642     /* Force interupt (^C) */
643     game_tchars.t_intrc = (char)3;
644
645     /* Force start/stop (^Q, ^S) */
646     game_tchars.t_startc = (char)17;
647     game_tchars.t_stopc = (char)19;
648
649     /* Cancel some things */
650     game_tchars.t_quitc = (char)-1;
651     game_tchars.t_eofc = (char)-1;
652     game_tchars.t_brkc = (char)-1;
653
654     /* Force suspend (^Z) */
655     game_ltchars.t_suspc = (char)26;
656
657     /* Cancel some things */
658     game_ltchars.t_dsuspc = (char)-1;
659     game_ltchars.t_rprntc = (char)-1;
660     game_ltchars.t_flushc = (char)-1;
661     game_ltchars.t_werasc = (char)-1;
662     game_ltchars.t_lnextc = (char)-1;
663
664     /* XXX XXX XXX XXX Verify this before use */
665     /* Hack -- Turn off "echo" and "canonical" mode */
666     /* game_termios.c_lflag &= ~(ECHO | ICANON); */
667     game_ttyb.flag &= ~(ECHO | ICANON);
668
669     /* XXX XXX XXX  Should maybe turn off flow control too.  How? */
670
671 #endif
672 }
673
674 /*
675  * Suspend/Resume
676  */
677 static errr game_term_xtra_cap_alive(int v)
678 {
679     /* Suspend */
680     if (!v) {
681         if (!active) {
682             return 1;
683         }
684
685         /* Hack -- make sure the cursor is visible */
686         curs_set(1);
687
688         /* Move to bottom right */
689         do_move(0, rows - 1, 0, rows - 1);
690
691         /* Go to normal keymap mode */
692         keymap_norm();
693
694         /* No longer active */
695         active = false;
696     }
697
698     /* Resume */
699     else {
700         if (active) {
701             return 1;
702         }
703
704         /* Hack -- restore the cursor location */
705         do_move(curx, cury, curx, cury);
706
707         /* Hack -- restore the cursor visibility */
708         curs_set(curv);
709
710         /* Go to angband keymap mode */
711         keymap_game();
712
713         /* Now we are active */
714         active = true;
715     }
716
717     /* Success */
718     return 0;
719 }
720
721 /*
722  * Process an event
723  */
724 static errr game_term_xtra_cap_event(int v)
725 {
726     int i, arg;
727     char buf[2];
728
729     /* Wait */
730     if (v) {
731         /* Wait for one byte */
732         i = read(0, buf, 1);
733
734         /* Hack -- Handle "errors" */
735         if ((i <= 0) && (errno != EINTR)) {
736             exit_game_panic(p_ptr);
737         }
738     }
739
740     /* Do not wait */
741     else {
742         /* Get the current flags for stdin */
743         if ((arg = fcntl(0, F_GETFL, 0)) < 1) {
744             return 1;
745         }
746
747         /* Tell stdin not to block */
748         if (fcntl(0, F_SETFL, arg | O_NDELAY) < 0) {
749             return 1;
750         }
751
752         /* Read one byte, if possible */
753         i = read(0, buf, 1);
754
755         /* Replace the flags for stdin */
756         if (fcntl(0, F_SETFL, arg)) {
757             return 1;
758         }
759     }
760
761     /* No keys ready */
762     if ((i != 1) || (!buf[0])) {
763         return 1;
764     }
765
766     /* Enqueue the keypress */
767     game_term_keypress(buf[0]);
768
769     /* Success */
770     return 0;
771 }
772
773 /*
774  * Actually move the hardware cursor
775  */
776 static errr game_term_curs_cap(int x, int y)
777 {
778     /* Literally move the cursor */
779     do_move(curx, cury, x, y);
780
781     /* Save the cursor location */
782     curx = x;
783     cury = y;
784
785     /* Success */
786     return 0;
787 }
788
789 /*
790  * Erase a grid of space
791  *
792  * XXX XXX XXX Note that we will never be asked to clear the
793  * bottom line all the way to the bottom right edge, since we
794  * have set the "avoid the bottom right corner" flag.
795  */
796 static errr game_term_wipe_cap(int x, int y, int n)
797 {
798     int dx;
799
800     /* Place the cursor */
801     game_term_curs_cap(x, y);
802
803     /* Wipe to end of line */
804     if (x + n >= 80) {
805         do_ce();
806     }
807
808     /* Wipe region */
809     else {
810         for (dx = 0; dx < n; ++dx) {
811             putc(' ', stdout);
812             curx++;
813         }
814     }
815
816     /* Success */
817     return 0;
818 }
819
820 /*
821  * Place some text on the screen using an attribute
822  */
823 static errr game_term_text_cap(int x, int y, int n, byte a, concptr s)
824 {
825     int i;
826
827     /* Move the cursor */
828     game_term_curs_cap(x, y);
829
830     /* Dump the text, advance the cursor */
831     for (i = 0; s[i]; i++) {
832         /* Dump the char */
833         putc(s[i], stdout);
834
835         /* Advance cursor 'X', and wrap */
836         if (++curx >= cols) {
837             /* Reset cursor 'X' */
838             curx = 0;
839
840             /* Hack -- Advance cursor 'Y', and wrap */
841             if (++cury == rows) {
842                 cury = 0;
843             }
844         }
845     }
846
847     /* Success */
848     return 0;
849 }
850
851 /*
852  * Handle a "special request"
853  */
854 static errr game_term_xtra_cap(int n, int v)
855 {
856     /* Analyze the request */
857     switch (n) {
858     /* Clear the screen */
859     case TERM_XTRA_CLEAR:
860         do_cl();
861         do_move(0, 0, 0, 0);
862         return 0;
863
864     /* Make a noise */
865     case TERM_XTRA_NOISE:
866         (void)write(1, "\007", 1);
867         return 0;
868
869     /* Change the cursor visibility */
870     case TERM_XTRA_SHAPE:
871         curv = v;
872         curs_set(v);
873         return 0;
874
875     /* Suspend/Resume */
876     case TERM_XTRA_ALIVE:
877         return game_term_xtra_cap_alive(v);
878
879     /* Process events */
880     case TERM_XTRA_EVENT:
881         return game_term_xtra_cap_event(v);
882
883     /* Flush events */
884     case TERM_XTRA_FLUSH:
885         while (!game_term_xtra_cap_event(false)) {
886             ;
887         }
888         return 0;
889
890     /* Delay */
891     case TERM_XTRA_DELAY:
892         usleep(1000 * v);
893         return 0;
894     }
895
896     /* Not parsed */
897     return 1;
898 }
899
900 /*
901  * Init a "term" for this file
902  */
903 static void game_term_init_cap(term *t)
904 {
905     if (active) {
906         return;
907     }
908
909     /* Assume cursor at top left */
910     curx = 0;
911     cury = 0;
912
913     /* Assume visible cursor */
914     curv = 1;
915
916     /* Clear the screen */
917     do_cl();
918
919     /* Hack -- visible cursor */
920     curs_set(1);
921
922     /* Assume active */
923     active = true;
924 }
925
926 /*
927  * Nuke a "term" for this file
928  */
929 static void game_term_nuke_cap(term *t)
930 {
931     if (!active) {
932         return;
933     }
934
935     /* Hack -- make sure the cursor is visible */
936     curs_set(1);
937
938     /* Move to bottom right */
939     do_move(0, rows - 1, 0, rows - 1);
940
941     /* Normal keymap */
942     keymap_norm();
943
944     /* No longer active */
945     active = false;
946 }
947
948 /*
949  * Prepare this file for Angband usage
950  */
951 errr init_cap(void)
952 {
953     term *t = &term_screen_body;
954
955     /*** Initialize ***/
956
957     /* Initialize the screen */
958     if (init_cap_aux()) {
959         return -1;
960     }
961
962     /* Hack -- Require large screen, or Quit with message */
963     if ((rows < 24) || (cols < 80)) {
964         quit("Screen too small!");
965     }
966
967     /*** Prepare to play ***/
968
969     /* Extract the normal keymap */
970     keymap_norm_prepare();
971
972     /* Extract the game keymap */
973     keymap_game_prepare();
974
975     /* Hack -- activate the game keymap */
976     keymap_game();
977
978     /* Hack -- Do NOT buffer stdout */
979     setbuf(stdout, nullptr);
980
981     /*** Now prepare the term ***/
982
983     /* Initialize the term */
984     term_init(t, 80, 24, 256);
985
986     /* Avoid the bottom right corner */
987     t->icky_corner = true;
988
989     /* Erase with "white space" */
990     t->attr_blank = TERM_WHITE;
991     t->char_blank = ' ';
992
993     /* Set some hooks */
994     t->init_hook = game_term_init_cap;
995     t->nuke_hook = game_term_nuke_cap;
996
997     /* Set some more hooks */
998     t->text_hook = game_term_text_cap;
999     t->wipe_hook = game_term_wipe_cap;
1000     t->curs_hook = game_term_curs_cap;
1001     t->xtra_hook = game_term_xtra_cap;
1002
1003     /* Save the term */
1004     term_screen = t;
1005
1006     /* Activate it */
1007     game_term_activate(term_screen);
1008
1009     /* Success */
1010     return 0;
1011 }
1012
1013 #endif /* USE_CAP */