1 /*
2  *  WINNTSCR.C
3  *
4  *  Written in August 1996 by Andrew Clarke and released to the public domain.
5  *
6  *  Screen definitions & routines for Windows NT.
7  */
8 
9 #include <stdlib.h>
10 #include <string.h>
11 #include <windows.h>
12 #include "winsys.h"
13 #include "unused.h"
14 #include "specch.h"
15 
16 #define TERMDEF 1
17 
18 #ifdef KEYDEBUG
19 #include <stdio.h>
20 static FILE *fTrace = NULL;
21 #endif
22 
23 int vcol, vrow;                 /* cursor position         */
24 int color;                      /* current color on screen */
25 int cur_start = 0;
26 int cur_end = 0;
27 
28 TERM term =
29 {
30     80,
31     25,
32     0,
33 };
34 
35 #define EBUFSZ 25
36 
37 static int ebufin = 0;          /* event in */
38 static int ebufout = 0;         /* event out */
39 static EVT EVent[EBUFSZ];       /* event circular queue */
40 
41 static HANDLE HInput = INVALID_HANDLE_VALUE;
42 static HANDLE HOutput = INVALID_HANDLE_VALUE;
43 static unsigned long key_hit = 0xFFFFFFFFUL;
44 
45 static int FullBuffer(void);
46 
47 /* codepage 437 / 850 block graphics */
48 char *tt_specials="\272\315\311\273\310\274\263\304\332\277\300\331\261\020\021\334\337\030\031\024\035\000";
49 
50 int tt_graphics = 0;
51 
TTBeginOutput(void)52 void TTBeginOutput(void) {}
TTEndOutput(void)53 void TTEndOutput(void) {}
54 
TTopen(void)55 int TTopen(void)
56 {
57     CONSOLE_SCREEN_BUFFER_INFO csbi;
58     TTkopen();
59     GetConsoleScreenBufferInfo(HOutput, &csbi);
60     vcol = (int) csbi.dwCursorPosition.X;
61     vrow = (int) csbi.dwCursorPosition.Y;
62     term.NCol = (short) csbi.dwSize.X;
63     term.NRow = (short) csbi.dwSize.Y;
64     color = 0x07;
65     return 1;
66 }
67 
TTclose(void)68 int TTclose(void)
69 {
70     return 1;
71 }
72 
73 #ifdef __GNUC__
74 #pragma warn -par
75 #endif
76 
77 /*
78  * Configure the terminal. This must be called *before* TTopen!
79  *
80  * The Windows NT console terminal does not need any configuration.
81  *
82  */
83 
TTconfigure(const char * keyword,const char * value)84 int TTconfigure(const char *keyword, const char *value)
85 {
86     return 0;
87 }
88 
89 #ifdef __GNUC__
90 #pragma warn +par
91 #endif
92 
TTgotoxy(int row,int col)93 int TTgotoxy(int row, int col)
94 {
95     COORD coord;
96     coord.X = (SHORT) col;
97     coord.Y = (SHORT) row;
98     SetConsoleCursorPosition(HOutput, coord);
99     vcol = col;
100     vrow = row;
101     return 1;
102 }
103 
TTPutChr(unsigned int Ch)104 int TTPutChr(unsigned int Ch)
105 {
106     DWORD len;
107     COORD coord;
108     WORD wattr;
109     unsigned char wch;
110     coord.X = (SHORT) vcol;
111     coord.Y = (SHORT) vrow;
112     wattr = (WORD) color;
113     wch = (unsigned char) Ch;
114     WriteConsoleOutputCharacterA(HOutput, &wch, 1, coord, &len);
115     WriteConsoleOutputAttribute(HOutput, &wattr, 1, coord, &len);
116     TTgotoxy(vrow, vcol + 1);
117     return 1;
118 }
119 
mykbhit(int block)120 static int mykbhit(int block)
121 {
122     int iKey = 0;
123     INPUT_RECORD irBuffer;
124     DWORD pcRead;
125 
126     if (FullBuffer())
127     {
128         return 0;
129     }
130 
131     if (key_hit != 0xFFFFFFFFUL)
132     {
133         return (int)key_hit;
134     }
135 
136     memset(&irBuffer, 0, sizeof irBuffer);
137 
138     if (WaitForSingleObject(HInput, (block)? INFINITE : 0L) == 0)
139     {
140         ReadConsoleInput(HInput, &irBuffer, 1, &pcRead);
141 
142 #ifdef KEYDEBUG
143         if (irBuffer.EventType == KEY_EVENT)
144         {
145             fprintf(fTrace, "bKD=%d wRC=%hd wVKC=%hd wVSC=%hd c=%d dwCKS=%lx\n",
146                     irBuffer.Event.KeyEvent.bKeyDown,
147                     irBuffer.Event.KeyEvent.wRepeatCount,
148                     irBuffer.Event.KeyEvent.wVirtualKeyCode,
149                     irBuffer.Event.KeyEvent.wVirtualScanCode,
150 #ifdef __MINGW32__
151                     irBuffer.Event.KeyEvent.AsciiChar;
152 #else
153                     irBuffer.Event.KeyEvent.uChar.AsciiChar;
154 #endif
155                     irBuffer.Event.KeyEvent.dwControlKeyState);
156         }
157 #endif
158 
159 
160         if (irBuffer.EventType == KEY_EVENT && irBuffer.Event.KeyEvent.bKeyDown != 0 && irBuffer.Event.KeyEvent.wRepeatCount <= 1)
161         {
162             WORD vk, vs, uc;
163             BOOL fShift, fAlt, fCtrl;
164 
165             vk = irBuffer.Event.KeyEvent.wVirtualKeyCode;
166             vs = irBuffer.Event.KeyEvent.wVirtualScanCode;
167 #ifdef __MINGW32__
168             uc = irBuffer.Event.KeyEvent.AsciiChar;
169 #else
170             uc = irBuffer.Event.KeyEvent.uChar.AsciiChar;
171 #endif
172             fShift = (irBuffer.Event.KeyEvent.dwControlKeyState & (SHIFT_PRESSED));
173             fAlt = (irBuffer.Event.KeyEvent.dwControlKeyState & (RIGHT_ALT_PRESSED + LEFT_ALT_PRESSED));
174             fCtrl = (irBuffer.Event.KeyEvent.dwControlKeyState & (RIGHT_CTRL_PRESSED + LEFT_CTRL_PRESSED));
175 
176             if (uc == 0)       /* function keys */
177             {
178                 switch (vk)
179                 {
180                 case 0x21:     /* PgUp */
181                     if (fCtrl)
182                     {
183                         vs = 0x84;  /* Ctrl+PgUp */
184                     }
185                     break;
186 
187                 case 0x22:     /* PgDn */
188                     if (fCtrl)
189                     {
190                         vs = 0x76;  /* Ctrl+PgDn */
191                     }
192                     break;
193 
194                 case 0x23:     /* End */
195                     if (fCtrl)
196                     {
197                         vs = 0x75;  /* Ctrl+End */
198                     }
199                     break;
200 
201                 case 0x24:     /* Home */
202                     if (fCtrl)
203                     {
204                         vs = 0x77;  /* Ctrl+Home */
205                     }
206                     break;
207 
208                 case 0x25:     /* Left Arrow */
209                     if (fCtrl)
210                     {
211                         vs = 0x73;  /* Ctrl+Left Arrow */
212                     }
213                     break;
214 
215                 case 0x26:     /* Up Arrow */
216                     if (fCtrl)
217                     {
218                         vs = 0x8d;  /* Ctrl+Up Arrow */
219                     }
220                     break;
221 
222                 case 0x27:     /* Right Arrow */
223                     if (fCtrl)
224                     {
225                         vs = 0x74;  /* Ctrl+Right Arrow */
226                     }
227                     break;
228 
229                 case 0x28:     /* Down Arrow */
230                     if (fCtrl)
231                     {
232                         vs = 0x91;  /* Ctrl+Down Arrow */
233                     }
234                     break;
235 
236                 case 0x70:     /* F-Keys */
237                 case 0x71:
238                 case 0x72:
239                 case 0x73:
240                 case 0x74:
241                 case 0x75:
242                 case 0x76:
243                 case 0x77:
244                 case 0x78:
245                 case 0x79:
246                     if (fAlt != 0)
247                     {
248                         vs += 0x2D;  /* Alt+F-Key */
249                     }
250                     else if (fShift != 0)
251                     {
252                         vs += 0x19;  /* Shift+F-Key */
253                     }
254                     break;
255                 }
256 
257                 if (vk > 0x20 && vk < 0x92)  /* If it's OK use scan code */
258                 {
259                     iKey = vs << 8;
260                 }
261             }
262             else
263             {
264                 if (fAlt && (!fCtrl))       /* Alt+Key */
265                 {
266                     iKey = vs << 8;
267                 }
268                 else if (fCtrl && (!fAlt)) /* Ctrl+Key */
269                 {
270                     iKey = vk & 0xBF;
271                 }
272                 else
273                 {
274                     iKey = uc;
275                 }
276             }
277         }
278     }
279 
280     if (iKey != 0)
281     {
282         key_hit = iKey;
283     }
284 
285     return (int)iKey;
286 }
287 
TTGetKey(void)288 unsigned int TTGetKey(void)
289 {
290     int iKey;
291     while (key_hit == 0xFFFFFFFFUL)
292     {
293         mykbhit(1);
294     }
295     iKey = key_hit;
296     key_hit = 0xFFFFFFFFUL;
297     return (unsigned int)iKey;
298 }
299 
TTScolor(unsigned int Attr)300 int TTScolor(unsigned int Attr)
301 {
302     color = Attr;
303     return 1;
304 }
305 
TTCurSet(int st)306 int TTCurSet(int st)
307 {
308     CONSOLE_CURSOR_INFO cci;
309     GetConsoleCursorInfo(HOutput, &cci);
310     cci.bVisible = st;
311     SetConsoleCursorInfo(HOutput, &cci);
312     return 0;
313 }
314 
TTgetxy(int * row,int * col)315 int TTgetxy(int *row, int *col)
316 {
317     *row = vrow;
318     *col = vcol;
319     return 1;
320 }
321 
TTdelay(int mil)322 int TTdelay(int mil)
323 {
324     Sleep((DWORD) mil);
325     return 0;
326 }
327 
TTSendMsg(unsigned int msg,int x,int y,unsigned int msgtype)328 void TTSendMsg(unsigned int msg, int x, int y, unsigned int msgtype)
329 {
330     if (((ebufin + 1) % EBUFSZ) != ebufout)
331     {
332         EVent[ebufin].msg = msg;
333         EVent[ebufin].x = x;
334         EVent[ebufin].y = y;
335         EVent[ebufin].msgtype = msgtype;
336         ebufin = (ebufin + 1) % EBUFSZ;
337     }
338 }
339 
collect_events(int delay)340 int collect_events(int delay)
341 {
342     if (mykbhit(0))
343     {
344         TTSendMsg(TTGetKey(), 0, 0, WND_WM_CHAR);
345     }
346     else if (delay)
347     {
348         TTdelay(50);
349     }
350     return 0;
351 }
352 
TTkopen(void)353 int TTkopen(void)
354 {
355     DWORD cmode;
356 
357     HInput = GetStdHandle(STD_INPUT_HANDLE);
358     HOutput = GetStdHandle(STD_OUTPUT_HANDLE);
359 
360     GetConsoleMode(HInput, (LPDWORD)&cmode);
361     SetConsoleMode(HInput, cmode & (~ENABLE_PROCESSED_INPUT));
362 
363 #ifdef KEYDEBUG
364     fTrace = fopen("ntkeys.trc", "w");
365     if (fTrace == NULL)
366     {
367         abort();
368     }
369 #endif
370 
371     return 0;
372 }
373 
TTkclose(void)374 int TTkclose(void)
375 {
376     CloseHandle(HInput);
377     HInput = INVALID_HANDLE_VALUE;
378     CloseHandle(HOutput);
379     HOutput = INVALID_HANDLE_VALUE;
380 
381 #ifdef KEYDEBUG
382     fclose(fTrace);
383 #endif
384 
385     return 0;
386 }
387 
MouseOFF(void)388 void MouseOFF(void)
389 {
390 }
391 
MouseON(void)392 void MouseON(void)
393 {
394 }
395 
MouseInit(void)396 void MouseInit(void)
397 {
398 }
399 
GetMouInfo(int * x,int * y)400 int GetMouInfo(int *x, int *y)
401 {
402     unused(x);
403     unused(y);
404     return 0;
405 }
406 
TTGetMsg(EVT * e)407 int TTGetMsg(EVT * e)
408 {
409     while (ebufin == ebufout)
410     {
411         collect_events(1);
412     }
413     e->msg = EVent[ebufout].msg;
414     e->x = EVent[ebufout].x;
415     e->y = EVent[ebufout].y;
416     e->msgtype = EVent[ebufout].msgtype;
417     e->id = 0;
418     ebufout = (ebufout + 1) % EBUFSZ;
419     return e->msg;
420 }
421 
TTPeekQue(void)422 int TTPeekQue(void)
423 {
424     collect_events(0);
425     return ebufin != ebufout;
426 }
427 
TTClearQue(void)428 void TTClearQue(void)
429 {
430     ebufin = ebufout;
431 }
432 
TTGetChr(void)433 int TTGetChr(void)
434 {
435     EVT e;
436     TTGetMsg(&e);
437     return e.msg;
438 }
439 
dv_running(void)440 int dv_running(void)
441 {
442     return 0;
443 }
444 
FullBuffer(void)445 static int FullBuffer(void)
446 {
447     if (((ebufin + 1) % EBUFSZ) != ebufout)
448     {
449         return 0;
450     }
451     else
452     {
453         return 1;
454     }
455 }
456 
TTStrWr(unsigned char * s,int row,int col,int len)457 int TTStrWr(unsigned char *s, int row, int col, int len)
458 {
459     DWORD i;
460     COORD coord;
461     LPWORD pwattr;
462     DWORD ntlen;
463 
464     if (len < 0)
465         len = strlen((char *)s);
466 
467     ntlen = len;
468 
469     if (len == 0)
470         return 1;
471 
472     pwattr = (LPWORD) malloc(len * sizeof *pwattr);
473     if (pwattr == NULL)
474     {
475         return 0;
476     }
477     coord.X = (SHORT) col;
478     coord.Y = (SHORT) row;
479     for (i = 0; i < len; i++)
480     {
481         *(pwattr + i) = color;
482     }
483     WriteConsoleOutputCharacterA(HOutput, s, (DWORD) len, coord, &ntlen);
484     WriteConsoleOutputAttribute(HOutput, pwattr, (DWORD) len, coord, &ntlen);
485     free(pwattr);
486     TTgotoxy(row, col + ntlen);
487     return 1;
488 }
489 
clearbox(int x1,int y1,int x2,int y2)490 static void clearbox(int x1, int y1, int x2, int y2)
491 {
492     COORD coord;
493     LPWORD pwattr;
494     char y, *pstr;
495     DWORD i, len, width;
496     width = x2 - x1 + 1;
497     pwattr = malloc(width * sizeof *pwattr);
498     if (pwattr == NULL)
499     {
500         return;
501     }
502     pstr = malloc(width);
503     if (pstr == NULL)
504     {
505         free(pwattr);
506         return;
507     }
508     for (i = 0; i < width; i++)
509     {
510         *(pwattr + i) = color;
511         *(pstr + i) = ' ';
512     }
513     for (y = y1; y <= y2; y++)
514     {
515         coord.X = (SHORT) x1;
516         coord.Y = (SHORT) y;
517         WriteConsoleOutputCharacterA(HOutput, pstr, width, coord, &len);
518         WriteConsoleOutputAttribute(HOutput, pwattr, width, coord, &len);
519     }
520     free(pwattr);
521     free(pstr);
522 }
523 
TTClear(int x1,int y1,int x2,int y2)524 int TTClear(int x1, int y1, int x2, int y2)
525 {
526     clearbox(x1, y1, x2, y2);
527     TTgotoxy(y1, x1);
528     return 1;
529 }
530 
TTEeol(void)531 int TTEeol(void)
532 {
533     clearbox(vcol, vrow, term.NCol -1, vrow);
534     TTgotoxy(vcol, vrow);
535     return 1;
536 }
537 
TTWriteStr(unsigned long * b,int len,int row,int col)538 int TTWriteStr(unsigned long *b, int len, int row, int col)
539 {
540     DWORD i, wlen;
541     COORD coord;
542     LPWORD pwattr;
543     unsigned char *pstr;
544 
545     pwattr = malloc(len * sizeof *pwattr);
546     if (pwattr == NULL)
547     {
548         return 0;
549     }
550     pstr = malloc(len);
551     if (pstr == NULL)
552     {
553         free(pwattr);
554         return 0;
555     }
556     for (i = 0; i < len; i++)
557     {
558         *(pstr + i) = *b & 0xff;
559         *(pwattr + i) = ((*b) >> 16) & 0xff;
560         b++;
561     }
562     coord.X = (SHORT) col;
563     coord.Y = (SHORT) row;
564     WriteConsoleOutputCharacterA(HOutput, pstr, len, coord, &wlen);
565     WriteConsoleOutputAttribute(HOutput, pwattr, len, coord, &wlen);
566     free(pwattr);
567     free(pstr);
568     TTgotoxy(row, col + len);
569     return 1;
570 }
571 
TTReadStr(unsigned long * b,int len,int row,int col)572 int TTReadStr(unsigned long *b, int len, int row, int col)
573 {
574     DWORD i, wlen;
575     COORD coord;
576     LPWORD pwattr;
577     unsigned char *pstr;
578 
579     pwattr = malloc(len * sizeof *pwattr);
580     if (pwattr == NULL)
581     {
582         return 0;
583     }
584     pstr = malloc(len);
585     if (pstr == NULL)
586     {
587         free(pwattr);
588         return 0;
589     }
590     coord.X = (SHORT) col;
591     coord.Y = (SHORT) row;
592     ReadConsoleOutputCharacterA(HOutput, pstr, len, coord, &wlen);
593     ReadConsoleOutputAttribute(HOutput, pwattr, len, coord, &wlen);
594     for (i = 0; i < len; i++)
595     {
596         b[i] = MAKECELL(pstr[i] & 0xFF, pwattr[i] & 0xFF);
597     }
598     free(pwattr);
599     free(pstr);
600     return 1;
601 }
602 
gettext(int x1,int y1,int x2,int y2,char * dest)603 static void gettext(int x1, int y1, int x2, int y2, char *dest)
604 {
605     DWORD i, len, width;
606     COORD coord;
607     LPWORD pwattr;
608     char y, *pstr;
609     width = x2 - x1 + 1;
610     pwattr = malloc(width * sizeof *pwattr);
611     if (pwattr == NULL)
612     {
613         return;
614     }
615     pstr = malloc(width);
616     if (pstr == NULL)
617     {
618         free(pwattr);
619         return;
620     }
621     for (y = y1; y <= y2; y++)
622     {
623         coord.X = (SHORT) x1;
624         coord.Y = (SHORT) y;
625         ReadConsoleOutputCharacterA(HOutput, pstr, width, coord, &len);
626         ReadConsoleOutputAttribute(HOutput, pwattr, width, coord, &len);
627         for (i = 0; i < width; i++)
628         {
629             *((unsigned char *)dest) = *(pstr + i);
630             dest++;
631             *((unsigned char *)dest) = (char)*(pwattr + i);
632             dest++;
633         }
634     }
635     free(pwattr);
636     free(pstr);
637 }
638 
puttext(int x1,int y1,int x2,int y2,char * srce)639 static void puttext(int x1, int y1, int x2, int y2, char *srce)
640 {
641     DWORD i, len, width;
642     COORD coord;
643     LPWORD pwattr;
644     char y, *pstr;
645     width = x2 - x1 + 1;
646     pwattr = malloc(width * sizeof *pwattr);
647     if (pwattr == NULL)
648     {
649         return;
650     }
651     pstr = malloc(width);
652     if (pstr == NULL)
653     {
654         free(pwattr);
655         return;
656     }
657     for (y = y1; y <= y2; y++)
658     {
659         for (i = 0; i < width; i++)
660         {
661             *(pstr + i) = *((unsigned char *)srce);
662             srce++;
663             *(pwattr + i) = *((unsigned char *)srce);
664             srce++;
665         }
666         coord.X = (SHORT) x1;
667         coord.Y = (SHORT) y;
668         WriteConsoleOutputCharacterA(HOutput, pstr, width, coord, &len);
669         WriteConsoleOutputAttribute(HOutput, pwattr, width, coord, &len);
670     }
671     free(pwattr);
672     free(pstr);
673 }
674 
TTScroll(int x1,int y1,int x2,int y2,int lines,int Dir)675 int TTScroll(int x1, int y1, int x2, int y2, int lines, int Dir)
676 {
677     int width, height;
678     char *buf;
679 
680     width = x2 - x1 + 1;
681     height = y2 - y1 + 1;
682     buf = malloc(width * height * 2);
683     if (buf == NULL)
684     {
685         return 0;
686     }
687 
688     if (Dir)
689     {
690         gettext(x1, y1, x2, y2, buf);
691         puttext(x1, y1, x2, y2 - lines, buf + (width * 2));
692     }
693     else
694     {
695         gettext(x1, y1, x2, y2, buf);
696         puttext(x1, y1 + lines, x2, y2, buf);
697     }
698 
699     free(buf);
700     return 1;
701 }
702