OSDN Git Service

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