1 /* SCCS Id: @(#)nttty.c 3.4 $Date: 2003/11/15 00:39:32 $ */
2 /* Copyright (c) NetHack PC Development Team 1993 */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 /* tty.c - (Windows NT) version */
6
7 /*
8 * Initial Creation M. Allison 1993/01/31
9 * Switch to low level console output routines M. Allison 2003/10/01
10 * Restrict cursor movement until input pending M. Lehotay 2003/10/02
11 *
12 */
13
14 #ifdef WIN32CON
15 #define NEED_VARARGS /* Uses ... */
16 #include "hack.h"
17 #include "wintty.h"
18 #include <sys\types.h>
19 #include <sys\stat.h>
20 #include "win32api.h"
21
22 void FDECL(cmov, (int, int));
23 void FDECL(nocmov, (int, int));
24 int FDECL(process_keystroke, (INPUT_RECORD *, boolean *,
25 BOOLEAN_P numberpad, int portdebug));
26
27 /*
28 * The following WIN32 Console API routines are used in this file.
29 *
30 * CreateFile
31 * GetConsoleScreenBufferInfo
32 * GetStdHandle
33 * SetConsoleCursorPosition
34 * SetConsoleTextAttribute
35 * SetConsoleCtrlHandler
36 * PeekConsoleInput
37 * ReadConsoleInput
38 * WriteConsoleOutputCharacter
39 * FillConsoleOutputAttribute
40 */
41
42 /* Win32 Console handles for input and output */
43 HANDLE hConIn;
44 HANDLE hConOut;
45
46 /* Win32 Screen buffer,coordinate,console I/O information */
47 CONSOLE_SCREEN_BUFFER_INFO csbi, origcsbi;
48 COORD ntcoord;
49 INPUT_RECORD ir;
50
51 /* Flag for whether NetHack was launched via the GUI, not the command line.
52 * The reason we care at all, is so that we can get
53 * a final RETURN at the end of the game when launched from the GUI
54 * to prevent the scoreboard (or panic message :-|) from vanishing
55 * immediately after it is displayed, yet not bother when started
56 * from the command line.
57 */
58 int GUILaunched;
59 static BOOL FDECL(CtrlHandler, (DWORD));
60
61 #ifdef PORT_DEBUG
62 static boolean display_cursor_info = FALSE;
63 #endif
64
65 extern boolean getreturn_enabled; /* from sys/share/pcsys.c */
66
67 /* dynamic keystroke handling .DLL support */
68 typedef int (__stdcall * PROCESS_KEYSTROKE)(
69 HANDLE,
70 INPUT_RECORD *,
71 boolean *,
72 BOOLEAN_P,
73 int
74 );
75
76 typedef int (__stdcall * NHKBHIT)(
77 HANDLE,
78 INPUT_RECORD *
79 );
80
81 typedef int (__stdcall * CHECKINPUT)(
82 HANDLE,
83 INPUT_RECORD *,
84 DWORD *,
85 BOOLEAN_P,
86 int,
87 int *,
88 coord *
89 );
90
91 typedef int (__stdcall * SOURCEWHERE)(
92 char **
93 );
94
95 typedef int (__stdcall * SOURCEAUTHOR)(
96 char **
97 );
98
99 typedef int (__stdcall * KEYHANDLERNAME)(
100 char **,
101 int
102 );
103
104 HANDLE hLibrary;
105 PROCESS_KEYSTROKE pProcessKeystroke;
106 NHKBHIT pNHkbhit;
107 CHECKINPUT pCheckInput;
108 SOURCEWHERE pSourceWhere;
109 SOURCEAUTHOR pSourceAuthor;
110 KEYHANDLERNAME pKeyHandlerName;
111
112 #ifndef CLR_MAX
113 #define CLR_MAX 16
114 #endif
115 boolean colorflag = FALSE; /* colors are initialized */
116 int ttycolors[CLR_MAX];
117 # ifdef TEXTCOLOR
118 static void NDECL(init_ttycolor);
119 # endif
120 static void NDECL(really_move_cursor);
121
122 #define MAX_OVERRIDES 256
123 unsigned char key_overrides[MAX_OVERRIDES];
124
125 static char nullstr[] = "";
126 char erase_char,kill_char;
127
128 #define DEFTEXTCOLOR ttycolors[7]
129 static WORD background = 0;
130 static WORD foreground = (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED);
131 static WORD attr = (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED);
132 static DWORD ccount, acount;
133 static COORD cursor = {0,0};
134
135 /*
136 * Called after returning from ! or ^Z
137 */
138 void
gettty()139 gettty()
140 {
141 #ifndef TEXTCOLOR
142 int k;
143 #endif
144 erase_char = '\b';
145 kill_char = 21; /* cntl-U */
146 iflags.cbreak = TRUE;
147 #ifdef TEXTCOLOR
148 init_ttycolor();
149 #else
150 for(k=0; k < CLR_MAX; ++k)
151 ttycolors[k] = 7;
152 #endif
153 }
154
155 /* reset terminal to original state */
156 void
settty(s)157 settty(s)
158 const char *s;
159 {
160 cmov(ttyDisplay->curx, ttyDisplay->cury);
161 end_screen();
162 if(s) raw_print(s);
163 }
164
165 /* called by init_nhwindows() and resume_nhwindows() */
166 void
setftty()167 setftty()
168 {
169 start_screen();
170 }
171
172 void
tty_startup(wid,hgt)173 tty_startup(wid, hgt)
174 int *wid, *hgt;
175 {
176 int twid = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1;
177
178 if (twid > 80) twid = 80;
179 *wid = twid;
180 *hgt = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1;
181 set_option_mod_status("mouse_support", SET_IN_GAME);
182 }
183
184 void
tty_number_pad(state)185 tty_number_pad(state)
186 int state;
187 {
188 }
189
190 void
tty_start_screen()191 tty_start_screen()
192 {
193 if (iflags.num_pad) tty_number_pad(1); /* make keypad send digits */
194 }
195
196 void
tty_end_screen()197 tty_end_screen()
198 {
199 clear_screen();
200 really_move_cursor();
201 if (GetConsoleScreenBufferInfo(hConOut,&csbi))
202 {
203 DWORD ccnt;
204 COORD newcoord;
205
206 newcoord.X = 0;
207 newcoord.Y = 0;
208 FillConsoleOutputAttribute(hConOut,
209 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
210 csbi.dwSize.X * csbi.dwSize.Y,
211 newcoord, &ccnt);
212 FillConsoleOutputCharacter(hConOut,' ',
213 csbi.dwSize.X * csbi.dwSize.Y,
214 newcoord, &ccnt);
215 }
216 FlushConsoleInputBuffer(hConIn);
217 }
218
CtrlHandler(ctrltype)219 static BOOL CtrlHandler(ctrltype)
220 DWORD ctrltype;
221 {
222 switch(ctrltype) {
223 /* case CTRL_C_EVENT: */
224 case CTRL_BREAK_EVENT:
225 clear_screen();
226 case CTRL_CLOSE_EVENT:
227 case CTRL_LOGOFF_EVENT:
228 case CTRL_SHUTDOWN_EVENT:
229 getreturn_enabled = FALSE;
230 #ifndef NOSAVEONHANGUP
231 hangup(0);
232 #endif
233 #if 0
234 clearlocks();
235 terminate(EXIT_FAILURE);
236 #endif
237 default:
238 return FALSE;
239 }
240 }
241
242 /* called by init_tty in wintty.c for WIN32CON port only */
243 void
nttty_open()244 nttty_open()
245 {
246 HANDLE hStdOut;
247 DWORD cmode;
248 long mask;
249
250 load_keyboard_handler();
251 /* Initialize the function pointer that points to
252 * the kbhit() equivalent, in this TTY case nttty_kbhit()
253 */
254 nt_kbhit = nttty_kbhit;
255
256 /* The following 6 lines of code were suggested by
257 * Bob Landau of Microsoft WIN32 Developer support,
258 * as the only current means of determining whether
259 * we were launched from the command prompt, or from
260 * the NT program manager. M. Allison
261 */
262 hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
263 GetConsoleScreenBufferInfo( hStdOut, &origcsbi);
264 GUILaunched = ((origcsbi.dwCursorPosition.X == 0) &&
265 (origcsbi.dwCursorPosition.Y == 0));
266 if ((origcsbi.dwSize.X <= 0) || (origcsbi.dwSize.Y <= 0))
267 GUILaunched = 0;
268
269 /* Obtain handles for the standard Console I/O devices */
270 hConIn = GetStdHandle(STD_INPUT_HANDLE);
271 hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
272 #if 0
273 hConIn = CreateFile("CONIN$",
274 GENERIC_READ |GENERIC_WRITE,
275 FILE_SHARE_READ |FILE_SHARE_WRITE,
276 0, OPEN_EXISTING, 0, 0);
277 hConOut = CreateFile("CONOUT$",
278 GENERIC_READ |GENERIC_WRITE,
279 FILE_SHARE_READ |FILE_SHARE_WRITE,
280 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
281 #endif
282
283 GetConsoleMode(hConIn,&cmode);
284 #ifdef NO_MOUSE_ALLOWED
285 mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
286 ENABLE_MOUSE_INPUT | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;
287 #else
288 mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
289 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;
290 #endif
291 /* Turn OFF the settings specified in the mask */
292 cmode &= ~mask;
293 #ifndef NO_MOUSE_ALLOWED
294 cmode |= ENABLE_MOUSE_INPUT;
295 #endif
296 SetConsoleMode(hConIn,cmode);
297 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE)) {
298 /* Unable to set control handler */
299 cmode = 0; /* just to have a statement to break on for debugger */
300 }
301 get_scr_size();
302 cursor.X = cursor.Y = 0;
303 really_move_cursor();
304 }
305
process_keystroke(ir,valid,numberpad,portdebug)306 int process_keystroke(ir, valid, numberpad, portdebug)
307 INPUT_RECORD *ir;
308 boolean *valid;
309 boolean numberpad;
310 int portdebug;
311 {
312 int ch = pProcessKeystroke(hConIn, ir, valid, numberpad, portdebug);
313 /* check for override */
314 if (ch && ch < MAX_OVERRIDES && key_overrides[ch])
315 ch = key_overrides[ch];
316 return ch;
317 }
318
319 int
nttty_kbhit()320 nttty_kbhit()
321 {
322 return pNHkbhit(hConIn, &ir);
323 }
324
325
326 void
get_scr_size()327 get_scr_size()
328 {
329 GetConsoleScreenBufferInfo(hConOut, &csbi);
330
331 LI = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1);
332 CO = csbi.srWindow.Right - (csbi.srWindow.Left + 1);
333
334 if ( (LI < 25) || (CO < 80) ) {
335 COORD newcoord;
336
337 LI = 25;
338 CO = 80;
339
340 newcoord.Y = LI;
341 newcoord.X = CO;
342
343 SetConsoleScreenBufferSize( hConOut, newcoord );
344 }
345 }
346
347 int
tgetch()348 tgetch()
349 {
350 int mod;
351 coord cc;
352 DWORD count;
353 really_move_cursor();
354 return pCheckInput(hConIn, &ir, &count, iflags.num_pad, 0, &mod, &cc);
355 }
356
357 int
ntposkey(x,y,mod)358 ntposkey(x, y, mod)
359 int *x, *y, *mod;
360 {
361 int ch;
362 coord cc;
363 DWORD count;
364 really_move_cursor();
365 ch = pCheckInput(hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc);
366 if (!ch) {
367 *x = cc.x;
368 *y = cc.y;
369 }
370 return ch;
371 }
372
373 static void
really_move_cursor()374 really_move_cursor()
375 {
376 #if defined(PORT_DEBUG) && defined(WIZARD)
377 char oldtitle[BUFSZ], newtitle[BUFSZ];
378 if (display_cursor_info && wizard) {
379 oldtitle[0] = '\0';
380 if (GetConsoleTitle(oldtitle, BUFSZ)) {
381 oldtitle[39] = '\0';
382 }
383 Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)",
384 oldtitle, ttyDisplay->curx, ttyDisplay->cury,
385 cursor.X, cursor.Y);
386 (void)SetConsoleTitle(newtitle);
387 }
388 #endif
389 if (ttyDisplay) {
390 cursor.X = ttyDisplay->curx;
391 cursor.Y = ttyDisplay->cury;
392 }
393 SetConsoleCursorPosition(hConOut, cursor);
394 }
395
396 void
cmov(x,y)397 cmov(x, y)
398 register int x, y;
399 {
400 ttyDisplay->cury = y;
401 ttyDisplay->curx = x;
402 cursor.X = x;
403 cursor.Y = y;
404 }
405
406 void
nocmov(x,y)407 nocmov(x, y)
408 int x,y;
409 {
410 cursor.X = x;
411 cursor.Y = y;
412 ttyDisplay->curx = x;
413 ttyDisplay->cury = y;
414 }
415
416 void
xputc_core(ch)417 xputc_core(ch)
418 char ch;
419 {
420 switch(ch) {
421 case '\n':
422 cursor.Y++;
423 /* fall through */
424 case '\r':
425 cursor.X = 1;
426 break;
427 case '\b':
428 cursor.X--;
429 break;
430 default:
431 WriteConsoleOutputAttribute(hConOut,&attr,1,
432 cursor,&acount);
433 WriteConsoleOutputCharacter(hConOut,&ch,1,
434 cursor,&ccount);
435 cursor.X++;
436 }
437 }
438
439 void
xputc(ch)440 xputc(ch)
441 char ch;
442 {
443 cursor.X = ttyDisplay->curx;
444 cursor.Y = ttyDisplay->cury;
445 xputc_core(ch);
446 }
447
448 void
xputs(s)449 xputs(s)
450 const char *s;
451 {
452 int k;
453 int slen = strlen(s);
454
455 if (ttyDisplay) {
456 cursor.X = ttyDisplay->curx;
457 cursor.Y = ttyDisplay->cury;
458 }
459
460 if (s) {
461 for (k=0; k < slen && s[k]; ++k)
462 xputc_core(s[k]);
463 }
464 }
465
466
467 /*
468 * Overrides wintty.c function of the same name
469 * for win32. It is used for glyphs only, not text.
470 */
471 void
g_putch(in_ch)472 g_putch(in_ch)
473 int in_ch;
474 {
475 char ch = (char)in_ch;
476
477 cursor.X = ttyDisplay->curx;
478 cursor.Y = ttyDisplay->cury;
479 WriteConsoleOutputAttribute(hConOut,&attr,1,cursor,&acount);
480 WriteConsoleOutputCharacter(hConOut,&ch,1,cursor,&ccount);
481 }
482
483 void
cl_end()484 cl_end()
485 {
486 int cx;
487 cursor.X = ttyDisplay->curx;
488 cursor.Y = ttyDisplay->cury;
489 cx = CO - cursor.X;
490 FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, cursor, &acount);
491 FillConsoleOutputCharacter(hConOut,' ', cx, cursor,&ccount);
492 tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1,
493 (int)ttyDisplay->cury);
494 }
495
496
497 void
clear_screen()498 clear_screen()
499 {
500 if (GetConsoleScreenBufferInfo(hConOut,&csbi)) {
501 DWORD ccnt;
502 COORD newcoord;
503
504 newcoord.X = 0;
505 newcoord.Y = 0;
506 FillConsoleOutputAttribute(hConOut,
507 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
508 csbi.dwSize.X * csbi.dwSize.Y,
509 newcoord, &ccnt);
510 FillConsoleOutputCharacter(hConOut,' ',
511 csbi.dwSize.X * csbi.dwSize.Y,
512 newcoord, &ccnt);
513 }
514 home();
515 }
516
517
518 void
home()519 home()
520 {
521 cursor.X = cursor.Y = 0;
522 ttyDisplay->curx = ttyDisplay->cury = 0;
523 }
524
525
526 void
backsp()527 backsp()
528 {
529 cursor.X = ttyDisplay->curx;
530 cursor.Y = ttyDisplay->cury;
531 xputc_core('\b');
532 }
533
534 void
cl_eos()535 cl_eos()
536 {
537 int cy = ttyDisplay->cury+1;
538 if (GetConsoleScreenBufferInfo(hConOut,&csbi)) {
539 DWORD ccnt;
540 COORD newcoord;
541
542 newcoord.X = ttyDisplay->curx;
543 newcoord.Y = ttyDisplay->cury;
544 FillConsoleOutputAttribute(hConOut,
545 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
546 csbi.dwSize.X * csbi.dwSize.Y - cy,
547 newcoord, &ccnt);
548 FillConsoleOutputCharacter(hConOut,' ',
549 csbi.dwSize.X * csbi.dwSize.Y - cy,
550 newcoord, &ccnt);
551 }
552 tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury);
553 }
554
555 void
tty_nhbell()556 tty_nhbell()
557 {
558 if (flags.silent) return;
559 Beep(8000,500);
560 }
561
562 volatile int junk; /* prevent optimizer from eliminating loop below */
563
564 void
tty_delay_output()565 tty_delay_output()
566 {
567 /* delay 50 ms - uses ANSI C clock() function now */
568 clock_t goal;
569 int k;
570
571 goal = 50 + clock();
572 while (goal > clock()) {
573 k = junk; /* Do nothing */
574 }
575 }
576
577 # ifdef TEXTCOLOR
578 /*
579 * CLR_BLACK 0
580 * CLR_RED 1
581 * CLR_GREEN 2
582 * CLR_BROWN 3 low-intensity yellow
583 * CLR_BLUE 4
584 * CLR_MAGENTA 5
585 * CLR_CYAN 6
586 * CLR_GRAY 7 low-intensity white
587 * NO_COLOR 8
588 * CLR_ORANGE 9
589 * CLR_BRIGHT_GREEN 10
590 * CLR_YELLOW 11
591 * CLR_BRIGHT_BLUE 12
592 * CLR_BRIGHT_MAGENTA 13
593 * CLR_BRIGHT_CYAN 14
594 * CLR_WHITE 15
595 * CLR_MAX 16
596 * BRIGHT 8
597 */
598
599 static void
init_ttycolor()600 init_ttycolor()
601 {
602 ttycolors[CLR_BLACK] = FOREGROUND_INTENSITY; /* fix by Quietust */
603 ttycolors[CLR_RED] = FOREGROUND_RED;
604 ttycolors[CLR_GREEN] = FOREGROUND_GREEN;
605 ttycolors[CLR_BROWN] = FOREGROUND_GREEN|FOREGROUND_RED;
606 ttycolors[CLR_BLUE] = FOREGROUND_BLUE;
607 ttycolors[CLR_MAGENTA] = FOREGROUND_BLUE|FOREGROUND_RED;
608 ttycolors[CLR_CYAN] = FOREGROUND_GREEN|FOREGROUND_BLUE;
609 ttycolors[CLR_GRAY] = FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_BLUE;
610 ttycolors[BRIGHT] = FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED|\
611 FOREGROUND_INTENSITY;
612 ttycolors[CLR_ORANGE] = FOREGROUND_RED|FOREGROUND_INTENSITY;
613 ttycolors[CLR_BRIGHT_GREEN] = FOREGROUND_GREEN|FOREGROUND_INTENSITY;
614 ttycolors[CLR_YELLOW] = FOREGROUND_GREEN|FOREGROUND_RED|\
615 FOREGROUND_INTENSITY;
616 ttycolors[CLR_BRIGHT_BLUE] = FOREGROUND_BLUE|FOREGROUND_INTENSITY;
617 ttycolors[CLR_BRIGHT_MAGENTA] = FOREGROUND_BLUE|FOREGROUND_RED|\
618 FOREGROUND_INTENSITY;
619 ttycolors[CLR_BRIGHT_CYAN] = FOREGROUND_GREEN|FOREGROUND_BLUE|\
620 FOREGROUND_INTENSITY;
621 ttycolors[CLR_WHITE] = FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED|\
622 FOREGROUND_INTENSITY;
623 }
624 # endif /* TEXTCOLOR */
625
626 #ifdef VIDEOSHADES
627 static int FDECL(convert_uchars,(char *, uchar *, int));
628
629 /*
630 * OPTIONS=videocolors:1-2-3-4-5-6-7-8-9-10-11-12-13-14-15
631 * Left to right assignments for:
632 * red green brown blue magenta cyan gray black
633 * orange br.green yellow br.blue br.mag br.cyan white
634 */
assign_videocolors(char * colorvals)635 int assign_videocolors(char *colorvals)
636 {
637 int i,icolor;
638 uchar *tmpcolor;
639
640 init_ttycolor();
641
642 i = strlen(colorvals);
643 tmpcolor = (uchar *)alloc(i);
644 if (convert_uchars(colorvals,tmpcolor,i) < 0) return FALSE;
645
646 icolor = CLR_RED;
647 for( i = 0; tmpcolor[i] != 0; ++i) {
648 if (icolor <= CLR_WHITE)
649 ttycolors[icolor++] = tmpcolor[i];
650 }
651
652 colorflag = TRUE;
653 free((genericptr_t)tmpcolor);
654 return 1;
655 }
656
657 static int
convert_uchars(bufp,list,size)658 convert_uchars(bufp,list,size)
659 char *bufp; /* current pointer */
660 uchar *list; /* return list */
661 int size;
662 {
663 unsigned int num = 0;
664 int count = 0;
665
666 list[count] = 0;
667
668 while (1) {
669 switch(*bufp) {
670 case ' ': case '\0':
671 case '\t': case '-':
672 case '\n':
673 if (num) {
674 list[count++] = num;
675 list[count] = 0;
676 num = 0;
677 }
678 if ((count==size) || !*bufp) return count;
679 bufp++;
680 break;
681 case '#':
682 if (num) {
683 list[count++] = num;
684 list[count] = 0;
685 }
686 return count;
687 case '0': case '1': case '2': case '3':
688 case '4': case '5': case '6': case '7':
689 case '8': case '9':
690 num = num*10 + (*bufp-'0');
691 if (num > 15) return -1;
692 bufp++;
693 break;
694 default: return -1;
695 }
696 }
697 /*NOTREACHED*/
698 }
699 #endif /* !VIDEOSHADES */
700
701
702 int
has_color(int color)703 has_color(int color)
704 {
705 # ifdef TEXTCOLOR
706 return 1;
707 # else
708 if (color == CLR_BLACK)
709 return 1;
710 else if (color == CLR_WHITE)
711 return 1;
712 else
713 return 0;
714 # endif
715 }
716
717 void
term_start_attr(int attrib)718 term_start_attr(int attrib)
719 {
720 switch(attrib){
721 case ATR_INVERSE:
722 if (iflags.wc_inverse) {
723 /* Suggestion by Lee Berger */
724 if ((foreground & (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED)) ==
725 (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED))
726 foreground &= ~(FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED);
727 background = (BACKGROUND_RED|BACKGROUND_BLUE|BACKGROUND_GREEN);
728 break;
729 }
730 /*FALLTHRU*/
731 case ATR_ULINE:
732 case ATR_BLINK:
733 case ATR_BOLD:
734 foreground |= FOREGROUND_INTENSITY;
735 break;
736 default:
737 foreground &= ~FOREGROUND_INTENSITY;
738 break;
739 }
740 attr = (foreground | background);
741 }
742
743 void
term_end_attr(int attrib)744 term_end_attr(int attrib)
745 {
746 switch(attrib){
747
748 case ATR_INVERSE:
749 if ((foreground & (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED)) == 0)
750 foreground |= (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED);
751 background = 0;
752 break;
753 case ATR_ULINE:
754 case ATR_BLINK:
755 case ATR_BOLD:
756 foreground &= ~FOREGROUND_INTENSITY;
757 break;
758 }
759 attr = (foreground | background);
760 }
761
762 void
term_end_raw_bold(void)763 term_end_raw_bold(void)
764 {
765 term_end_attr(ATR_BOLD);
766 }
767
768 void
term_start_raw_bold(void)769 term_start_raw_bold(void)
770 {
771 term_start_attr(ATR_BOLD);
772 }
773
774 void
term_start_color(int color)775 term_start_color(int color)
776 {
777 #ifdef TEXTCOLOR
778 if (color >= 0 && color < CLR_MAX) {
779 foreground = (background != 0 && (color == CLR_GRAY || color == CLR_WHITE)) ?
780 ttycolors[0] : ttycolors[color];
781 }
782 #else
783 foreground = DEFTEXTCOLOR;
784 #endif
785 attr = (foreground | background);
786 }
787
788 void
term_end_color(void)789 term_end_color(void)
790 {
791 #ifdef TEXTCOLOR
792 foreground = DEFTEXTCOLOR;
793 #endif
794 attr = (foreground | background);
795 }
796
797
798 void
standoutbeg()799 standoutbeg()
800 {
801 term_start_attr(ATR_BOLD);
802 }
803
804
805 void
standoutend()806 standoutend()
807 {
808 term_end_attr(ATR_BOLD);
809 }
810
811 #ifndef NO_MOUSE_ALLOWED
812 void
toggle_mouse_support()813 toggle_mouse_support()
814 {
815 DWORD cmode;
816 GetConsoleMode(hConIn,&cmode);
817 if (iflags.wc_mouse_support)
818 cmode |= ENABLE_MOUSE_INPUT;
819 else
820 cmode &= ~ENABLE_MOUSE_INPUT;
821 SetConsoleMode(hConIn,cmode);
822 }
823 #endif
824
825 /* handle tty options updates here */
nttty_preference_update(pref)826 void nttty_preference_update(pref)
827 const char *pref;
828 {
829 if( stricmp( pref, "mouse_support")==0) {
830 #ifndef NO_MOUSE_ALLOWED
831 toggle_mouse_support();
832 #endif
833 }
834 return;
835 }
836
837 #ifdef PORT_DEBUG
838 void
win32con_debug_keystrokes()839 win32con_debug_keystrokes()
840 {
841 DWORD count;
842 boolean valid = 0;
843 int ch;
844 xputs("\n");
845 while (!valid || ch != 27) {
846 nocmov(ttyDisplay->curx, ttyDisplay->cury);
847 ReadConsoleInput(hConIn,&ir,1,&count);
848 if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown)
849 ch = process_keystroke(&ir, &valid, iflags.num_pad, 1);
850 }
851 (void)doredraw();
852 }
853 void
win32con_handler_info()854 win32con_handler_info()
855 {
856 char *buf;
857 int ci;
858 if (!pSourceAuthor && !pSourceWhere)
859 pline("Keyboard handler source info and author unavailable.");
860 else {
861 if (pKeyHandlerName && pKeyHandlerName(&buf, 1)) {
862 xputs("\n");
863 xputs("Keystroke handler loaded: \n ");
864 xputs(buf);
865 }
866 if (pSourceAuthor && pSourceAuthor(&buf)) {
867 xputs("\n");
868 xputs("Keystroke handler Author: \n ");
869 xputs(buf);
870 }
871 if (pSourceWhere && pSourceWhere(&buf)) {
872 xputs("\n");
873 xputs("Keystroke handler source code available at:\n ");
874 xputs(buf);
875 }
876 xputs("\nPress any key to resume.");
877 ci=nhgetch();
878 (void)doredraw();
879 }
880 }
881
win32con_toggle_cursor_info()882 void win32con_toggle_cursor_info()
883 {
884 display_cursor_info = !display_cursor_info;
885 }
886 #endif
887
888 void
map_subkeyvalue(op)889 map_subkeyvalue(op)
890 register char *op;
891 {
892 char digits[] = "0123456789";
893 int length, i, idx, val;
894 char *kp;
895
896 idx = -1;
897 val = -1;
898 kp = index(op, '/');
899 if (kp) {
900 *kp = '\0';
901 kp++;
902 length = strlen(kp);
903 if (length < 1 || length > 3) return;
904 for (i = 0; i < length; i++)
905 if (!index(digits, kp[i])) return;
906 val = atoi(kp);
907 length = strlen(op);
908 if (length < 1 || length > 3) return;
909 for (i = 0; i < length; i++)
910 if (!index(digits, op[i])) return;
911 idx = atoi(op);
912 }
913 if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1)
914 return;
915 key_overrides[idx] = val;
916 }
917
918 void
load_keyboard_handler()919 load_keyboard_handler()
920 {
921 char suffx[] = ".dll";
922 char *truncspot;
923 #define MAX_DLLNAME 25
924 char kh[MAX_ALTKEYHANDLER];
925 if (iflags.altkeyhandler[0]) {
926 if (hLibrary) { /* already one loaded apparently */
927 FreeLibrary(hLibrary);
928 hLibrary = (HANDLE)0;
929 pNHkbhit = (NHKBHIT)0;
930 pCheckInput = (CHECKINPUT)0;
931 pSourceWhere = (SOURCEWHERE)0;
932 pSourceAuthor = (SOURCEAUTHOR)0;
933 pKeyHandlerName = (KEYHANDLERNAME)0;
934 pProcessKeystroke = (PROCESS_KEYSTROKE)0;
935 }
936 if ((truncspot = strstri(iflags.altkeyhandler, suffx)) != 0)
937 *truncspot = '\0';
938 (void) strncpy(kh, iflags.altkeyhandler,
939 (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
940 kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
941 Strcat(kh, suffx);
942 Strcpy(iflags.altkeyhandler, kh);
943 hLibrary = LoadLibrary(kh);
944 if (hLibrary) {
945 pProcessKeystroke =
946 (PROCESS_KEYSTROKE) GetProcAddress (hLibrary, TEXT ("ProcessKeystroke"));
947 pNHkbhit =
948 (NHKBHIT) GetProcAddress (hLibrary, TEXT ("NHkbhit"));
949 pCheckInput =
950 (CHECKINPUT) GetProcAddress (hLibrary, TEXT ("CheckInput"));
951 pSourceWhere =
952 (SOURCEWHERE) GetProcAddress (hLibrary, TEXT ("SourceWhere"));
953 pSourceAuthor =
954 (SOURCEAUTHOR) GetProcAddress (hLibrary, TEXT ("SourceAuthor"));
955 pKeyHandlerName =
956 (KEYHANDLERNAME) GetProcAddress (hLibrary, TEXT ("KeyHandlerName"));
957 }
958 }
959 if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
960 if (hLibrary) {
961 FreeLibrary(hLibrary);
962 hLibrary = (HANDLE)0;
963 pNHkbhit = (NHKBHIT)0;
964 pCheckInput = (CHECKINPUT)0;
965 pSourceWhere = (SOURCEWHERE)0;
966 pSourceAuthor = (SOURCEAUTHOR)0;
967 pKeyHandlerName = (KEYHANDLERNAME)0;
968 pProcessKeystroke = (PROCESS_KEYSTROKE)0;
969 }
970 (void)strncpy(kh, "nhdefkey.dll", (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
971 kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
972 Strcpy(iflags.altkeyhandler, kh);
973 hLibrary = LoadLibrary(kh);
974 if (hLibrary) {
975 pProcessKeystroke =
976 (PROCESS_KEYSTROKE) GetProcAddress (hLibrary, TEXT ("ProcessKeystroke"));
977 pCheckInput =
978 (CHECKINPUT) GetProcAddress (hLibrary, TEXT ("CheckInput"));
979 pNHkbhit =
980 (NHKBHIT) GetProcAddress (hLibrary, TEXT ("NHkbhit"));
981 pSourceWhere =
982 (SOURCEWHERE) GetProcAddress (hLibrary, TEXT ("SourceWhere"));
983 pSourceAuthor =
984 (SOURCEAUTHOR) GetProcAddress (hLibrary, TEXT ("SourceAuthor"));
985 pKeyHandlerName =
986 (KEYHANDLERNAME) GetProcAddress (hLibrary, TEXT ("KeyHandlerName"));
987 }
988 }
989 if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
990 if (!hLibrary)
991 raw_printf("\nNetHack was unable to load keystroke handler.\n");
992 else {
993 FreeLibrary(hLibrary);
994 hLibrary = (HANDLE)0;
995 raw_printf("\nNetHack keystroke handler is invalid.\n");
996 }
997 exit(EXIT_FAILURE);
998 }
999 }
1000
1001 /* this is used as a printf() replacement when the window
1002 * system isn't initialized yet
1003 */
1004 void
1005 msmsg VA_DECL(const char *, fmt)
1006 char buf[ROWNO * COLNO]; /* worst case scenario */
1007 VA_START(fmt);
1008 VA_INIT(fmt, const char *);
1009 Vsprintf(buf, fmt, VA_ARGS);
1010 VA_END();
1011 xputs(buf);
1012 if (ttyDisplay) curs(BASE_WINDOW, cursor.X+1, cursor.Y);
1013 return;
1014 }
1015
1016 /* fatal error */
1017 /*VARARGS1*/
1018 void
1019 error VA_DECL(const char *,s)
1020 char buf[BUFSZ];
1021 VA_START(s);
1022 VA_INIT(s, const char *);
1023 /* error() may get called before tty is initialized */
1024 if (iflags.window_inited) end_screen();
1025 buf[0] = '\n';
1026 (void) vsprintf(&buf[1], s, VA_ARGS);
1027 VA_END();
1028 msmsg(buf);
1029 really_move_cursor();
1030 exit(EXIT_FAILURE);
1031 }
1032
1033 void
1034 synch_cursor()
1035 {
1036 really_move_cursor();
1037 }
1038 #endif /* WIN32CON */
1039