1 /*
2    Copyright (c) 1996-2000 Paul B. McBride
3 
4    Permission is hereby granted, free of charge, to any person
5    obtaining a copy of this software and associated documentation
6    files (the "Software"), to deal in the Software without
7    restriction, including without limitation the rights to use, copy,
8    modify, merge, publish, distribute, sublicense, and/or sell copies
9    of the Software, and to permit persons to whom the Software is
10    furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be
13    included in all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22    SOFTWARE.
23 */
24 /* modified 05 Jan 2000 by Paul B. McBride (pmcbride@tiac.net) */
25 /* mycurses.c - minimal curses library routines for Win32 LifeLines */
26 
27 #include <windows.h>
28 #include <stdarg.h>
29 #include <fcntl.h>
30 #include <curses.h>
31 
32 typedef enum { W8BITS, W16BITS } WBITS;
33 
34 /* fullscreen==1 to use screen buffer size instead of window size */
35 static int mycur_init(int fullscreen);
36 static int mycur_getc(WBITS wbits);
37 static void adjust_linescols(void);
38 static void console_resize_callback(void);
39 
40 
41 /* Windows Console */
42 
43 static int first = TRUE;
44 static HANDLE hStdin = INVALID_HANDLE_VALUE;
45 static HANDLE hStdout = INVALID_HANDLE_VALUE;
46 static DWORD dwModeIn = 0;
47 static DWORD dwModeOut = 0;
48 static CONSOLE_CURSOR_INFO ConCursorInfo = {0};
49 static COORD cOrigin = {0,0};
50 static int redirected_in = 0;
51 static int redirected_out = 0;
52 static int redir_unflushed = 0; /* used to separate output when redirected */
53 static int CurrentScreenWidth = -1;
54 static int CurrentScreenHeight = -1;
55 
56 /* Others Windows environment data */
57 extern int _fmode;		/* O_TEXT or O_BINARY */
58 
59 /* Windows NT stuff */
60 static BOOL WindowsNt = 0; /* set to 1 if NT/2000/XP */
61 static HINSTANCE LibKernel32 = 0;
62 typedef BOOL (CALLBACK *ApiFncReadConsoleInput)(HANDLE, PINPUT_RECORD, DWORD, LPDWORD);
63 static ApiFncReadConsoleInput ApiReadConsoleInput = 0;
64 
65 /* Debugging */
66 
67 /* #define DEBUG */
68 
69 #ifdef DEBUG
70 static FILE *errfp = NULL;
71 #endif
72 
73 /* Curses data */
74 
75 static int echoing = TRUE;
76 static int keypading = FALSE;
77 
78 static chtype myacsmap[256] = {
79 	'*', '*', '*', '*', '*', '*', '*', '*',
80 	'*', '*', '*', '*', '*', '*', '*', '*',
81 	'*', '*', '*', '*', '*', '*', '*', '*',
82 	'*', '*', '*', '*', '*', '*', '*', '*',
83 	'*', '*', '*', '*', '*', '*', '*', '*',
84 	'*', '*', '*', '*', '*', '*', '*', '*',
85 	'*', '*', '*', '*', '*', '*', '*', '*',
86 	'*', '*', '*', '*', '*', '*', '*', '*',
87 	'*', '*', '*', '*', '*', '*', '*', '*',
88 	'*', '*', '*', '*', '*', '*', '*', '*',
89 	'*', '*', '*', '*', '*', '*', '*', '*',
90 	'*', '*', '*', '*', '*', '*', '*', '*',
91 	'*', '*', '*', '*', '*', '*', '*', '*',
92 	'*', '*', '*', '*', '*', '*', '*', '*',
93 	'*', '*', '*', '*', '*', '*', '*', '*',
94 	'*', '*', '*', '*', '*', '*', '*', '*',
95 	'*', '*', '*', '*', '*', '*', '*', '*',
96 	'*', '*', '*', '*', '*', '*', '*', '*',
97 	'*', '*', '*', '*', '*', '*', '*', '*',
98 	'*', '*', '*', '*', '*', '*', '*', '*',
99 	'*', '*', '*', '*', '*', '*', '*', '*',
100 	'*', '*', '*', '*', '*', '*', '*', '*',
101 	'*', '*', '*', '*', '*', '*', '*', '*',
102 	'*', '*', '*', '*', '*', '*', '*', '*',
103 	'*', '*', '*', '*', '*', '*', '*', '*',
104 	'*', '*', '*', '*', '*', '*', '*', '*',
105 	'*', '*', '*', '*', '*', '*', '*', '*',
106 	'*', '*', '*', '*', '*', '*', '*', '*',
107 	'*', '*', '*', '*', '*', '*', '*', '*',
108 	'*', '*', '*', '*', '*', '*', '*', '*',
109 	'*', '*', '*', '*', '*', '*', '*', '*',
110 	'*', '*', '*', '*', '*', '*', '*', '*'
111 	};
112 
113 int LINES = 25;
114 int COLS  = CUR_MAXCOLS;
115 chtype *acs_map = myacsmap;
116 WINDOW *curscr = NULL;
117 WINDOW *stdscr = NULL;
118 
endwin()119 int endwin()
120 {
121 	COORD cCursor;
122 
123 	cCursor.X = 0;
124 	cCursor.Y = LINES-1;
125 	SetConsoleCursorPosition(hStdout, cCursor);
126 	return(0);
127 }
128 
129 
initscr()130 WINDOW	*initscr()
131 {
132 	_fmode = O_BINARY;	/* use binary mode for reading and writing */
133 	/* open an error file for debugging */
134 
135 #ifdef DEBUG
136 	if(errfp == NULL)
137 	 	errfp = fopen("mycurses.err", "w");
138 #endif
139 
140 	if (!mycur_init(1))
141 		return NULL;
142 	if (curscr)
143 	{
144 		delwin(curscr);
145 		curscr = 0;
146 	}
147 	curscr = newwin(LINES, COLS, 0, 0);
148 	/* set update point so whole screen is displayed */
149 	curscr->_mincy = 0;
150 	curscr->_maxcy = curscr->_maxy-1;
151 
152 	if (stdscr)
153 	{
154 		delwin(stdscr);
155 		stdscr = 0;
156 	}
157 	stdscr = newwin(LINES, COLS, 0, 0);
158 
159 	return(stdscr);
160 }
161 
newwin(int nlines,int ncols,int begy,int begx)162 WINDOW  *newwin(int nlines, int ncols, int begy, int begx)
163 {
164 	WINDOW *wp;
165 	static int wincnt = 0;
166 
167 	/* limit to screen size */
168 	if(nlines > LINES) nlines = LINES;
169 	if(ncols > COLS) ncols = COLS;
170 
171 	wp = calloc(1, sizeof(WINDOW));
172 	wp->_ylines = nlines;
173 	wp->_ycols = ncols;
174 	wp->_yarr = calloc(sizeof(char), wp->_ylines * wp->_ycols);
175 	wp->_num = wincnt++;
176 	wp->_maxy = nlines;
177 	wp->_maxx = ncols;
178 	if(begy < 0) begy = 0;
179 	if(begx < 0) begx = 0;
180 	wp->_begy = begy;
181 	wp->_begx = begx;
182 	wp->_curx = 0;
183 	wp->_cury = 0;
184 	wp->_scroll = TRUE;
185 	werase(wp);
186 	return(wp);
187 }
188 
delwin(WINDOW * wp)189 int delwin(WINDOW *wp)
190 {
191 	free(wp->_yarr);
192 	free(wp);
193 	return(0);
194 }
195 
subwin(WINDOW * wp,int nlines,int ncols,int begy,int begx)196 WINDOW  *subwin(WINDOW *wp, int nlines, int ncols, int begy, int begx)
197 {
198 	WINDOW *swp;
199 	swp = newwin(nlines, ncols, begy, begx);
200 	swp->_parent = wp;
201 	return(swp);
202 }
203 
crmode()204 int crmode()
205 {
206 	SetConsoleMode(hStdin, dwModeIn);
207 	return(0);
208 }
209 
nocrmode()210 int nocrmode()
211 {
212 	SetConsoleMode(hStdin, dwModeIn);
213 	return(0);
214 }
215 
cbreak()216 int cbreak()
217 {
218 	SetConsoleMode(hStdin, dwModeIn);
219 	return(0);
220 }
221 
nocbreak()222 int nocbreak()
223 {
224 	SetConsoleMode(hStdin, dwModeIn);
225 	return(0);
226 }
227 
curs_set(int mode)228 int curs_set(int mode)
229 {
230 	/* mode 0 = hide, 1 = show */
231 	ConCursorInfo.bVisible = mode;
232 	SetConsoleCursorInfo(hStdout, &ConCursorInfo);
233 	return(0);
234 }
235 
echo()236 int echo()
237 {
238 	echoing = TRUE;
239 	return(0);
240 }
241 
noecho()242 int noecho()
243 {
244 	echoing = FALSE;
245 	return(0);
246 }
247 
keypad(WINDOW * win,int bf)248 int keypad(WINDOW *win, int bf)
249 {
250 	keypading = !!bf;
251 	return(0);
252 }
253 
sleep(int secs)254 int sleep(int secs)
255 
256 {
257 	Sleep(secs*1000);
258 	return(0);
259 }
260 
clearok(WINDOW * wp,int okay)261 int clearok(WINDOW *wp, int okay)
262 {
263 	return(0);
264 }
265 
scrollok(WINDOW * wp,int okay)266 int scrollok(WINDOW *wp, int okay)
267 {
268 	wp->_scroll = okay;
269 	return(0);
270 }
271 
touchwin(WINDOW * wp)272 int touchwin(WINDOW *wp)
273 {
274 	curscr->_mincy = 0;
275 	curscr->_maxcy = curscr->_maxy-1;
276 	return(0);
277 }
278 
wrefresh(WINDOW * wp)279 int wrefresh(WINDOW *wp)
280 {
281 	wnoutrefresh(wp);
282 	doupdate();
283 	return(0);
284 }
285 
redrawwin(WINDOW * wp)286 int redrawwin(WINDOW *wp)
287 {
288 	return wrefresh(wp);
289 }
290 
atw(WINDOW * wp,int line,int col)291 static char atw(WINDOW * wp, int line, int col)
292 {
293 	if (! (line < wp->_ylines && line >= 0) )
294 	{
295 		return 0;
296 	}
297 	if (! (col < wp->_ycols && col >= 0) )
298 	{
299 		return 0;
300 	}
301 	return wp->_yarr[line * wp->_ycols + col];
302 }
setw(WINDOW * wp,int line,int col,char ch)303 static void setw(WINDOW * wp, int line, int col, char ch)
304 {
305 	if (! (line < wp->_ylines && line >= 0) )
306 	{
307 		return;
308 	}
309 	if (! (col < wp->_ycols && col >= 0) )
310 	{
311 		return;
312 	}
313 	wp->_yarr[line * wp->_ycols + col] = ch;
314 }
getlinew(WINDOW * wp,int line)315 static char * getlinew(WINDOW *wp, int line)
316 {
317 	if (! (line < wp->_ylines && line >= 0) ) return "";
318 	return &wp->_yarr[line * wp->_ycols];
319 }
320 
321 /* refresh virtual image of screen (curscr) */
wnoutrefresh(WINDOW * wp)322 int wnoutrefresh(WINDOW *wp)
323 {
324 	int i, j;
325 	int y, x;
326 
327 	if(wp->_parent)
328 		wrefresh(wp->_parent);
329 	for(i = 0; i < wp->_maxy; i++)
330 	{
331 		y = wp->_begy + i;
332 		if(y < curscr->_maxy)
333 		{
334 			for(j = 0; j < wp->_maxx; j++)
335 			{
336 				x = wp->_begx + j;
337 				if(x < curscr->_maxx)
338 				{
339 					if(atw(curscr, y, x) != atw(wp, i, j))
340 					{
341 						if(y < curscr->_mincy) curscr->_mincy = y;
342 						if(y > curscr->_maxcy) curscr->_maxcy = y;
343 						setw(curscr, y, x, atw(wp, i, j));
344 					}
345 				}
346 			}
347  		}
348 	}
349 	return(0);
350 }
351 
352 /* repaint physical screen from virtual image (curscr) */
doupdate(void)353 int doupdate(void)
354 {
355 	int linecount=0;
356 	int i=0;
357 	/* update the screen */
358 	if((linecount  = (curscr->_maxcy - curscr->_mincy)) >= 0)
359 	{
360 		COORD cLocation = {0,0};
361 		cLocation.X = 0;
362 		cLocation.Y = curscr->_mincy;
363 		linecount++;
364 		for (i=0; i<linecount; i++, cLocation.Y++)
365 		{
366 			DWORD dwLen;
367 			WriteConsoleOutputCharacter(hStdout,
368 				(LPTSTR)(getlinew(curscr, curscr->_mincy+i)),
369 				(DWORD)curscr->_maxx,
370 				cLocation, &dwLen);
371 		}
372 		curscr->_mincy = curscr->_maxy;
373 		curscr->_maxcy = -1;
374 	}
375 	return(0);
376 }
377 
werase(WINDOW * wp)378 int werase(WINDOW *wp)
379 {
380 	int i, j;
381 
382 	for(i = 0; i < LINES; i++)
383 		for(j = 0; j < COLS; j++)
384 			setw(wp, i, j, ' ');
385 	return(0);
386 }
387 
wclrtoeol(WINDOW * wp)388 int wclrtoeol(WINDOW *wp)
389 {
390 	int i;
391 	for(i = wp->_curx; i < wp->_maxx; i++)
392 		setw(wp, wp->_cury, i, ' ');
393 	return(0);
394 }
395 
wmove(WINDOW * wp,int y,int x)396 int wmove(WINDOW *wp, int y, int x)
397 {
398 	if(x < 0) x = 0;
399 	if(x >= wp->_maxx) x = wp->_maxx -1;
400 	if(y < 0) y = 0;
401 	if(y >= wp->_maxy) y = wp->_maxy -1;
402 	wp->_curx = x;
403 	wp->_cury = y;
404 	redir_unflushed = 1;
405 	return(0);
406 }
407 
vwprintw(WINDOW * wp,char * fmtp,va_list ap)408 int vwprintw(WINDOW *wp, char *fmtp, va_list ap)
409 {
410 	char tmpbuf[2048]; /* help what should this be ? */
411 	_vsnprintf(tmpbuf, sizeof(tmpbuf), fmtp, ap);
412 	waddstr(wp, tmpbuf);
413 	return(0);
414 }
415 
wprintw(WINDOW * wp,...)416 int wprintw(WINDOW *wp, ...)
417 {
418 	va_list ap;
419 	char tmpbuf[256];
420 	char * fmtp;
421 
422 	va_start(ap, wp);
423 	fmtp = va_arg(ap, char *);
424 	vsprintf(tmpbuf, fmtp, ap);
425 	waddstr(wp, tmpbuf);
426 	va_end(ap);
427 	return(0);
428 }
429 
430 static char
screenchar(chtype ch)431 screenchar(chtype ch)
432 {
433 	/* This implementation only stores chars */
434 	return (char)ch;
435 }
436 
waddch(WINDOW * wp,chtype ch)437 int waddch(WINDOW *wp, chtype ch)
438 {
439 	int i, j;
440 
441 	if (redirected_out)
442 	{
443 		if (redir_unflushed)
444 		{
445 			putc('\n', stdout);
446 			redir_unflushed=0;
447 		}
448 		putc(ch, stdout);
449 		return 0;
450 	}
451 
452 	if(ch == '\r')
453 		wp->_curx = 0;
454 	else if(ch == '\n')
455 	{
456 		wp->_curx = 0;
457 		wp->_cury++;
458 		if(wp->_cury >= wp->_maxy)
459 		{
460 			if(wp->_scroll)
461 			{
462 				for(i = 0; i < (wp->_maxy - 1); i++)
463 				{
464 					for(j = 0; j < wp->_maxx; j++)
465 					{
466 						ch = atw(wp, i+1, j);
467 						setw(wp, i, j, screenchar(ch));
468 					}
469 				}
470 				i = wp->_maxy-1;
471 				for(j = 0; j < wp->_maxx; j++)
472 				setw(wp, i, j, ' ');
473 			}
474 			wp->_cury = wp->_maxy-1;
475 		}
476 	}
477 	else
478 	{
479 		setw(wp, wp->_cury, wp->_curx, screenchar(ch));
480 		wp->_curx++;
481 		if(wp->_curx >= wp->_maxx)
482 		{
483 			wp->_curx = 0;
484 			wp->_cury++;
485 			if(wp->_cury >= wp->_maxy)
486 			{
487 				if(wp->_scroll)
488 				{
489 					for(i = 0; i < (wp->_maxy - 1); i++)
490 					{
491 						for(j = 0; j < wp->_maxx; j++)
492 						{
493 							ch = atw(wp, i+1, j);
494 							setw(wp, i, j, screenchar(ch));
495 						}
496 					}
497 					i = wp->_maxy-1;
498 					for(j = 0; j < wp->_maxx; j++)
499 						setw(wp, i, j, ' ');
500 				}
501 				else wp->_curx = wp->_maxx-1;
502 				wp->_cury = wp->_maxy-1;
503 			}
504 		}
505 	}
506 	return(0);
507 }
508 
waddstr(WINDOW * wp,const char * cp)509 int waddstr(WINDOW *wp, const char *cp)
510 {
511 	while(*cp)
512 	{
513 		waddch(wp, *cp);
514 		cp++;
515 	}
516 	return(0);
517 }
518 
waddnstr(WINDOW * wp,const char * cp,int n)519 int waddnstr(WINDOW *wp, const char *cp, int n)
520 {
521 	while(n && *cp)
522 	{
523 		waddch(wp, *cp);
524 		cp++;
525 		--n;
526 	}
527 	return(0);
528 }
529 
mvwaddstr(WINDOW * wp,int y,int x,char * cp)530 int mvwaddstr(WINDOW *wp, int y, int x, char *cp)
531 {
532 	wmove(wp, y, x);
533 	waddstr(wp, cp);
534 	return(0);
535 }
536 
mvwaddnstr(WINDOW * wp,int y,int x,char * cp,int n)537 int mvwaddnstr(WINDOW *wp, int y, int x, char *cp, int n)
538 {
539 	wmove(wp, y, x);
540 	waddnstr(wp, cp, n);
541 	return(0);
542 }
543 
mvwaddch(WINDOW * wp,int y,int x,chtype ch)544 int mvwaddch(WINDOW *wp, int y, int x, chtype ch)
545 {
546 	wmove(wp, y, x);
547 	waddch(wp, ch);
548 	return(0);
549 }
550 
mvwprintw(WINDOW * wp,int y,int x,...)551 int mvwprintw(WINDOW *wp, int y, int x, ...)
552 {
553 	va_list ap;
554 	char tmpbuf[256];
555 	char * fmtp;
556 
557 	wmove(wp, y, x);
558 
559 	va_start(ap, x);
560 	fmtp = va_arg(ap, char *);
561 	vsprintf(tmpbuf, fmtp, ap);
562 	waddstr(wp, tmpbuf);
563 	va_end(ap);
564 	return(0);
565 }
566 
mvwgetstr(WINDOW * wp,int y,int x,char * cp)567 int mvwgetstr(WINDOW *wp, int y, int x, char *cp)
568 {
569 	wmove(wp, y, x);
570 	wgetstr(wp, cp);
571 	return(0);
572 }
573 
mvwgetnstr(WINDOW * wp,int y,int x,char * cp,int n)574 int mvwgetnstr(WINDOW *wp, int y, int x, char *cp, int n)
575 {
576 	wmove(wp, y, x);
577 	wgetnstr(wp, cp, n);
578 	return(0);
579 }
580 
581 
box(WINDOW * wp,chtype v,chtype h)582 int box(WINDOW *wp, chtype v, chtype h)
583 {
584 	return wborder(wp, v, v, h, h, 0, 0, 0, 0);
585 }
586 
wborder(WINDOW * wp,chtype ls,chtype rs,chtype ts,chtype bs,chtype tl,chtype tr,chtype bl,chtype br)587 int wborder(WINDOW *wp, chtype ls, chtype rs, chtype ts, chtype bs
588 	, chtype tl, chtype tr, chtype bl, chtype br)
589 {
590 	int i;
591 
592 	wp->_boxed = TRUE;
593 	if (!ls) ls = ACS_VLINE;
594 	if (!rs) rs = ACS_VLINE;
595 	if (!ts) ts = ACS_HLINE;
596 	if (!bs) bs = ACS_HLINE;
597 	if (!tl) tl = ACS_ULCORNER;
598 	if (!tr) tr = ACS_URCORNER;
599 	if (!bl) bl = ACS_LLCORNER;
600 	if (!br) br = ACS_LRCORNER;
601 	for(i = 0; i < wp->_maxy; i++)
602 	{
603 		setw(wp, i, 0, screenchar(ls));
604 		setw(wp, i, wp->_maxx-1, screenchar(rs));
605 	}
606 	for(i = 0; i < wp->_maxx; i++)
607 	{
608 		setw(wp, 0, i, screenchar(ts));
609 		setw(wp, wp->_maxy-1, i, screenchar(bs));
610 	}
611 	setw(wp, 0, 0, screenchar(tl));
612 	setw(wp, 0, wp->_maxx-1, screenchar(tr));
613 	setw(wp, wp->_maxy-1, 0, screenchar(bl));
614 	setw(wp, wp->_maxy-1, wp->_maxx-1, screenchar(br));
615 	return(0);
616 }
617 
wgetch(WINDOW * wp)618 int wgetch(WINDOW *wp)
619 {
620 	COORD cCursor;
621 	int ch;
622 
623 	cCursor.X = wp->_curx + wp->_begx;
624 	cCursor.Y = wp->_cury + wp->_begy;
625 	SetConsoleCursorPosition(hStdout, cCursor);
626 	ch = mycur_getc(W8BITS);
627 	if (echoing && ch>31 && ch<256 && ch!=EOF)
628 	{
629 		waddch(wp, ch);
630 		wrefresh(wp);
631 		cCursor.X = wp->_curx + wp->_begx;
632 		cCursor.Y = wp->_cury + wp->_begy;
633 		SetConsoleCursorPosition(hStdout, cCursor);
634 	}
635 	return(ch);
636 }
637 
has_key(int ch)638 int has_key(int ch)
639 {
640 	return (ch>=KEY_MIN && ch<=KEY_MAX);
641 }
642 
wgetstr(WINDOW * wp,char * cp)643 int wgetstr(WINDOW *wp, char *cp)
644 {
645 	return wgetnstr(wp, cp, -1);
646 }
647 
wgetnstr(WINDOW * wp,char * cp,int n)648 int wgetnstr(WINDOW *wp, char *cp, int n)
649 {
650 	COORD cCursor;
651 	char *bp;
652 	int ch;
653 	int overflowed=0, echoprev;
654 
655 	bp = cp;
656 	while(1)
657 	{
658 		overflowed = (n>=0 && bp-cp>=n-1);
659 		echoprev = echoing;
660 		if(overflowed)
661 			echoing = 0;
662 		ch = wgetch(wp);
663 		echoing = echoprev;
664 		if (ch == '\b')
665 		{
666 			if(bp != cp)
667 			{
668 				bp--;
669 				if(echoing)
670 				{
671 					if(wp->_curx > 0) wp->_curx--;
672 					setw(wp, wp->_cury, wp->_curx, ' ');
673 					wrefresh(wp);
674 					cCursor.X = wp->_curx + wp->_begx;
675 					cCursor.Y = wp->_cury + wp->_begy;
676 					SetConsoleCursorPosition(hStdout, cCursor);
677 				}
678 			}
679 		}
680 		if (ch==EOF || ch=='\n' || ch=='\r')
681 		{
682 			break;
683 		}
684 		else if (ch>31 && ch<256)
685 		{
686 			if(overflowed)
687 				MessageBeep(MB_OK);
688 			else
689 				*bp++ = ch;
690 		}
691 	}
692 	*bp = '\0';
693 	return(0);
694 }
695 
696 /* Win32 Stuff */
697 /* returns 0 if fails */
mycur_init(int fullscreen)698 static int mycur_init(int fullscreen)
699 {
700 	COORD cStartPos;
701 	DWORD dwLen;
702 
703 	if(first)
704 	{
705 		CONSOLE_SCREEN_BUFFER_INFO ConScreenBuffer = {0};
706 		OSVERSIONINFO verinfo;
707 		verinfo.dwOSVersionInfoSize = sizeof(verinfo);
708 		if (GetVersionEx(&verinfo) && verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
709 		{
710 			WindowsNt = 1;
711 			LibKernel32 = LoadLibrary("Kernel32.dll");
712 			ApiReadConsoleInput = (ApiFncReadConsoleInput)GetProcAddress(LibKernel32, "ReadConsoleInputW");
713 		}
714 
715 		/* set up alternate character set values */
716 
717 		ACS_VLINE = (CHTYPE)179;
718 		ACS_HLINE = (CHTYPE)196;
719 		ACS_BTEE = (CHTYPE)193;
720 		ACS_TTEE = (CHTYPE)194;
721 		ACS_RTEE = (CHTYPE)180;
722 		ACS_LTEE = (CHTYPE)195;
723 		ACS_ULCORNER = (CHTYPE)218;
724 		ACS_LRCORNER = (CHTYPE)217;
725 		ACS_URCORNER = (CHTYPE)191;
726 		ACS_LLCORNER = (CHTYPE)192;
727 
728 		/* set up console I/O */
729 		first = FALSE;
730 		hStdin = GetStdHandle((DWORD)STD_INPUT_HANDLE);
731 		if(hStdin == INVALID_HANDLE_VALUE)
732 		{
733 			printf("Error opening console window for input\n");
734 			return 0;
735 		}
736 		if (!GetConsoleMode(hStdin, &dwModeIn))
737 			redirected_in = 1;
738 		dwModeIn &= ~(ENABLE_LINE_INPUT
739 			| ENABLE_ECHO_INPUT
740 			| ENABLE_MOUSE_INPUT
741 			| ENABLE_WINDOW_INPUT);
742 		dwModeIn |=	ENABLE_PROCESSED_INPUT;
743 		SetConsoleMode(hStdin, dwModeIn);
744 
745 		hStdout = GetStdHandle((DWORD)STD_OUTPUT_HANDLE);
746 		if (hStdout == INVALID_HANDLE_VALUE)
747 		{
748 			printf("Error opening console window for output\n");
749 			return 0;
750 		}
751 
752 		if (!GetConsoleScreenBufferInfo(hStdout, &ConScreenBuffer)) {
753 			redirected_out = 1;
754 			ConScreenBuffer.dwSize.X = 80;
755 			ConScreenBuffer.dwSize.Y = 25;
756 			ConScreenBuffer.srWindow.Bottom = 25;
757 			ConScreenBuffer.srWindow.Right = 80;
758 			/*
759 			TODO: What to do with console output functions when output redirected ?
760 			2002-10-19, Perry
761 			*/
762 		}
763 		CurrentScreenWidth = ConScreenBuffer.dwSize.X;
764 		CurrentScreenHeight = ConScreenBuffer.dwSize.Y;
765 
766 		/* get info on cursor */
767 		GetConsoleCursorInfo(hStdout, &ConCursorInfo);
768 		/*
769 		TODO: What to do with console cursor functions when output redirected?
770 		2005-09-21, Matt
771 		*/
772 
773 #ifdef DEBUG
774 		fprintf(errfp, "Screen buffer: (%d,%d) pos=(%d,%d)\n",
775 			ConScreenBuffer.dwSize.X, ConScreenBuffer.dwSize.Y,
776 			ConScreenBuffer.dwCursorPosition.X, ConScreenBuffer.dwCursorPosition.Y);
777 		fprintf(errfp, "Window: (%d-%d,%d-%d) max=(%d,%d)\n",
778 			ConScreenBuffer.srWindow.Left, ConScreenBuffer.srWindow.Right,
779 			ConScreenBuffer.srWindow.Top, ConScreenBuffer.srWindow.Bottom,
780 			ConScreenBuffer.dwMaximumWindowSize.X,
781 			ConScreenBuffer.dwMaximumWindowSize.Y);
782 #endif
783 		if (ConScreenBuffer.srWindow.Left || ConScreenBuffer.srWindow.Top)
784 		{
785 			/* WARNING: this code will not work correctly with offset window */
786 		}
787 		cStartPos.X = 0;
788 		cStartPos.Y = 0;
789 
790 		/* clear console (fill with blanks) */
791 		FillConsoleOutputCharacter(hStdout, (TCHAR)' ',
792 			(DWORD)(ConScreenBuffer.dwSize.X*ConScreenBuffer.dwSize.Y),
793 			cStartPos, &dwLen);
794 		/* save size into curses globals LINES & COLS */
795 		if (fullscreen)
796 		{
797 			LINES = ConScreenBuffer.dwSize.Y;
798 			COLS = ConScreenBuffer.dwSize.X;
799 		}
800 		else
801 		{
802 			LINES = ConScreenBuffer.srWindow.Bottom;
803 			COLS = ConScreenBuffer.srWindow.Right;
804 		}
805 		adjust_linescols();
806 	}
807 	return 1;
808 }
809 
810 /*
811 Adjust LINES & COLS so they're not ridiculously large
812 because screen buffer size can be very large (eg, 9000 lines)
813 */
adjust_linescols()814 static void adjust_linescols()
815 {
816 	if (LINES > CUR_MAXLINES)
817 		LINES = CUR_MAXLINES;
818 	if (COLS > CUR_MAXCOLS)
819 		COLS = CUR_MAXCOLS;
820 }
821 
822 /* helper structure for key table in mycur_getc */
823 struct keycvt { int win; int curs; };
824 
825 /* Check if console size has changed, and update LINES & COLS if so */
check_for_resize(void)826 static void check_for_resize (void)
827 {
828 	CONSOLE_SCREEN_BUFFER_INFO ConScreenBuffer = {0};
829 	if (!GetConsoleScreenBufferInfo(hStdout, &ConScreenBuffer))
830 		return;
831 
832 	if (CurrentScreenWidth != ConScreenBuffer.dwSize.X
833 		|| CurrentScreenHeight != ConScreenBuffer.dwSize.Y) {
834 		/* screen has been resized */
835 		LINES = CurrentScreenHeight= ConScreenBuffer.dwSize.Y;
836 		COLS = CurrentScreenWidth = ConScreenBuffer.dwSize.X;
837 		adjust_linescols();
838 		console_resize_callback();
839 	}
840 }
841 /*
842  In May of 2002 Perry changed from ReadConsole to ReadConsoleInput
843  in order to be able to get arrow keys etc
844 */
845 /* Caller can request either 8-bit input (ReadConsoleInputA) or 16-bit input (ReadConsoleInputW) */
846 
mycur_getc(WBITS wbits)847 static int mycur_getc(WBITS wbits)
848 {
849 	/* table of curses names for special keys */
850 	/* NB: These are not single-byte constants, so return value must be int */
851 	static struct keycvt keymap[] = {
852 		{ VK_DOWN, KEY_DOWN }
853 		, { VK_UP, KEY_UP }
854 		, { VK_NEXT, KEY_NPAGE }
855 		, { VK_PRIOR, KEY_PPAGE }
856 		, { VK_HOME, KEY_HOME }
857 		, { VK_END, KEY_END }
858 		, { VK_RETURN, KEY_ENTER }
859 	};
860 	static struct keycvt skeymap[] = {
861 		{ VK_NEXT, KEY_SNEXT }
862 		, { VK_PRIOR, KEY_SPREVIOUS }
863 		, { VK_HOME, KEY_SHOME }
864 	};
865 	static int altctrls = LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED;
866 	static int numpadbase=0;
867 	static int numpadval=0;
868 
869 	if (hStdin == INVALID_HANDLE_VALUE || redirected_in)
870 		return getchar();
871 
872 	while (1)
873 	{
874 		INPUT_RECORD inrec;
875 		int nrecs=0, i;
876 
877 		if (WindowsNt && wbits==W16BITS)
878 		{
879 			(*ApiReadConsoleInput)(hStdin, &inrec, 1, &nrecs);
880 		}
881 		else
882 		{
883 			ReadConsoleInput(hStdin, &inrec, 1, &nrecs);
884 		}
885 
886 		/* To get special keys, have to use ReadConsoleInput */
887 		if (!nrecs)
888 			return EOF;
889 
890 		/* 2006-07-23, Perry:
891 		Not receiving any inrec.EventType == WINDOW_BUFFER_SIZE_EVENT)
892 			int width= inrec.Event.WindowBufferSizeEvent.dwSize.X;
893 			int height = inrec.Event.WindowBufferSizeEvent.dwSize.Y;
894 		*/
895 		check_for_resize();
896 		if (inrec.EventType == KEY_EVENT && inrec.Event.KeyEvent.bKeyDown
897 			&& inrec.Event.KeyEvent.wVirtualKeyCode != VK_MENU)
898 		{
899 			int keystate, keycode;
900 			/* return normal keys */
901 			if (WindowsNt && wbits==W16BITS)
902 			{
903 				if (inrec.Event.KeyEvent.uChar.UnicodeChar)
904 				{
905 					unsigned int ch = (wchar_t)inrec.Event.KeyEvent.uChar.UnicodeChar;
906 					return ch;
907 				}
908 			}
909 			else
910 			{
911 				if (inrec.Event.KeyEvent.uChar.AsciiChar)
912 				{
913 					unsigned int ch = (unsigned char)inrec.Event.KeyEvent.uChar.AsciiChar;
914 					return ch;
915 				}
916 			}
917 			keystate = inrec.Event.KeyEvent.dwControlKeyState;
918 			keycode = inrec.Event.KeyEvent.wVirtualKeyCode;
919 			/* handle keyboard numeric escapes for non-ASCII characters */
920 			if ((keystate & LEFT_ALT_PRESSED || keystate & RIGHT_ALT_PRESSED)
921 				&& (VK_NUMPAD0 <= keycode && keycode <= VK_NUMPAD9))
922 			{
923 				if (!numpadval)
924 				{
925 					if (keycode == VK_NUMPAD0)
926 					{
927 						/* TODO: 0-prefixed alt-codes are not octal codes in the console
928 						codeset at all, but rather decimal codes but in the Windows codeset !
929 						2003-04-20, Perry
930 						*/
931 						numpadbase = 8;
932 						numpadval = -1;
933 					}
934 					else
935 					{
936 						numpadbase = 10;
937 						numpadval = (keycode - VK_NUMPAD0);
938 					}
939 				}
940 				else
941 				{
942 					if (numpadval == -1)
943 						numpadval = keycode - VK_NUMPAD0;
944 					else
945 						numpadval = numpadval * numpadbase + (keycode - VK_NUMPAD0);
946 					if (numpadval > 127)
947 					{
948 						int val = numpadval;
949 						numpadval = 0;
950 						return val;
951 					}
952 				}
953 			}
954 			else
955 				numpadval = 0;
956 			/* check if it is a hardware key we handle */
957 			/* if so, map it to curses constant */
958 			if (!(keystate & altctrls))
959 			{
960 				if (keystate & SHIFT_PRESSED)
961 				{
962 					for (i=0; i<sizeof(skeymap)/sizeof(skeymap[0]); ++i)
963 					{
964 						if (inrec.Event.KeyEvent.wVirtualKeyCode == skeymap[i].win)
965 							return skeymap[i].curs;
966 					}
967 				}
968 				else /* not shifted */
969 				{
970 					for (i=0; i<sizeof(keymap)/sizeof(keymap[0]); ++i)
971 					{
972 						if (inrec.Event.KeyEvent.wVirtualKeyCode == keymap[i].win)
973 							return keymap[i].curs;
974 					}
975 				}
976 			}
977 			else
978 			{
979 			}
980 		}
981 	}
982 }
983 
wtitle(const char * title)984 void wtitle(const char *title)
985 {
986 	SetConsoleTitle(title);
987 }
988 
989 static void * cbparam = 0;
990 static void (*cbfunc)(void *) = 0;
w_set_console_resize_callback(void (* fptr)(void * param),void * param)991 void w_set_console_resize_callback(void (*fptr)(void * param), void * param)
992 {
993 	cbparam = param;
994 	cbfunc = fptr;
995 }
console_resize_callback(void)996 static void console_resize_callback(void)
997 {
998 	if (cbfunc)
999 		(cbfunc)(cbparam);
1000 }
1001