1 /*
2 Copyright (C) 2004-2017,2018 John E. Davis
3 
4 This file is part of the S-Lang Library.
5 
6 The S-Lang Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10 
11 The S-Lang Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 USA.
20 */
21 
22 #include "slinclud.h"
23 
24 #include "slang.h"
25 #include "_slang.h"
26 
27 #define INCL_BASE
28 #define INCL_NOPM
29 #define INCL_VIO
30 #define INCL_KBD
31 #define INCL_DOS
32 #if 0
33 # define INCL_DOSSEMAPHORES
34 #endif
35 #ifdef LONG
36 #undef LONG
37 #endif
38 #ifdef VOID
39 #undef VOID
40 #endif
41 #include <os2.h>
42 
43 #include <signal.h>
44 #include <process.h>
45 
46 static TID SLos2_threadID = (TID) 0;
47 
48 KBDINFO	initialKbdInfo;	/* keyboard info */
49 
50 /* Code to read keystrokes in a separate thread */
51 
52 typedef struct kbdcodes {
53   UCHAR ascii;
54   UCHAR scan;
55 /*  USHORT shift; */
56 } KBDCODES;
57 
58 #define BUFFER_LEN 4096
59 static KBDCODES threadKeys[BUFFER_LEN];
60 static int atEnd = 0;
61 static int startBuf;
62 static int endBuf;
63 
64 /* Original code used semaphores to control access to threadKeys.
65  * It is expected that the semaphore code will be deleted after 0.97.
66 */
67 #if 0
68 
69 #ifdef __os2_16__
70 
71 typedef USHORT APIRET;
72 static HSEM Hmtx;
73 
74 #define DosRequestMutexSem(hmtx,timeout) DosSemRequest(hmtx,timeout)
75 #define DosReleaseMutexSem(hmtx) DosSemClear(hmtx)
76 #define DosCloseMutexSem(hmtx) DosCloseSem(hmtx)
77 
78 #else /* !defined(__os2_16__) */
79 
80 static HMTX Hmtx;     /* Mutex Semaphore */
81 
82 #endif
83 
84 static APIRET CreateSem(void)
85 {
86 #ifdef __os2_16__
87   char SemName[32];
88   sprintf(SemName, "\\SEM\\jed\\%u", getpid());
89   return ( DosCreateSem (0, &Hmtx, SemName) );
90 #else
91   return ( DosCreateMutexSem (NULL, &Hmtx, 0, 0) );
92 #endif
93 }
94 
95 static APIRET RequestSem(void)
96 {
97   return ( DosRequestMutexSem (Hmtx, -1) );
98 }
99 
100 static APIRET ReleaseSem(void)
101 {
102   return ( DosReleaseMutexSem (Hmtx) );
103 }
104 
105 static APIRET CloseSem(void)
106 {
107   return( DosCloseMutexSem (Hmtx) );
108 }
109 
110 #else
111 
112 #define CreateSem()
113 #define RequestSem()
114 #define ReleaseSem()
115 #define CloseSem()
116 
117 #endif
118 
set_kbd(void)119 static void set_kbd(void)
120 {
121   KBDINFO kbdInfo;
122 
123   kbdInfo = initialKbdInfo;
124   kbdInfo.fsMask &= ~0x0001;		/* not echo on		*/
125   kbdInfo.fsMask |= 0x0002;		/* echo off		*/
126   kbdInfo.fsMask &= ~0x0008;		/* cooked mode off	*/
127   kbdInfo.fsMask |= 0x0004;		/* raw mode		*/
128   kbdInfo.fsMask &= ~0x0100;		/* shift report	off	*/
129   KbdSetStatus(&kbdInfo, 0);
130 }
131 
thread_getkey()132 static void thread_getkey ()
133 {
134    KBDKEYINFO keyInfo;
135    int n;
136 
137    while (!atEnd) {     /* at end is a flag */
138       set_kbd();
139       KbdCharIn(&keyInfo, IO_NOWAIT, 0);       /* get a character	*/
140       if (keyInfo.fbStatus & 0x040) {          /* found a char process it */
141 	if (keyInfo.chChar == SLang_Abort_Char) {
142 	  if (SLang_Ignore_User_Abort == 0) SLang_set_error (SL_USER_BREAK);
143 	  SLKeyBoard_Quit = 1;
144 	}
145 	n = (endBuf + 1) % BUFFER_LEN;
146 	if (n == startBuf) {
147 	  DosBeep (500, 20);
148 	  KbdFlushBuffer(0);
149 	  continue;
150 	}
151 	RequestSem();
152 	threadKeys [n].ascii = keyInfo.chChar;
153 	threadKeys [n].scan = keyInfo.chScan;
154 /*	threadKeys [n].shift = keyInfo.fsState; */
155 	endBuf = n;
156 	ReleaseSem();
157       } else                    /* no char available*/
158 	DosSleep (20);
159    }
160 }
161 
thread_code(void * Args)162 static void thread_code (void *Args)
163 {
164   (void) Args;
165   startBuf = -1;      /* initialize the buffer pointers */
166   endBuf = -1;
167   thread_getkey ();
168   atEnd = 0;          /* reset the flag */
169   _endthread();
170 }
171 
172 /* The code below is in the main thread */
173 
SLang_init_tty(int abort_char,int dum2,int dum3)174 int SLang_init_tty(int abort_char, int dum2, int dum3)
175 {
176   VIOCURSORINFO cursorInfo, OldcursorInfo;
177 
178   (void) dum2; (void) dum3;
179    if (abort_char == -1) abort_char = 3;   /* ^C */
180    SLang_Abort_Char = abort_char;
181    SLKeyBoard_Quit = 0;
182 
183   /*  set ^C off */
184   signal (SIGINT, SIG_IGN);
185   signal (SIGBREAK, SIG_IGN);
186 
187   /* set up the keyboard */
188 
189   initialKbdInfo.cb = sizeof(initialKbdInfo);
190   KbdGetStatus(&initialKbdInfo, 0);
191   set_kbd();
192 
193   /* open a semaphore */
194   CreateSem();
195 
196   /* start a separate thread to read the keyboard */
197 #if defined(__BORLANDC__)
198   SLos2_threadID = _beginthread (thread_code, 8096, NULL);
199 #else
200   SLos2_threadID = _beginthread (thread_code, NULL,  8096, NULL);
201 #endif
202 
203    if ((int)SLos2_threadID == -1)
204      {
205 	SLang_exit_error ("init_tty: Error starting keyboard thread.");
206      }
207 
208   VioGetCurType (&OldcursorInfo, 0);
209   cursorInfo.yStart = 1;
210   cursorInfo.cEnd = 15;
211   cursorInfo.cx = 1;
212   cursorInfo.attr = 1;
213   if (VioSetCurType (&cursorInfo, 0))
214     VioSetCurType (&OldcursorInfo, 0);   /* reset to previous value */
215 
216   return 0;
217 }
218 
SLang_reset_tty(void)219 void SLang_reset_tty (void)
220 {
221    if (0 == SLos2_threadID) return;
222    atEnd = 1;                      /* set flag and wait until thread ends */
223    while (atEnd) {DosSleep (0);}
224 
225    CloseSem();
226 
227    /* close the keyboard */
228    KbdSetStatus(&initialKbdInfo, 0); /* restore original state	*/
229    SLos2_threadID = 0;
230 }
231 
232 #define keyWaiting() (endBuf != startBuf)
233 
234 /* sleep for *tsecs tenths of a sec waiting for input */
235 
_pSLsys_input_pending(int tsecs)236 int _pSLsys_input_pending(int tsecs)
237 {
238    if (keyWaiting()) return 1;
239 
240    /* Convert tsecs to units of 20 ms */
241    tsecs = tsecs * 5;
242 
243    /* If tsecs is less than 0, it represents millisecs */
244    if (tsecs < 0)
245      tsecs = -tsecs / 100;
246 
247    while (tsecs > 0)
248      {
249 	DosSleep(20);		       /* 20 ms or 1/50 sec */
250 	if (keyWaiting()) break;
251 	tsecs--;
252      }
253    return (tsecs);
254 }
255 
_pSLsys_getkey()256 unsigned int _pSLsys_getkey ()
257 {
258    unsigned int c;
259    unsigned char scan;
260 
261 
262    if (!keyWaiting())
263      {
264 	int tsecs = 300;
265 	while (!_pSLsys_input_pending(tsecs))
266 	  ;
267      }
268 
269    /* read codes from buffer */
270    RequestSem();
271    startBuf = (startBuf + 1) % BUFFER_LEN;
272    c = threadKeys [startBuf].ascii;
273    scan = threadKeys [startBuf].scan;
274    ReleaseSem();
275 
276    switch (c)
277      {
278       case 8:
279 	if (scan == 0x0E) c = 127;
280 	break;
281 
282       case 0xE0:
283       case 0:
284 	c = _pSLpc_convert_scancode (scan, 0, 1);
285 	break;
286 
287       default:
288 	break;
289      }
290    return (c);
291 }
292 
SLang_set_abort_signal(void (* dum)(int))293 int SLang_set_abort_signal (void (*dum)(int))
294 {
295    (void) dum;
296    return 0;
297 }
298 
SLtt_set_mouse_mode(int mode,int force)299 int SLtt_set_mouse_mode (int mode, int force)
300 {
301    /* FIXME: Priority=low */
302    (void) mode;
303    (void) force;
304 
305    return -1;
306 }
307