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