]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/os2/event.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / os2 / event.c
1 /****************************************************************************
2 *
3 *                   SciTech OS Portability Manager Library
4 *
5 *  ========================================================================
6 *
7 *    The contents of this file are subject to the SciTech MGL Public
8 *    License Version 1.0 (the "License"); you may not use this file
9 *    except in compliance with the License. You may obtain a copy of
10 *    the License at http://www.scitechsoft.com/mgl-license.txt
11 *
12 *    Software distributed under the License is distributed on an
13 *    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 *    implied. See the License for the specific language governing
15 *    rights and limitations under the License.
16 *
17 *    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 *
19 *    The Initial Developer of the Original Code is SciTech Software, Inc.
20 *    All Rights Reserved.
21 *
22 *  ========================================================================
23 *
24 * Language:     ANSI C
25 * Environment:  IBM PC (OS/2)
26 *
27 * Description:  OS/2 implementation for the SciTech cross platform
28 *               event library.
29 *
30 ****************************************************************************/
31
32 /*---------------------------- Global Variables ---------------------------*/
33
34 /* Define generous keyboard monitor circular buffer size to minimize
35  * the danger of losing keystrokes
36  */
37 #define KEYBUFSIZE  (EVENTQSIZE + 10)
38
39 static int      oldMouseState;          /* Old mouse state               */
40 static ulong    oldKeyMessage;          /* Old keyboard state            */
41 static ushort   keyUpMsg[256] = {0};    /* Table of key up messages      */
42 static int      rangeX,rangeY;          /* Range of mouse coordinates    */
43 HMOU            _EVT_hMouse;            /* Handle to the mouse driver    */
44 HMONITOR        _EVT_hKbdMon;           /* Handle to the keyboard driver */
45 TID             kbdMonTID = 0;          /* Keyboard monitor thread ID    */
46 HEV             hevStart;               /* Start event semaphore handle  */
47 BOOL            bMonRunning;            /* Flag set if monitor thread OK */
48 HMTX            hmtxKeyBuf;             /* Mutex protecting key buffer   */
49 KEYPACKET       keyMonPkts[KEYBUFSIZE]; /* Array of monitor key packets  */
50 int             kpHead = 0;             /* Key packet buffer head        */
51 int             kpTail = 0;             /* Key packet buffer tail        */
52
53 /*---------------------------- Implementation -----------------------------*/
54
55 /* These are not used under OS/2 */
56 #define _EVT_disableInt()       1
57 #define _EVT_restoreInt(flags)
58
59 /****************************************************************************
60 PARAMETERS:
61 scanCode    - Scan code to test
62
63 REMARKS:
64 This macro determines if a specified key is currently down at the
65 time that the call is made.
66 ****************************************************************************/
67 #define _EVT_isKeyDown(scanCode)    (keyUpMsg[scanCode] != 0)
68
69 /****************************************************************************
70 REMARKS:
71 This function is used to return the number of ticks since system
72 startup in milliseconds. This should be the same value that is placed into
73 the time stamp fields of events, and is used to implement auto mouse down
74 events.
75 ****************************************************************************/
76 ulong _EVT_getTicks(void)
77 {
78     ULONG   count;
79     DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &count, sizeof(ULONG) );
80     return count;
81 }
82
83 /****************************************************************************
84 REMARKS:
85 Converts a mickey movement value to a pixel adjustment value.
86 ****************************************************************************/
87 static int MickeyToPixel(
88     int mickey)
89 {
90     // TODO: We can add some code in here to handle 'acceleration' for
91     //       the mouse cursor. For now just use the mickeys.
92     return mickey;
93 }
94
95 /* Some useful defines any typedefs used in the keyboard handling */
96 #define KEY_RELEASE             0x40
97
98 /****************************************************************************
99 REMARKS:
100 Pumps all messages in the message queue from OS/2 into our event queue.
101 ****************************************************************************/
102 static void _EVT_pumpMessages(void)
103 {
104     KBDINFO         keyInfo;        /* Must not cross a 64K boundary */
105     KBDKEYINFO      key;            /* Must not cross a 64K boundary */
106     MOUQUEINFO      mqueue;         /* Must not cross a 64K boundary */
107     MOUEVENTINFO    mouse;          /* Must not cross a 64K boundary */
108     ushort          mWait;          /* Must not cross a 64K boundary */
109     KEYPACKET       kp;             /* Must not cross a 64K boundary */
110     event_t         evt;
111     int             scan;
112     ibool           noInput = TRUE; /* Flag to determine if any input was available */
113
114     /* First of all, check if we should do any session switch work */
115     __PM_checkConsoleSwitch();
116
117     /* Pump all keyboard messages from our circular buffer */
118     for (;;) {
119         /* Check that the monitor thread is still running */
120         if (!bMonRunning)
121             PM_fatalError("Keyboard monitor thread died!");
122
123         /* Protect keypacket buffer with mutex */
124         DosRequestMutexSem(hmtxKeyBuf, SEM_INDEFINITE_WAIT);
125         if (kpHead == kpTail) {
126             DosReleaseMutexSem(hmtxKeyBuf);
127             break;
128             }
129
130         noInput = FALSE;
131
132         /* Read packet from circular buffer and remove it */
133         memcpy(&kp, &keyMonPkts[kpTail], sizeof(KEYPACKET));
134         if (++kpTail == KEYBUFSIZE)
135             kpTail = 0;
136         DosReleaseMutexSem(hmtxKeyBuf);
137
138         /* Compensate for the 0xE0 character */
139         if (kp.XlatedScan && kp.XlatedChar == 0xE0)
140             kp.XlatedChar = 0;
141
142         /* Determine type of keyboard event */
143         memset(&evt,0,sizeof(evt));
144         if (kp.KbdDDFlagWord & KEY_RELEASE)
145             evt.what = EVT_KEYUP;
146         else
147             evt.what = EVT_KEYDOWN;
148
149         /* Convert keyboard codes */
150         scan = kp.MonFlagWord >> 8;
151         if (evt.what == EVT_KEYUP) {
152             /* Get message for keyup code from table of cached down values */
153             evt.message = keyUpMsg[scan];
154             keyUpMsg[scan] = 0;
155             oldKeyMessage = -1;
156             }
157         else {
158             evt.message = ((ulong)scan << 8) | kp.XlatedChar;
159             if (evt.message == keyUpMsg[scan]) {
160                 evt.what = EVT_KEYREPEAT;
161                 evt.message |= 0x10000;
162                 }
163             oldKeyMessage = evt.message & 0x0FFFF;
164             keyUpMsg[scan] = (ushort)evt.message;
165             }
166
167          /* Convert shift state modifiers */
168          if (kp.u.ShiftState & 0x0001)
169              evt.modifiers |= EVT_RIGHTSHIFT;
170          if (kp.u.ShiftState & 0x0002)
171              evt.modifiers |= EVT_LEFTSHIFT;
172          if (kp.u.ShiftState & 0x0100)
173              evt.modifiers |= EVT_LEFTCTRL;
174          if (kp.u.ShiftState & 0x0200)
175              evt.modifiers |= EVT_LEFTALT;
176          if (kp.u.ShiftState & 0x0400)
177              evt.modifiers |= EVT_RIGHTCTRL;
178          if (kp.u.ShiftState & 0x0800)
179              evt.modifiers |= EVT_RIGHTALT;
180          EVT.oldMove = -1;
181
182          /* Add time stamp and add the event to the queue */
183          evt.when = key.time;
184          if (EVT.count < EVENTQSIZE)
185              addEvent(&evt);
186          }
187
188     /* Don't just flush because that terminally confuses the monitor */
189     do {
190         KbdCharIn(&key, IO_NOWAIT, 0);
191         } while (key.fbStatus & KBDTRF_FINAL_CHAR_IN);
192
193     /* Pump all mouse messages */
194     KbdGetStatus(&keyInfo,0);
195     /* Check return code - mouse may not be operational!! */
196     if (MouGetNumQueEl(&mqueue,_EVT_hMouse) == NO_ERROR) {
197         while (mqueue.cEvents) {
198             while (mqueue.cEvents--) {
199                 memset(&evt,0,sizeof(evt));
200                 mWait = MOU_NOWAIT;
201                 MouReadEventQue(&mouse,&mWait,_EVT_hMouse);
202
203                 /* Update the mouse position. We get the mouse coordinates
204                  * in mickeys so we have to translate these into pixels and
205                  * move our mouse position. If we don't do this, OS/2 gives
206                  * us the coordinates in character positions since it still
207                  * thinks we are in text mode!
208                  */
209                 EVT.mx += MickeyToPixel(mouse.col);
210                 EVT.my += MickeyToPixel(mouse.row);
211                 if (EVT.mx < 0) EVT.mx = 0;
212                 if (EVT.my < 0) EVT.my = 0;
213                 if (EVT.mx > rangeX)    EVT.mx = rangeX;
214                 if (EVT.my > rangeY)    EVT.my = rangeY;
215                 evt.where_x = EVT.mx;
216                 evt.where_y = EVT.my;
217                 evt.relative_x = mouse.col;
218                 evt.relative_y = mouse.row;
219                 evt.when = key.time;
220                 if (mouse.fs & (MOUSE_BN1_DOWN | MOUSE_MOTION_WITH_BN1_DOWN))
221                     evt.modifiers |= EVT_LEFTBUT;
222                 if (mouse.fs & (MOUSE_BN2_DOWN | MOUSE_MOTION_WITH_BN2_DOWN))
223                     evt.modifiers |= EVT_RIGHTBUT;
224                 if (mouse.fs & (MOUSE_BN3_DOWN | MOUSE_MOTION_WITH_BN3_DOWN))
225                     evt.modifiers |= EVT_MIDDLEBUT;
226                 if (keyInfo.fsState & 0x0001)
227                     evt.modifiers |= EVT_RIGHTSHIFT;
228                 if (keyInfo.fsState & 0x0002)
229                     evt.modifiers |= EVT_LEFTSHIFT;
230                 if (keyInfo.fsState & 0x0100)
231                     evt.modifiers |= EVT_LEFTCTRL;
232                 if (keyInfo.fsState & 0x0200)
233                     evt.modifiers |= EVT_LEFTALT;
234                 if (keyInfo.fsState & 0x0400)
235                     evt.modifiers |= EVT_RIGHTCTRL;
236                 if (keyInfo.fsState & 0x0800)
237                     evt.modifiers |= EVT_RIGHTALT;
238
239                 /* Check for left mouse click events */
240                 /* 0x06 == (MOUSE_BN1_DOWN | MOUSE_MOTION_WITH_BN1_DOWN) */
241                 if (((mouse.fs & 0x0006) && !(oldMouseState & 0x0006))
242                         || (!(mouse.fs & 0x0006) && (oldMouseState & 0x0006))) {
243                     if (mouse.fs & 0x0006)
244                         evt.what = EVT_MOUSEDOWN;
245                     else
246                         evt.what = EVT_MOUSEUP;
247                     evt.message = EVT_LEFTBMASK;
248                     EVT.oldMove = -1;
249                     if (EVT.count < EVENTQSIZE)
250                         addEvent(&evt);
251                     }
252
253                 /* Check for right mouse click events */
254                 /* 0x0018 == (MOUSE_BN2_DOWN | MOUSE_MOTION_WITH_BN2_DOWN) */
255                 if (((mouse.fs & 0x0018) && !(oldMouseState & 0x0018))
256                         || (!(mouse.fs & 0x0018) && (oldMouseState & 0x0018))) {
257                     if (mouse.fs & 0x0018)
258                         evt.what = EVT_MOUSEDOWN;
259                     else
260                         evt.what = EVT_MOUSEUP;
261                     evt.message = EVT_RIGHTBMASK;
262                     EVT.oldMove = -1;
263                     if (EVT.count < EVENTQSIZE)
264                         addEvent(&evt);
265                     }
266
267                 /* Check for middle mouse click events */
268                 /* 0x0060 == (MOUSE_BN3_DOWN | MOUSE_MOTION_WITH_BN3_DOWN) */
269                 if (((mouse.fs & 0x0060) && !(oldMouseState & 0x0060))
270                         || (!(mouse.fs & 0x0060) && (oldMouseState & 0x0060))) {
271                     if (mouse.fs & 0x0060)
272                         evt.what = EVT_MOUSEDOWN;
273                     else
274                         evt.what = EVT_MOUSEUP;
275                     evt.message = EVT_MIDDLEBMASK;
276                     EVT.oldMove = -1;
277                     if (EVT.count < EVENTQSIZE)
278                         addEvent(&evt);
279                     }
280
281                 /* Check for mouse movement event */
282                 if (mouse.fs & 0x002B) {
283                     evt.what = EVT_MOUSEMOVE;
284                     if (EVT.oldMove != -1) {
285                         EVT.evtq[EVT.oldMove].where_x = evt.where_x;/* Modify existing one  */
286                         EVT.evtq[EVT.oldMove].where_y = evt.where_y;
287                         }
288                     else {
289                         EVT.oldMove = EVT.freeHead; /* Save id of this move event   */
290                         if (EVT.count < EVENTQSIZE)
291                             addEvent(&evt);
292                         }
293                     }
294
295                 /* Save current mouse state */
296                 oldMouseState = mouse.fs;
297                 }
298             MouGetNumQueEl(&mqueue,_EVT_hMouse);
299             }
300             noInput = FALSE;
301         }
302
303     /* If there was no input available, give up the current timeslice
304      * Note: DosSleep(0) will effectively do nothing if no other thread is ready. Hence
305      * DosSleep(0) will still use 100% CPU _but_ should not interfere with other programs.
306      */
307     if (noInput)
308         DosSleep(0);
309 }
310
311 /****************************************************************************
312 REMARKS:
313 This macro/function is used to converts the scan codes reported by the
314 keyboard to our event libraries normalised format. We only have one scan
315 code for the 'A' key, and use shift modifiers to determine if it is a
316 Ctrl-F1, Alt-F1 etc. The raw scan codes from the keyboard work this way,
317 but the OS gives us 'cooked' scan codes, we have to translate them back
318 to the raw format.
319 ****************************************************************************/
320 #define _EVT_maskKeyCode(evt)
321
322 /****************************************************************************
323 REMARKS:
324 Keyboard monitor thread. Needed to catch both keyup and keydown events.
325 ****************************************************************************/
326 static void _kbdMonThread(
327     void *params)
328 {
329     APIRET       rc;
330     KEYPACKET    kp;
331     USHORT       count = sizeof(KEYPACKET);
332     MONBUF       monInbuf;
333     MONBUF       monOutbuf;
334     int          kpNew;
335
336     /* Raise thread priority for higher responsiveness */
337     DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
338     monInbuf.cb  = sizeof(monInbuf) - sizeof(monInbuf.cb);
339     monOutbuf.cb = sizeof(monOutbuf) - sizeof(monOutbuf.cb);
340     bMonRunning = FALSE;
341
342     /* Register the buffers to be used for monitoring for current session */
343     if (DosMonReg(_EVT_hKbdMon, &monInbuf, (ULONG*)&monOutbuf,MONITOR_END, -1)) {
344         DosPostEventSem(hevStart);  /* unblock the main thread */
345         return;
346         }
347
348     /* Unblock the main thread and tell it we're OK*/
349     bMonRunning = TRUE;
350     DosPostEventSem(hevStart);
351     while (bMonRunning) {  /* Start an endless loop */
352         /* Read data from keyboard driver */
353         rc = DosMonRead((PBYTE)&monInbuf, IO_WAIT, (PBYTE)&kp, (PUSHORT)&count);
354         if (rc) {
355 #ifdef CHECKED
356             if (bMonRunning)
357                 printf("Error in DosMonRead, rc = %ld\n", rc);
358 #endif
359             bMonRunning = FALSE;
360             return;
361             }
362
363         /* Pass FLUSH packets immediately */
364         if (kp.MonFlagWord & 4) {
365 #ifdef CHECKED
366             printf("Flush packet!\n");
367 #endif
368             DosMonWrite((PBYTE)&monOutbuf, (PBYTE)&kp, count);
369             continue;
370             }
371
372         //TODO: to be removed
373         /* Skip extended scancodes & some others */
374         if (((kp.MonFlagWord >> 8) == 0xE0) || ((kp.KbdDDFlagWord & 0x0F) == 0x0F)) {
375             DosMonWrite((PBYTE)&monOutbuf, (PBYTE)&kp, count);
376             continue;
377             }
378
379 //      printf("RawScan = %X, XlatedScan = %X, fbStatus = %X, KbdDDFlags = %X\n",
380 //          kp.MonFlagWord >> 8, kp.XlatedScan, kp.u.ShiftState, kp.KbdDDFlagWord);
381
382         /* Protect access to buffer with mutex semaphore */
383         rc = DosRequestMutexSem(hmtxKeyBuf, 1000);
384         if (rc) {
385 #ifdef CHECKED
386             printf("Can't get access to mutex, rc = %ld\n", rc);
387 #endif
388             bMonRunning = FALSE;
389             return;
390             }
391
392         /* Store packet in circular buffer, drop it if it's full */
393         kpNew = kpHead + 1;
394         if (kpNew == KEYBUFSIZE)
395             kpNew = 0;
396         if (kpNew != kpTail) {
397             memcpy(&keyMonPkts[kpHead], &kp, sizeof(KEYPACKET));
398             // TODO: fix this!
399             /* Convert break to make code */
400             keyMonPkts[kpHead].MonFlagWord &= 0x7FFF;
401             kpHead = kpNew;
402             }
403         DosReleaseMutexSem(hmtxKeyBuf);
404
405         /* Finally write the packet */
406         rc = DosMonWrite((PBYTE)&monOutbuf, (PBYTE)&kp, count);
407         if (rc) {
408 #ifdef CHECKED
409             if (bMonRunning)
410                 printf("Error in DosMonWrite, rc = %ld\n", rc);
411 #endif
412             bMonRunning = FALSE;
413             return;
414             }
415         }
416     (void)params;
417 }
418
419 /****************************************************************************
420 REMARKS:
421 Safely abort the event module upon catching a fatal error.
422 ****************************************************************************/
423 void _EVT_abort(
424     int signal)
425 {
426     EVT_exit();
427     PM_fatalError("Unhandled exception!");
428 }
429
430 /****************************************************************************
431 PARAMETERS:
432 mouseMove   - Callback function to call wheneve the mouse needs to be moved
433
434 REMARKS:
435 Initiliase the event handling module. Here we install our mouse handling ISR
436 to be called whenever any button's are pressed or released. We also build
437 the free list of events in the event queue.
438
439 We use handler number 2 of the mouse libraries interrupt handlers for our
440 event handling routines.
441 ****************************************************************************/
442 void EVTAPI EVT_init(
443     _EVT_mouseMoveHandler mouseMove)
444 {
445     ushort  stat;
446
447     /* Initialise the event queue */
448     PM_init();
449     EVT.mouseMove = mouseMove;
450     initEventQueue();
451     oldMouseState = 0;
452     oldKeyMessage = 0;
453     memset(keyUpMsg,0,sizeof(keyUpMsg));
454
455     /* Open the mouse driver, and set it up to report events in mickeys */
456     MouOpen(NULL,&_EVT_hMouse);
457     stat = 0x7F;
458     MouSetEventMask(&stat,_EVT_hMouse);
459     stat = (MOU_NODRAW | MOU_MICKEYS) << 8;
460     MouSetDevStatus(&stat,_EVT_hMouse);
461
462     /* Open the keyboard monitor  */
463     if (DosMonOpen((PSZ)"KBD$", &_EVT_hKbdMon))
464         PM_fatalError("Unable to open keyboard monitor!");
465
466     /* Create event semaphore, the monitor will post it when it's initalized */
467     if (DosCreateEventSem(NULL, &hevStart, 0, FALSE))
468         PM_fatalError("Unable to create event semaphore!");
469
470     /* Create mutex semaphore protecting the keypacket buffer */
471     if (DosCreateMutexSem(NULL, &hmtxKeyBuf, 0, FALSE))
472         PM_fatalError("Unable to create mutex semaphore!");
473
474     /* Start keyboard monitor thread, use 32K stack */
475     kbdMonTID = _beginthread(_kbdMonThread, NULL, 0x8000, NULL);
476
477     /* Now block until the monitor thread is up and running */
478     /* Give the thread one second */
479     DosWaitEventSem(hevStart, 1000);
480     if (!bMonRunning) {  /* Check the thread is OK */
481         DosMonClose(_EVT_hKbdMon);
482         PM_fatalError("Keyboard monitor thread didn't initialize!");
483         }
484
485     /* Catch program termination signals so we can clean up properly */
486     signal(SIGABRT, _EVT_abort);
487     signal(SIGFPE, _EVT_abort);
488     signal(SIGINT, _EVT_abort);
489 }
490
491 /****************************************************************************
492 REMARKS
493 Changes the range of coordinates returned by the mouse functions to the
494 specified range of values. This is used when changing between graphics
495 modes set the range of mouse coordinates for the new display mode.
496 ****************************************************************************/
497 void EVTAPI EVT_setMouseRange(
498     int xRes,
499     int yRes)
500 {
501     rangeX = xRes;
502     rangeY = yRes;
503 }
504
505 /****************************************************************************
506 REMARKS
507 Modifes the mouse coordinates as necessary if scaling to OS coordinates,
508 and sets the OS mouse cursor position.
509 ****************************************************************************/
510 #define _EVT_setMousePos(x,y)
511
512 /****************************************************************************
513 REMARKS:
514 Initiailises the internal event handling modules. The EVT_suspend function
515 can be called to suspend event handling (such as when shelling out to DOS),
516 and this function can be used to resume it again later.
517 ****************************************************************************/
518 void EVT_resume(void)
519 {
520     // Do nothing for OS/2
521 }
522
523 /****************************************************************************
524 REMARKS
525 Suspends all of our event handling operations. This is also used to
526 de-install the event handling code.
527 ****************************************************************************/
528 void EVT_suspend(void)
529 {
530     // Do nothing for OS/2
531 }
532
533 /****************************************************************************
534 REMARKS
535 Exits the event module for program terminatation.
536 ****************************************************************************/
537 void EVT_exit(void)
538 {
539     APIRET   rc;
540
541     /* Restore signal handlers */
542     signal(SIGABRT, SIG_DFL);
543     signal(SIGFPE, SIG_DFL);
544     signal(SIGINT, SIG_DFL);
545
546     /* Close the mouse driver */
547     MouClose(_EVT_hMouse);
548
549     /* Stop the keyboard monitor thread and close the monitor */
550     bMonRunning = FALSE;
551     rc = DosKillThread(kbdMonTID);
552 #ifdef CHECKED
553     if (rc)
554         printf("DosKillThread failed, rc = %ld\n", rc);
555 #endif
556     rc = DosMonClose(_EVT_hKbdMon);
557 #ifdef CHECKED
558     if (rc) {
559         printf("DosMonClose failed, rc = %ld\n", rc);
560         }
561 #endif
562     DosCloseEventSem(hevStart);
563     DosCloseMutexSem(hmtxKeyBuf);
564     KbdFlushBuffer(0);
565 }
566