OSDN Git Service

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