1 /*
2  *  OS2SCR.C
3  *
4  *  Written on 10-Jul-94 by John Dennis and released to the public domain.
5  *
6  *  Screen definitions & routines for the IBM PC under OS/2 only.  There
7  *  are three threads of execution in this module; the mouse, keyboard
8  *  and the main thread.
9  *
10  *  The mouse thread polls the OS/2 mouse subsystem - I know it *should*
11  *  be blocked, but unfortunately a thread that is blocked cannot be
12  *  killed and we have to explicitly release the mouse control for the
13  *  current screen group (when we exit), if another application wants to
14  *  be able to use the mouse.
15  *
16  *  The keyboard thread is blocked and only sends events when a key is
17  *  pressed.
18  */
19 
20 #include "winsys.h"
21 #include "memextra.h"
22 #include "specch.h"
23 
24 #define TERMDEF 1
25 
26 #define NCOL 80
27 #define NROW 25
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdarg.h>
33 
34 #define EBUFSZ    25
35 #define INCL_VIO
36 #define INCL_AVIO
37 #define INCL_KBD
38 #define INCL_MOU
39 #define INCL_DOSPROCESS
40 #define INCL_DOSINFOSEG
41 #include <os2.h>
42 
43 #include "mcompile.h"
44 
45 #ifndef KBDTRF_FINAL_CHAR_IN
46 #define KBDTRF_FINAL_CHAR_IN FINAL_CHAR_IN
47 #endif
48 
49 /* codepage 437 / 850 block graphics */
50 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";
51 
52 TERM term =
53 {
54     NCOL - 1,
55     NROW - 1,
56     0
57 };
58 
59 int vcol, vrow;                 /* cursor position         */
60 int color;                      /* current color on screen */
61 int cur_start = 0;
62 int cur_end = 0;
63 
64 static VIOMODEINFO fossil_data;
65 
66 static MOUEVENTINFO *pMouEvent = 0;   /* Mouse Event storage */
67 static USHORT MouHandle;        /* handle for the mouse */
68 static USHORT MouAvail = 0;     /* mouse services available ? */
69 static MOU mstatus = {0, 39, 12, 0, 0, 1, 1, 0};
70 static EVT EVent[EBUFSZ];       /* event circular queue */
71 static int ebufin = 0;          /* event in */
72 static int ebufout = 0;         /* event out */
73 
74 static int mykbhit(void);
75 static int FullBuffer(void);
76 static unsigned long hsec_time(void);
77 
TTBeginOutput(void)78 void TTBeginOutput(void) {}
TTEndOutput(void)79 void TTEndOutput(void) {}
80 
TTScolor(unsigned int Attr)81 int TTScolor(unsigned int Attr)
82 {
83     color = Attr & 0xFF; /* we don't need the F_ALTERNATE attribute! */
84     return 1;
85 }
86 
TTCurSet(int st)87 int TTCurSet(int st)
88 {
89     static USHORT oldstart = 0, oldstop = 0;
90     VIOCURSORINFO *pcur = xmalloc16(sizeof(VIOCURSORINFO));
91 
92     if (oldstart == 0)
93     {
94         if (cur_start != 0 && cur_end != 0)
95         {
96             /* save a user-defined cursor shape */
97             oldstart = (USHORT) cur_start;
98             oldstop = (USHORT) cur_end;
99         }
100         else
101         {
102             /* save the default cursor shape */
103             VioGetCurType((PVIOCURSORINFO) pcur, 0);
104             oldstart = pcur->yStart;
105             oldstop = pcur->cEnd;
106         }
107     }
108 
109     if (st)
110     {
111         pcur->yStart = oldstart;
112         pcur->cEnd = oldstop;
113         pcur->attr = 0;
114         pcur->cx = 0;
115         VioSetCurType((PVIOCURSORINFO) pcur, 0);
116     }
117     else
118     {
119         pcur->yStart = oldstart;
120         pcur->cEnd = oldstop;
121         pcur->attr = 0xFFFF;
122         pcur->cx = 0;
123         VioSetCurType((PVIOCURSORINFO) pcur, 0);
124     }
125 
126     xfree16(pcur);
127 
128     return 0;
129 }
130 
TTgotoxy(int row,int col)131 int TTgotoxy(int row, int col)
132 {
133     vrow = row;
134     vcol = col;
135     VioSetCurPos((short)row, (short)col, 0);
136     return 1;
137 }
138 
TTgetxy(int * row,int * col)139 int TTgetxy(int *row, int *col)
140 {
141     *row = vrow;
142     *col = vcol;
143     return 1;
144 }
145 
TTPutChr(unsigned int Ch)146 int TTPutChr(unsigned int Ch)
147 {
148     unsigned int *d = xmalloc16(sizeof(unsigned int));
149 
150     *d = ((unsigned)Ch & 0xFF) | (color << 8);
151     VioWrtCellStr((PCH) d, 2, (short)vrow, (short)vcol, 0);
152 
153     xfree16(d);
154 
155     return 1;
156 }
157 
TTWriteStr(unsigned long * b,int len,int row,int col)158 int TTWriteStr(unsigned long *b, int len, int row, int col)
159 {
160     unsigned short *ptr16;
161     int i;
162 
163     if (len == 0)
164     {
165         return 1;
166     }
167 
168     ptr16 = xmalloc16((short)(len * 2));
169 
170     for (i = 0; i < len; i++)
171     {
172         ptr16[i] =
173             (unsigned short)((b[i] & 0xFFUL) | ((b[i] >> 8) & 0xFF00UL));
174     }
175 
176     VioWrtCellStr((PCH) ptr16, (short)(len * 2), (short)row, (short)col & 0xFF, 0);
177     xfree16(ptr16);
178 
179     return 1;
180 }
181 
TTStrWr(unsigned char * s,int row,int col,int len)182 int TTStrWr(unsigned char *s, int row, int col, int len)
183 {
184     char *ptr16;
185 
186     if (len < 0)
187         len = strlen((char *)s);
188 
189     if (len == 0)
190     {
191         return 0;
192     }
193     ptr16 = xmalloc16(len);
194 
195     memmove(ptr16, s, len);
196     VioWrtCharStrAtt((char *)ptr16, (short)len, (short)row, (short)col,
197                      (PBYTE) &color, 0);
198     xfree16(ptr16);
199 
200     return 1;
201 }
202 
TTReadStr(unsigned long * b,int len,int row,int col)203 int TTReadStr(unsigned long *b, int len, int row, int col)
204 {
205     unsigned short l = (short)(len * 2);
206     unsigned short *ptr16;
207     int i;
208 
209     if (l == 0)
210     {
211         return 1;
212     }
213     ptr16 = xmalloc16(l);
214     VioReadCellStr((PCH) ptr16, &l, (short)row, (short)col, 0);
215     for (i = 0; i < len; i++)
216     {
217         b[i] = MAKECELL((ptr16[i] & 0xFF), ((ptr16[i] >> 8) & 0xFF));
218     }
219     xfree16(ptr16);
220 
221     return 1;
222 }
223 
TTScroll(int x1,int y1,int x2,int y2,int lines,int Dir)224 int TTScroll(int x1, int y1, int x2, int y2, int lines, int Dir)
225 {
226     unsigned char *scroll_fill = xmalloc16(2);
227 
228     if (Dir)
229     {
230         y2 = min(y2, term.NRow);
231         y1 = min(y1, term.NRow);
232         x1 = min(x1, term.NCol);
233         x2 = min(x2, term.NCol);
234         scroll_fill[0] = ' ';
235         scroll_fill[1] = (unsigned char)color;
236         if (lines == 0)
237         {
238             lines = -1;
239         }
240         VioScrollUp((short)y1, (short)x1, (short)y2, (short)x2,
241           (short)lines, (char *)scroll_fill, 0);
242     }
243     else
244     {
245         y2 = min(y2, term.NRow);
246         y1 = min(y1, term.NRow);
247         x1 = min(x1, term.NCol);
248         x2 = min(x2, term.NCol);
249         scroll_fill[0] = ' ';
250         scroll_fill[1] = (unsigned char)color;
251         if (lines == 0)
252         {
253             lines = -1;
254         }
255         VioScrollDn((short)y1, (short)x1, (short)y2, (short)x2,
256           (short)lines, (char *)scroll_fill, 0);
257     }
258     xfree16(scroll_fill);
259     return 1;
260 }
261 
TTClear(int x1,int y1,int x2,int y2)262 int TTClear(int x1, int y1, int x2, int y2)
263 {
264     TTScroll(x1, y1, x2, y2, 0, 1);
265     return 1;
266 }
267 
TTEeol(void)268 int TTEeol(void)
269 {
270     TTScroll(vcol, vrow, term.NCol - 1, vrow, 0, 1);
271     return 1;
272 }
273 
TTdelay(int mil)274 int TTdelay(int mil)
275 {
276     DosSleep((long)mil);
277     return (0);
278 }
279 
TTGetKey(void)280 unsigned int TTGetKey(void)
281 {
282     KBDKEYINFO *pki = xmalloc16(sizeof(KBDKEYINFO));
283     int retval;
284 
285     pki->chChar = pki->chScan = 0;
286     KbdCharIn(pki, IO_WAIT, 0);
287 
288     if (pki->chChar == 0xe0 && (pki->fbStatus & 2))
289     {
290         if (pki->chScan)
291         {
292             pki->chChar = 0;      /* Force Scan return */
293         }
294         else
295         {                       /* Get next block     */
296             pki->chChar = 0;
297             KbdCharIn(pki, IO_WAIT, 0);
298             if (!pki->chScan)
299             {                   /* Still no scan?     */
300                 pki->chScan = pki->chChar;  /* Move new char over */
301                 pki->chChar = 0;  /* Force its return  */
302             }
303             else
304             {
305                 pki->chChar = 0;  /* Force new scan     */
306             }
307         }
308     }
309     if (pki->chScan == 0xe0 && (pki->fbStatus & 2))
310     {
311         if (!pki->chChar)
312         {
313             pki->chScan = 0;
314             KbdCharIn(pki, IO_WAIT, 0);
315             if (!pki->chScan)
316             {                   /* Still no scan?     */
317                 pki->chScan = pki->chChar;  /* Move new char over */
318                 pki->chChar = 0;  /* Force its return  */
319             }
320             else
321             {
322                 pki->chChar = 0;  /* Force new scan     */
323             }
324         }
325         else
326         {
327             pki->chScan = 0;      /* Handle 0xe00d case */
328         }
329     }
330     if (pki->chChar)
331     {
332         pki->chScan = 0;
333     }
334 
335     retval = (unsigned int)((pki->chScan << 8) + (pki->chChar));
336     xfree16(pki);
337     return retval;
338 }
339 
TTSendMsg(unsigned int msg,int x,int y,unsigned int msgtype)340 void TTSendMsg(unsigned int msg, int x, int y, unsigned int msgtype)
341 {
342     if (((ebufin + 1) % EBUFSZ) != ebufout)
343     {
344         EVent[ebufin].msg = msg;
345         EVent[ebufin].x = x;
346         EVent[ebufin].y = y;
347         EVent[ebufin].msgtype = msgtype;
348         ebufin = (ebufin + 1) % EBUFSZ;
349     }
350 }
351 
352 #define CLICKMAX                 50  /* second max */
353 #define PULSE_PAUSE              2
354 #define REPEAT_PAUSE             800
355 
356 static unsigned long rtimer = 0;
357 static unsigned long ltimer = 0;
358 static unsigned long lpulse = 0;
359 static unsigned long rpulse = 0;
360 
collect_events(int delay)361 int collect_events(int delay)
362 {
363     USHORT wait = MOU_NOWAIT;
364     static int oy = 0, ox = 0;
365     int moved = 0;
366     int evt = 0;
367     int temp1, temp2;
368 
369 
370     if (MouAvail)
371     {
372         MouReadEventQue(pMouEvent, &wait, MouHandle);
373 
374         if (pMouEvent->time == 0)
375         {
376             if (mstatus.lbutton || mstatus.rbutton)
377             {
378                 if (mstatus.lbutton && hsec_time() > ltimer && hsec_time() > lpulse)
379                 {
380                     lpulse = hsec_time() + PULSE_PAUSE;
381                     TTSendMsg(LMOU_RPT, ox, oy, WND_WM_MOUSE);
382                 }
383                 else if (delay)
384                 {
385                     DosSleep(1L);
386                 }
387 
388                 if (mstatus.rbutton && hsec_time() > rtimer && hsec_time() > rpulse)
389                 {
390                     rpulse = hsec_time() + PULSE_PAUSE;
391                     TTSendMsg(RMOU_RPT, ox, oy, WND_WM_MOUSE);
392                 }
393                 else if (delay)
394                 {
395                     DosSleep(1L);
396                 }
397             }
398             else if (delay)
399             {
400                 DosSleep(1L);
401             }
402         }
403         else
404         {
405             temp1 = ((pMouEvent->fs & MOUSE_BN1_DOWN) || (pMouEvent->fs & MOUSE_MOTION_WITH_BN1_DOWN));
406             temp2 = ((pMouEvent->fs & MOUSE_BN2_DOWN) || (pMouEvent->fs & MOUSE_MOTION_WITH_BN2_DOWN));
407             evt = 0;
408 
409             if (pMouEvent->col != ox || pMouEvent->row != oy)
410             {
411                 ox = mstatus.x = pMouEvent->col;
412                 oy = mstatus.y = pMouEvent->row;
413             }
414             moved = 1;
415 
416             if (mstatus.lrelease && temp1)
417             {
418                 evt = 1;
419                 mstatus.lbutton = 1;
420                 mstatus.lrelease = 0;
421                 lpulse = hsec_time() + PULSE_PAUSE;
422                 ltimer = hsec_time() + CLICKMAX;
423                 TTSendMsg(MOU_LBTDN, ox, oy, WND_WM_MOUSE);
424             }
425             if (mstatus.lbutton && !temp1)
426             {
427                 evt = 1;
428                 mstatus.lbutton = 0;
429                 mstatus.lrelease = 1;
430                 TTSendMsg(MOU_LBTUP, ox, oy, WND_WM_MOUSE);
431 
432                 if (hsec_time() < ltimer)
433                 {
434                     TTSendMsg(LMOU_CLCK, ox, oy, WND_WM_MOUSE);
435                 }
436 
437                 ltimer = 0;
438             }
439             if (mstatus.rrelease && temp2)
440             {
441                 evt = 1;
442                 mstatus.rbutton = 1;
443                 mstatus.rrelease = 0;
444                 rpulse = hsec_time() + PULSE_PAUSE;
445                 rtimer = hsec_time() + CLICKMAX;
446                 TTSendMsg(MOU_RBTDN, ox, oy, WND_WM_MOUSE);
447             }
448             if (mstatus.rbutton && !temp2)
449             {
450                 evt = 1;
451                 mstatus.rbutton = 0;
452                 mstatus.rrelease = 1;
453                 TTSendMsg(MOU_RBTUP, ox, oy, WND_WM_MOUSE);
454 
455                 if (hsec_time() < rtimer)
456                 {
457                     TTSendMsg(RMOU_CLCK, ox, oy, WND_WM_MOUSE);
458                 }
459 
460                 rtimer = 0;
461             }
462             if ((moved && evt) || ((mstatus.rbutton || mstatus.lbutton) && moved))
463             {
464                 TTSendMsg(MOUSE_EVT, ox, oy, WND_WM_MOUSE);
465             }
466         }
467         if (mykbhit())
468         {
469             TTSendMsg(TTGetKey(), 0, 0, WND_WM_CHAR);
470         }
471         else if (delay)
472         {
473             if (MouAvail)
474             {
475                 DosSleep(1L);
476             }
477             else
478             {
479                 DosSleep(50L);
480             }
481         }
482     }
483     else
484     {
485         if (mykbhit())
486         {
487             TTSendMsg(TTGetKey(), 0, 0, WND_WM_CHAR);
488         }
489         else if (delay)
490         {
491             if (MouAvail)
492             {
493                 DosSleep(1L);
494             }
495             else
496             {
497                 DosSleep(50L);
498             }
499         }
500     }
501     return 0;
502 }
503 
TTkopen(void)504 int TTkopen(void)
505 {
506     return (0);
507 }
508 
TTkclose(void)509 int TTkclose(void)
510 {
511     return (0);
512 }
513 
MouseOFF(void)514 void MouseOFF(void)
515 {
516     NOPTRRECT *pmouRect = xmalloc16(sizeof(NOPTRRECT));
517 
518     if (!MouAvail)
519     {
520         return;
521     }
522 
523     pmouRect->row = 0;
524     pmouRect->col = 0;
525     pmouRect->cRow = (short)(term.NRow - 1);
526     pmouRect->cCol = (short)(term.NCol - 1);
527     MouRemovePtr(pmouRect, MouHandle);
528     xfree16(pmouRect);
529 }
530 
MouseON(void)531 void MouseON(void)
532 {
533     if (!MouAvail)
534     {
535         return;
536     }
537     MouDrawPtr(MouHandle);
538 }
539 
MouseInit(void)540 void MouseInit(void)
541 {
542     USHORT MouMask = MOUSE_MOTION | MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_BN1_DOWN | MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_BN2_DOWN | MOUSE_MOTION_WITH_BN3_DOWN | MOUSE_BN3_DOWN;
543 
544     if (term.Abil & NOMOUSE)
545     {
546         return;
547     }
548 
549     if (MouOpen(0L, &MouHandle))
550     {
551         MouAvail = 0;
552         return;
553     }
554 
555     MouAvail = 1;
556     if (pMouEvent == 0)
557     {
558         pMouEvent = xmalloc16(sizeof(MOUEVENTINFO));
559     }
560 
561     MouSetEventMask(&MouMask, MouHandle);
562 }
563 
GetMouInfo(int * x,int * y)564 int GetMouInfo(int *x, int *y)
565 {
566     if (!MouAvail)
567     {
568         return 0;
569     }
570     collect_events(0);
571     *x = mstatus.x;
572     *y = mstatus.y;
573     return 0;
574 }
575 
TTGetMsg(EVT * e)576 int TTGetMsg(EVT * e)
577 {
578     while (ebufin == ebufout)
579     {
580         collect_events(1);
581     }
582     e->msg = EVent[ebufout].msg;
583     e->x = EVent[ebufout].x;
584     e->y = EVent[ebufout].y;
585     e->msgtype = EVent[ebufout].msgtype;
586     e->id = 0;
587     ebufout = (ebufout + 1) % EBUFSZ;
588     return e->msg;
589 }
590 
TTPeekQue(void)591 int TTPeekQue(void)
592 {
593     collect_events(0);
594     return (ebufin != ebufout);
595 }
596 
TTClearQue(void)597 void TTClearQue(void)
598 {
599     ebufin = ebufout;
600 }
601 
TTGetChr(void)602 int TTGetChr(void)
603 {
604     EVT e;
605     TTGetMsg(&e);
606     return e.msg;
607 }
608 
TTopen(void)609 int TTopen(void)
610 {
611     KBDINFO *pki = xmalloc16(sizeof(KBDINFO));
612     fossil_data.cb = 2 * sizeof(fossil_data);
613     VioGetMode(&fossil_data, 0);  /* Get mode info      */
614     term.NCol = fossil_data.col;  /* Maximum 'X' value  */
615     term.NRow = fossil_data.row;  /* Maximum 'Y' value  */
616     pki->cb = sizeof(KBDINFO);      /* Set binary keyboard mode */
617     pki->fsMask = KEYBOARD_BINARY_MODE;
618     KbdSetStatus(pki, 0);
619     vcol = vrow = 0;
620     color = 0x07;
621     TTkopen();
622     MouseInit();
623     xfree16(pki);
624     return 1;
625 }
626 
TTclose(void)627 int TTclose(void)
628 {
629     TTkclose();
630     if (MouAvail)
631     {
632         if (pMouEvent != 0)
633         {
634             xfree16(pMouEvent);
635             pMouEvent = 0;
636         }
637 
638         MouClose(MouHandle);
639     }
640     return 1;
641 }
642 
643 
644 #pragma warn -par
645 
646 /*
647  * Configure the terminal. This must be called *before* TTopen!
648  *
649  * The OS/2 VIO terminal does not need any configuration.
650  *
651  */
652 
TTconfigure(const char * keyword,const char * value)653 int TTconfigure(const char *keyword, const char *value)
654 {
655     return 0;
656 }
657 
658 #pragma warn +par
659 
660 
mykbhit(void)661 static int mykbhit(void)
662 {
663     KBDKEYINFO *pki;
664     int retval;
665 
666     if (FullBuffer())
667     {
668         return (0);
669     }
670 
671     pki = xmalloc16(sizeof(KBDKEYINFO));
672     pki->fbStatus = 0;
673     KbdPeek(pki, 0);
674     retval = pki->fbStatus & KBDTRF_FINAL_CHAR_IN ? 1 : 0;
675     xfree16(pki);
676     return retval;
677 }
678 
dv_running(void)679 int dv_running(void)
680 {
681     return 0;
682 }
683 
FullBuffer(void)684 static int FullBuffer(void)
685 {
686     if (((ebufin + 1) % EBUFSZ) != ebufout)
687     {
688         return 0;
689     }
690     else
691     {
692         return 1;
693     }
694 }
695 
hsec_time(void)696 static unsigned long hsec_time(void)
697 {
698     DATETIME pdt;
699     DosGetDateTime(&pdt);
700     return (pdt.year * 3214080000UL) + (pdt.month * 267840000L) +
701       (pdt.day * 8640000L) + (pdt.hours * 360000L) +
702       (pdt.minutes * 6000L) + (pdt.seconds * 100L) +
703       pdt.hundredths;
704 }
705