566 lines
19 KiB
C
566 lines
19 KiB
C
/****************************************************************************
|
|
*
|
|
* SciTech OS Portability Manager Library
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* The contents of this file are subject to the SciTech MGL Public
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.scitechsoft.com/mgl-license.txt
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
|
|
*
|
|
* The Initial Developer of the Original Code is SciTech Software, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Language: ANSI C
|
|
* Environment: IBM PC (OS/2)
|
|
*
|
|
* Description: OS/2 implementation for the SciTech cross platform
|
|
* event library.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/*---------------------------- Global Variables ---------------------------*/
|
|
|
|
/* Define generous keyboard monitor circular buffer size to minimize
|
|
* the danger of losing keystrokes
|
|
*/
|
|
#define KEYBUFSIZE (EVENTQSIZE + 10)
|
|
|
|
static int oldMouseState; /* Old mouse state */
|
|
static ulong oldKeyMessage; /* Old keyboard state */
|
|
static ushort keyUpMsg[256] = {0}; /* Table of key up messages */
|
|
static int rangeX,rangeY; /* Range of mouse coordinates */
|
|
HMOU _EVT_hMouse; /* Handle to the mouse driver */
|
|
HMONITOR _EVT_hKbdMon; /* Handle to the keyboard driver */
|
|
TID kbdMonTID = 0; /* Keyboard monitor thread ID */
|
|
HEV hevStart; /* Start event semaphore handle */
|
|
BOOL bMonRunning; /* Flag set if monitor thread OK */
|
|
HMTX hmtxKeyBuf; /* Mutex protecting key buffer */
|
|
KEYPACKET keyMonPkts[KEYBUFSIZE]; /* Array of monitor key packets */
|
|
int kpHead = 0; /* Key packet buffer head */
|
|
int kpTail = 0; /* Key packet buffer tail */
|
|
|
|
/*---------------------------- Implementation -----------------------------*/
|
|
|
|
/* These are not used under OS/2 */
|
|
#define _EVT_disableInt() 1
|
|
#define _EVT_restoreInt(flags)
|
|
|
|
/****************************************************************************
|
|
PARAMETERS:
|
|
scanCode - Scan code to test
|
|
|
|
REMARKS:
|
|
This macro determines if a specified key is currently down at the
|
|
time that the call is made.
|
|
****************************************************************************/
|
|
#define _EVT_isKeyDown(scanCode) (keyUpMsg[scanCode] != 0)
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
This function is used to return the number of ticks since system
|
|
startup in milliseconds. This should be the same value that is placed into
|
|
the time stamp fields of events, and is used to implement auto mouse down
|
|
events.
|
|
****************************************************************************/
|
|
ulong _EVT_getTicks(void)
|
|
{
|
|
ULONG count;
|
|
DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &count, sizeof(ULONG) );
|
|
return count;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Converts a mickey movement value to a pixel adjustment value.
|
|
****************************************************************************/
|
|
static int MickeyToPixel(
|
|
int mickey)
|
|
{
|
|
/* TODO: We can add some code in here to handle 'acceleration' for */
|
|
/* the mouse cursor. For now just use the mickeys. */
|
|
return mickey;
|
|
}
|
|
|
|
/* Some useful defines any typedefs used in the keyboard handling */
|
|
#define KEY_RELEASE 0x40
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Pumps all messages in the message queue from OS/2 into our event queue.
|
|
****************************************************************************/
|
|
static void _EVT_pumpMessages(void)
|
|
{
|
|
KBDINFO keyInfo; /* Must not cross a 64K boundary */
|
|
KBDKEYINFO key; /* Must not cross a 64K boundary */
|
|
MOUQUEINFO mqueue; /* Must not cross a 64K boundary */
|
|
MOUEVENTINFO mouse; /* Must not cross a 64K boundary */
|
|
ushort mWait; /* Must not cross a 64K boundary */
|
|
KEYPACKET kp; /* Must not cross a 64K boundary */
|
|
event_t evt;
|
|
int scan;
|
|
ibool noInput = TRUE; /* Flag to determine if any input was available */
|
|
|
|
/* First of all, check if we should do any session switch work */
|
|
__PM_checkConsoleSwitch();
|
|
|
|
/* Pump all keyboard messages from our circular buffer */
|
|
for (;;) {
|
|
/* Check that the monitor thread is still running */
|
|
if (!bMonRunning)
|
|
PM_fatalError("Keyboard monitor thread died!");
|
|
|
|
/* Protect keypacket buffer with mutex */
|
|
DosRequestMutexSem(hmtxKeyBuf, SEM_INDEFINITE_WAIT);
|
|
if (kpHead == kpTail) {
|
|
DosReleaseMutexSem(hmtxKeyBuf);
|
|
break;
|
|
}
|
|
|
|
noInput = FALSE;
|
|
|
|
/* Read packet from circular buffer and remove it */
|
|
memcpy(&kp, &keyMonPkts[kpTail], sizeof(KEYPACKET));
|
|
if (++kpTail == KEYBUFSIZE)
|
|
kpTail = 0;
|
|
DosReleaseMutexSem(hmtxKeyBuf);
|
|
|
|
/* Compensate for the 0xE0 character */
|
|
if (kp.XlatedScan && kp.XlatedChar == 0xE0)
|
|
kp.XlatedChar = 0;
|
|
|
|
/* Determine type of keyboard event */
|
|
memset(&evt,0,sizeof(evt));
|
|
if (kp.KbdDDFlagWord & KEY_RELEASE)
|
|
evt.what = EVT_KEYUP;
|
|
else
|
|
evt.what = EVT_KEYDOWN;
|
|
|
|
/* Convert keyboard codes */
|
|
scan = kp.MonFlagWord >> 8;
|
|
if (evt.what == EVT_KEYUP) {
|
|
/* Get message for keyup code from table of cached down values */
|
|
evt.message = keyUpMsg[scan];
|
|
keyUpMsg[scan] = 0;
|
|
oldKeyMessage = -1;
|
|
}
|
|
else {
|
|
evt.message = ((ulong)scan << 8) | kp.XlatedChar;
|
|
if (evt.message == keyUpMsg[scan]) {
|
|
evt.what = EVT_KEYREPEAT;
|
|
evt.message |= 0x10000;
|
|
}
|
|
oldKeyMessage = evt.message & 0x0FFFF;
|
|
keyUpMsg[scan] = (ushort)evt.message;
|
|
}
|
|
|
|
/* Convert shift state modifiers */
|
|
if (kp.u.ShiftState & 0x0001)
|
|
evt.modifiers |= EVT_RIGHTSHIFT;
|
|
if (kp.u.ShiftState & 0x0002)
|
|
evt.modifiers |= EVT_LEFTSHIFT;
|
|
if (kp.u.ShiftState & 0x0100)
|
|
evt.modifiers |= EVT_LEFTCTRL;
|
|
if (kp.u.ShiftState & 0x0200)
|
|
evt.modifiers |= EVT_LEFTALT;
|
|
if (kp.u.ShiftState & 0x0400)
|
|
evt.modifiers |= EVT_RIGHTCTRL;
|
|
if (kp.u.ShiftState & 0x0800)
|
|
evt.modifiers |= EVT_RIGHTALT;
|
|
EVT.oldMove = -1;
|
|
|
|
/* Add time stamp and add the event to the queue */
|
|
evt.when = key.time;
|
|
if (EVT.count < EVENTQSIZE)
|
|
addEvent(&evt);
|
|
}
|
|
|
|
/* Don't just flush because that terminally confuses the monitor */
|
|
do {
|
|
KbdCharIn(&key, IO_NOWAIT, 0);
|
|
} while (key.fbStatus & KBDTRF_FINAL_CHAR_IN);
|
|
|
|
/* Pump all mouse messages */
|
|
KbdGetStatus(&keyInfo,0);
|
|
/* Check return code - mouse may not be operational!! */
|
|
if (MouGetNumQueEl(&mqueue,_EVT_hMouse) == NO_ERROR) {
|
|
while (mqueue.cEvents) {
|
|
while (mqueue.cEvents--) {
|
|
memset(&evt,0,sizeof(evt));
|
|
mWait = MOU_NOWAIT;
|
|
MouReadEventQue(&mouse,&mWait,_EVT_hMouse);
|
|
|
|
/* Update the mouse position. We get the mouse coordinates
|
|
* in mickeys so we have to translate these into pixels and
|
|
* move our mouse position. If we don't do this, OS/2 gives
|
|
* us the coordinates in character positions since it still
|
|
* thinks we are in text mode!
|
|
*/
|
|
EVT.mx += MickeyToPixel(mouse.col);
|
|
EVT.my += MickeyToPixel(mouse.row);
|
|
if (EVT.mx < 0) EVT.mx = 0;
|
|
if (EVT.my < 0) EVT.my = 0;
|
|
if (EVT.mx > rangeX) EVT.mx = rangeX;
|
|
if (EVT.my > rangeY) EVT.my = rangeY;
|
|
evt.where_x = EVT.mx;
|
|
evt.where_y = EVT.my;
|
|
evt.relative_x = mouse.col;
|
|
evt.relative_y = mouse.row;
|
|
evt.when = key.time;
|
|
if (mouse.fs & (MOUSE_BN1_DOWN | MOUSE_MOTION_WITH_BN1_DOWN))
|
|
evt.modifiers |= EVT_LEFTBUT;
|
|
if (mouse.fs & (MOUSE_BN2_DOWN | MOUSE_MOTION_WITH_BN2_DOWN))
|
|
evt.modifiers |= EVT_RIGHTBUT;
|
|
if (mouse.fs & (MOUSE_BN3_DOWN | MOUSE_MOTION_WITH_BN3_DOWN))
|
|
evt.modifiers |= EVT_MIDDLEBUT;
|
|
if (keyInfo.fsState & 0x0001)
|
|
evt.modifiers |= EVT_RIGHTSHIFT;
|
|
if (keyInfo.fsState & 0x0002)
|
|
evt.modifiers |= EVT_LEFTSHIFT;
|
|
if (keyInfo.fsState & 0x0100)
|
|
evt.modifiers |= EVT_LEFTCTRL;
|
|
if (keyInfo.fsState & 0x0200)
|
|
evt.modifiers |= EVT_LEFTALT;
|
|
if (keyInfo.fsState & 0x0400)
|
|
evt.modifiers |= EVT_RIGHTCTRL;
|
|
if (keyInfo.fsState & 0x0800)
|
|
evt.modifiers |= EVT_RIGHTALT;
|
|
|
|
/* Check for left mouse click events */
|
|
/* 0x06 == (MOUSE_BN1_DOWN | MOUSE_MOTION_WITH_BN1_DOWN) */
|
|
if (((mouse.fs & 0x0006) && !(oldMouseState & 0x0006))
|
|
|| (!(mouse.fs & 0x0006) && (oldMouseState & 0x0006))) {
|
|
if (mouse.fs & 0x0006)
|
|
evt.what = EVT_MOUSEDOWN;
|
|
else
|
|
evt.what = EVT_MOUSEUP;
|
|
evt.message = EVT_LEFTBMASK;
|
|
EVT.oldMove = -1;
|
|
if (EVT.count < EVENTQSIZE)
|
|
addEvent(&evt);
|
|
}
|
|
|
|
/* Check for right mouse click events */
|
|
/* 0x0018 == (MOUSE_BN2_DOWN | MOUSE_MOTION_WITH_BN2_DOWN) */
|
|
if (((mouse.fs & 0x0018) && !(oldMouseState & 0x0018))
|
|
|| (!(mouse.fs & 0x0018) && (oldMouseState & 0x0018))) {
|
|
if (mouse.fs & 0x0018)
|
|
evt.what = EVT_MOUSEDOWN;
|
|
else
|
|
evt.what = EVT_MOUSEUP;
|
|
evt.message = EVT_RIGHTBMASK;
|
|
EVT.oldMove = -1;
|
|
if (EVT.count < EVENTQSIZE)
|
|
addEvent(&evt);
|
|
}
|
|
|
|
/* Check for middle mouse click events */
|
|
/* 0x0060 == (MOUSE_BN3_DOWN | MOUSE_MOTION_WITH_BN3_DOWN) */
|
|
if (((mouse.fs & 0x0060) && !(oldMouseState & 0x0060))
|
|
|| (!(mouse.fs & 0x0060) && (oldMouseState & 0x0060))) {
|
|
if (mouse.fs & 0x0060)
|
|
evt.what = EVT_MOUSEDOWN;
|
|
else
|
|
evt.what = EVT_MOUSEUP;
|
|
evt.message = EVT_MIDDLEBMASK;
|
|
EVT.oldMove = -1;
|
|
if (EVT.count < EVENTQSIZE)
|
|
addEvent(&evt);
|
|
}
|
|
|
|
/* Check for mouse movement event */
|
|
if (mouse.fs & 0x002B) {
|
|
evt.what = EVT_MOUSEMOVE;
|
|
if (EVT.oldMove != -1) {
|
|
EVT.evtq[EVT.oldMove].where_x = evt.where_x;/* Modify existing one */
|
|
EVT.evtq[EVT.oldMove].where_y = evt.where_y;
|
|
}
|
|
else {
|
|
EVT.oldMove = EVT.freeHead; /* Save id of this move event */
|
|
if (EVT.count < EVENTQSIZE)
|
|
addEvent(&evt);
|
|
}
|
|
}
|
|
|
|
/* Save current mouse state */
|
|
oldMouseState = mouse.fs;
|
|
}
|
|
MouGetNumQueEl(&mqueue,_EVT_hMouse);
|
|
}
|
|
noInput = FALSE;
|
|
}
|
|
|
|
/* If there was no input available, give up the current timeslice
|
|
* Note: DosSleep(0) will effectively do nothing if no other thread is ready. Hence
|
|
* DosSleep(0) will still use 100% CPU _but_ should not interfere with other programs.
|
|
*/
|
|
if (noInput)
|
|
DosSleep(0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
This macro/function is used to converts the scan codes reported by the
|
|
keyboard to our event libraries normalised format. We only have one scan
|
|
code for the 'A' key, and use shift modifiers to determine if it is a
|
|
Ctrl-F1, Alt-F1 etc. The raw scan codes from the keyboard work this way,
|
|
but the OS gives us 'cooked' scan codes, we have to translate them back
|
|
to the raw format.
|
|
****************************************************************************/
|
|
#define _EVT_maskKeyCode(evt)
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Keyboard monitor thread. Needed to catch both keyup and keydown events.
|
|
****************************************************************************/
|
|
static void _kbdMonThread(
|
|
void *params)
|
|
{
|
|
APIRET rc;
|
|
KEYPACKET kp;
|
|
USHORT count = sizeof(KEYPACKET);
|
|
MONBUF monInbuf;
|
|
MONBUF monOutbuf;
|
|
int kpNew;
|
|
|
|
/* Raise thread priority for higher responsiveness */
|
|
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
|
|
monInbuf.cb = sizeof(monInbuf) - sizeof(monInbuf.cb);
|
|
monOutbuf.cb = sizeof(monOutbuf) - sizeof(monOutbuf.cb);
|
|
bMonRunning = FALSE;
|
|
|
|
/* Register the buffers to be used for monitoring for current session */
|
|
if (DosMonReg(_EVT_hKbdMon, &monInbuf, (ULONG*)&monOutbuf,MONITOR_END, -1)) {
|
|
DosPostEventSem(hevStart); /* unblock the main thread */
|
|
return;
|
|
}
|
|
|
|
/* Unblock the main thread and tell it we're OK*/
|
|
bMonRunning = TRUE;
|
|
DosPostEventSem(hevStart);
|
|
while (bMonRunning) { /* Start an endless loop */
|
|
/* Read data from keyboard driver */
|
|
rc = DosMonRead((PBYTE)&monInbuf, IO_WAIT, (PBYTE)&kp, (PUSHORT)&count);
|
|
if (rc) {
|
|
#ifdef CHECKED
|
|
if (bMonRunning)
|
|
printf("Error in DosMonRead, rc = %ld\n", rc);
|
|
#endif
|
|
bMonRunning = FALSE;
|
|
return;
|
|
}
|
|
|
|
/* Pass FLUSH packets immediately */
|
|
if (kp.MonFlagWord & 4) {
|
|
#ifdef CHECKED
|
|
printf("Flush packet!\n");
|
|
#endif
|
|
DosMonWrite((PBYTE)&monOutbuf, (PBYTE)&kp, count);
|
|
continue;
|
|
}
|
|
|
|
/*TODO: to be removed */
|
|
/* Skip extended scancodes & some others */
|
|
if (((kp.MonFlagWord >> 8) == 0xE0) || ((kp.KbdDDFlagWord & 0x0F) == 0x0F)) {
|
|
DosMonWrite((PBYTE)&monOutbuf, (PBYTE)&kp, count);
|
|
continue;
|
|
}
|
|
|
|
/* printf("RawScan = %X, XlatedScan = %X, fbStatus = %X, KbdDDFlags = %X\n", */
|
|
/* kp.MonFlagWord >> 8, kp.XlatedScan, kp.u.ShiftState, kp.KbdDDFlagWord); */
|
|
|
|
/* Protect access to buffer with mutex semaphore */
|
|
rc = DosRequestMutexSem(hmtxKeyBuf, 1000);
|
|
if (rc) {
|
|
#ifdef CHECKED
|
|
printf("Can't get access to mutex, rc = %ld\n", rc);
|
|
#endif
|
|
bMonRunning = FALSE;
|
|
return;
|
|
}
|
|
|
|
/* Store packet in circular buffer, drop it if it's full */
|
|
kpNew = kpHead + 1;
|
|
if (kpNew == KEYBUFSIZE)
|
|
kpNew = 0;
|
|
if (kpNew != kpTail) {
|
|
memcpy(&keyMonPkts[kpHead], &kp, sizeof(KEYPACKET));
|
|
/* TODO: fix this! */
|
|
/* Convert break to make code */
|
|
keyMonPkts[kpHead].MonFlagWord &= 0x7FFF;
|
|
kpHead = kpNew;
|
|
}
|
|
DosReleaseMutexSem(hmtxKeyBuf);
|
|
|
|
/* Finally write the packet */
|
|
rc = DosMonWrite((PBYTE)&monOutbuf, (PBYTE)&kp, count);
|
|
if (rc) {
|
|
#ifdef CHECKED
|
|
if (bMonRunning)
|
|
printf("Error in DosMonWrite, rc = %ld\n", rc);
|
|
#endif
|
|
bMonRunning = FALSE;
|
|
return;
|
|
}
|
|
}
|
|
(void)params;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Safely abort the event module upon catching a fatal error.
|
|
****************************************************************************/
|
|
void _EVT_abort(
|
|
int signal)
|
|
{
|
|
EVT_exit();
|
|
PM_fatalError("Unhandled exception!");
|
|
}
|
|
|
|
/****************************************************************************
|
|
PARAMETERS:
|
|
mouseMove - Callback function to call wheneve the mouse needs to be moved
|
|
|
|
REMARKS:
|
|
Initiliase the event handling module. Here we install our mouse handling ISR
|
|
to be called whenever any button's are pressed or released. We also build
|
|
the free list of events in the event queue.
|
|
|
|
We use handler number 2 of the mouse libraries interrupt handlers for our
|
|
event handling routines.
|
|
****************************************************************************/
|
|
void EVTAPI EVT_init(
|
|
_EVT_mouseMoveHandler mouseMove)
|
|
{
|
|
ushort stat;
|
|
|
|
/* Initialise the event queue */
|
|
PM_init();
|
|
EVT.mouseMove = mouseMove;
|
|
initEventQueue();
|
|
oldMouseState = 0;
|
|
oldKeyMessage = 0;
|
|
memset(keyUpMsg,0,sizeof(keyUpMsg));
|
|
|
|
/* Open the mouse driver, and set it up to report events in mickeys */
|
|
MouOpen(NULL,&_EVT_hMouse);
|
|
stat = 0x7F;
|
|
MouSetEventMask(&stat,_EVT_hMouse);
|
|
stat = (MOU_NODRAW | MOU_MICKEYS) << 8;
|
|
MouSetDevStatus(&stat,_EVT_hMouse);
|
|
|
|
/* Open the keyboard monitor */
|
|
if (DosMonOpen((PSZ)"KBD$", &_EVT_hKbdMon))
|
|
PM_fatalError("Unable to open keyboard monitor!");
|
|
|
|
/* Create event semaphore, the monitor will post it when it's initalized */
|
|
if (DosCreateEventSem(NULL, &hevStart, 0, FALSE))
|
|
PM_fatalError("Unable to create event semaphore!");
|
|
|
|
/* Create mutex semaphore protecting the keypacket buffer */
|
|
if (DosCreateMutexSem(NULL, &hmtxKeyBuf, 0, FALSE))
|
|
PM_fatalError("Unable to create mutex semaphore!");
|
|
|
|
/* Start keyboard monitor thread, use 32K stack */
|
|
kbdMonTID = _beginthread(_kbdMonThread, NULL, 0x8000, NULL);
|
|
|
|
/* Now block until the monitor thread is up and running */
|
|
/* Give the thread one second */
|
|
DosWaitEventSem(hevStart, 1000);
|
|
if (!bMonRunning) { /* Check the thread is OK */
|
|
DosMonClose(_EVT_hKbdMon);
|
|
PM_fatalError("Keyboard monitor thread didn't initialize!");
|
|
}
|
|
|
|
/* Catch program termination signals so we can clean up properly */
|
|
signal(SIGABRT, _EVT_abort);
|
|
signal(SIGFPE, _EVT_abort);
|
|
signal(SIGINT, _EVT_abort);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS
|
|
Changes the range of coordinates returned by the mouse functions to the
|
|
specified range of values. This is used when changing between graphics
|
|
modes set the range of mouse coordinates for the new display mode.
|
|
****************************************************************************/
|
|
void EVTAPI EVT_setMouseRange(
|
|
int xRes,
|
|
int yRes)
|
|
{
|
|
rangeX = xRes;
|
|
rangeY = yRes;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS
|
|
Modifes the mouse coordinates as necessary if scaling to OS coordinates,
|
|
and sets the OS mouse cursor position.
|
|
****************************************************************************/
|
|
#define _EVT_setMousePos(x,y)
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Initiailises the internal event handling modules. The EVT_suspend function
|
|
can be called to suspend event handling (such as when shelling out to DOS),
|
|
and this function can be used to resume it again later.
|
|
****************************************************************************/
|
|
void EVT_resume(void)
|
|
{
|
|
/* Do nothing for OS/2 */
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS
|
|
Suspends all of our event handling operations. This is also used to
|
|
de-install the event handling code.
|
|
****************************************************************************/
|
|
void EVT_suspend(void)
|
|
{
|
|
/* Do nothing for OS/2 */
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS
|
|
Exits the event module for program terminatation.
|
|
****************************************************************************/
|
|
void EVT_exit(void)
|
|
{
|
|
APIRET rc;
|
|
|
|
/* Restore signal handlers */
|
|
signal(SIGABRT, SIG_DFL);
|
|
signal(SIGFPE, SIG_DFL);
|
|
signal(SIGINT, SIG_DFL);
|
|
|
|
/* Close the mouse driver */
|
|
MouClose(_EVT_hMouse);
|
|
|
|
/* Stop the keyboard monitor thread and close the monitor */
|
|
bMonRunning = FALSE;
|
|
rc = DosKillThread(kbdMonTID);
|
|
#ifdef CHECKED
|
|
if (rc)
|
|
printf("DosKillThread failed, rc = %ld\n", rc);
|
|
#endif
|
|
rc = DosMonClose(_EVT_hKbdMon);
|
|
#ifdef CHECKED
|
|
if (rc) {
|
|
printf("DosMonClose failed, rc = %ld\n", rc);
|
|
}
|
|
#endif
|
|
DosCloseEventSem(hevStart);
|
|
DosCloseMutexSem(hmtxKeyBuf);
|
|
KbdFlushBuffer(0);
|
|
}
|