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