home *** CD-ROM | disk | FTP | other *** search
- /*
- os2hard.c
-
- % OS/2 keyboard, mouse, timer, and speaker routines
-
- 11/13/88 by Ted.
-
- OWL 1.2
- Copyright (c) 1988, by Oakland Group, Inc.
- ALL RIGHTS RESERVED.
-
- Revision History:
- -----------------
- 12/01/88 ted extracted event stuff.
- 2/07/89 Ted added timeout wait arg to hCheckEvent function.
- 4/03/89 ted Changed == 0 to != 0 for Kbd_Peek result in CheckEvent.
- 4/09/89 ted converted for static digdata.
- 4/22/89 ted merged in event stuff again, added digpriv's.
- 7/10/89 ted put os2hdatastruc in here (we used to share w/ pchdatastruc.
- 8/31/89 ted Added CLEAREVENTS.
- 9/10/89 gam Added check for extended keys.
- 9/11/89 gam Added some casts for Version 1.1
- 3/09/90 ted Added no-stack-check pragma because checking kills threads.
- 3/09/90 ted Changed mouse cursor show/hide approach.
- 3/10/90 ted Changed GetShift scheme to avoid Peek/CharIn conflict.
- 4/05/90 jmd ansi-fied
- 5/08/90 jmd preened
- 5/11/90 jmd converted to new scancode scheme
- 9/01/90 ted Added numlock test & keypad cases in os2_eventwait().
- 9/09/90 ted converted to new-old scancode scheme; removed os2_CvtScancode.
- 10/04/90 ted added casts to eliminate MC6.0 signed/unsigned warnings.
- 12/12/90 pmcm converted hsecs to millisecs in os2h_Sound
- */
-
- #include "os2priv.h"
-
- #ifdef OAK_OS2 /* Only compile this for OS2 */
-
- #include "scancode.h" /* for mouse pseudo-scancodes */
-
- os2hdata_struct os2hdatastruc;
-
- OSTATIC dig_hCheckEvent_func (os2_hCheckEvent);
- OSTATIC dig_hReadEvent_func (os2_hReadEvent);
- OSTATIC dig_hControl_func (os2_hControl);
- OSTATIC dig_hGetShift_func (os2_hGetShift);
- OSTATIC dig_hTimer_func (os2_hTimer);
- OSTATIC dig_hPause_func (os2_hPause);
- OSTATIC dig_hSound_func (os2_hSound);
-
- OSTATIC int DIGPRIV os2_eventwait(unsigned wait);
- OSTATIC boolean DIGPRIV initkeythread(void);
- OSTATIC int DIGPRIV mousecheck(void);
- OSTATIC void FAR keythread(void);
- OSTATIC void FAR mousethread(void);
- OSTATIC void DIGPRIV getmouevent(void);
- OSTATIC void DIGPRIV mouse_drawremov(void);
-
- #define newpos(_mouev) ((opcoord) _mouev.col != kminfo->oldpos.x || \
- (opcoord) _mouev.row != kminfo->oldpos.y || \
- (unsigned) _mouev.fs != kminfo->oldpos.event)
- #define newpos2(_moupos) (_moupos.x != kminfo->oldpos.x || \
- _moupos.y != kminfo->oldpos.y || \
- _moupos.event != kminfo->oldpos.event)
-
- static boolean kmexit = TRUE; /* thread termination flag */
- static RAMSEM psem; /* re-entrancy protection semaphore */
- static RAMSEM gosem; /* key/mouse thread start up semaphore */
- static RAMSEM keysem; /* keystroke ready semaphore */
-
- static RAMSEM mousem; /* mouse event ready semaphore */
-
- static os2minfo_type kminfo = NULL; /* mouse info ptr */
- /* -------------------------------------------------------------------------- */
-
- void DIGPRIV os2_hOpen(dig_struct *digp)
- /* init keyboard pointers */
- {
- digp->hCheckEvent = os2_hCheckEvent;
- digp->hReadEvent = os2_hReadEvent;
- digp->hControl = os2_hControl;
- digp->hGetShift = os2_hGetShift;
- digp->hTimer = os2_hTimer;
- digp->hPause = os2_hPause;
- digp->hSound = os2_hSound;
- }
- /* -------------------------------------------------------------------------- */
-
- static int os2_hCheckEvent(unsigned wait)
- /*
- Return scancode if pending key event, HARD_MEV if no key but mouse event pending,
- or KEY_NONE if no event is available before the wait time expires.
- */
- {
- /* If event already checked positive, repeat the message */
- if (os2data->evstash == KEY_NONE) {
- return(os2data->evstash = os2_eventwait(wait));
- }
- else {
- return(os2data->evstash);
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static int os2_hReadEvent(moupos_struct *mouposp)
- /*
- Returns key scancode if key event is available first, or HARD_MEV if
- mouse event is available first. Returns key event if both key and mouse
- event are available when it is called.
- */
- {
- int tevent;
-
- /* If CheckEvent already stashed an event, use that one. */
- /* (If the checked event was from the mouse, try for a fresher one) */
- if (os2data->evstash != KEY_NONE && os2data->evstash != HARD_MEV) {
- tevent = os2data->evstash;
- }
- /* Otherwise, get a new event */
- /* Note: if evstash is HARD_MEV eventwait will return right away */
- else {
- if ((tevent = os2_eventwait(-1)) == HARD_MEV) {
- memmove(mouposp, &kminfo->moupos, sizeof(moupos_struct));
- }
- }
- os2data->evstash = KEY_NONE;
- return(tevent);
- }
- /* -------------------------------------------------------------------------- */
-
- static int os2_hControl(dig_hcmsg msg, VOID *indata, VOID *outdata)
- {
- PIDINFO pidi;
- /* indata not used here for now. */ oak_notused(indata);
- /* outdata not used here for now. */ oak_notused(outdata);
-
- switch (msg) {
- case HC_OPEN:
- os2data->dosbox = FALSE;
-
- os2hdata->ismouse = FALSE;
- os2hdata->soundon = TRUE;
-
- psem = 0L;
- os2data->pnest = 0;
-
- return(initkeythread());
-
- case HC_CLOSE:
- kmexit = TRUE; /* kill the threads */
- DosSemClear(&gosem);
-
- if (kminfo != NULL) {
- ofree(OA_OS2KMDATA, (VOID *)kminfo);
- kminfo = NULL;
- }
- break;
- case HC_INITMOUSE:
- os2hdata->ismouse = mousecheck(); /* remember if mouse found */
- /* no break; */
- case HC_ISMOUSEON:
- return((int)os2hdata->ismouse);
- case HC_DEINITMOUSE:
- os2hdata->ismouse = FALSE;
- break;
- case HC_SETMOUSEBOX:
- break;
- case HC_SETSOUNDON:
- os2hdata->soundon = TRUE;
- break;
- case HC_SETSOUNDOFF:
- os2hdata->soundon = FALSE;
- break;
- case HC_GETSOUNDON:
- return((int)os2hdata->soundon);
-
- case HC_CLEAREVENTS:
- { /* Call ReadEvent until nothing in kb buffer */
- moupos_struct mouposdum;
-
- while (os2_hCheckEvent(0) != KEY_NONE) {
- os2_hReadEvent(&mouposdum);
- }
- break;
- }
- case HC_PROTECT:
- DosGetPID(&pidi);
- if (os2data->pnest == 0 || pidi.tid != os2data->ptid) {
- DosSemRequest(&psem, -1L);
- DosGetPID(&pidi);
- os2data->ptid = pidi.tid;
- }
- os2data->pnest++;
- break;
- case HC_UNPROTECT:
- os2data->pnest--;
- if (os2data->pnest == 0) {
- DosSemClear(&psem);
- }
- break;
- }
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- static unsigned os2_hGetShift()
- /*
- effects: gets the state of the keyboard shift keys.
- returns: an encoding of the shift keys as follows:
- LSB bit 0 - right shift
- bit 1 - left shift
- bit 2 - control
- bit 3 - alt
- bit 4 - scroll lock
- bit 5 - num lock
- bit 6 - caps lock
- bit 7 - insert
- MSB bits 8-15 - not used
- */
- {
- return(os2data->shift);
- }
- /* -------------------------------------------------------------------------- */
-
- static unsigned os2_hTimer()
- /*
- effects: Calculates current time stamp with 1/100 sec. resolution.
- Events with duration up to TIMER_LIMIT / 100 seconds
- can be timed.
- returns: An integer between 0 and TIMER_LIMIT - 1, which represents
- a time stamp. This time stamp can be compared to previous
- time stamps to calculate elapsed time in hundredths of
- seconds. The timer 'rolls over' at TIMER_LIMIT - 1.
- */
- {
- DATETIME time;
- unsigned hsecs, secs, mins;
-
- DosGetDateTime(&time);
-
- hsecs = time.hundredths;
- secs = time.seconds * 100;
- mins = time.minutes % 10;
-
- return((unsigned)(hsecs + secs * 100 + mins * 6000));
- }
- /* -------------------------------------------------------------------------- */
-
- static void os2_hPause(unsigned duration)
- /*
- Pause for a duration given in hundredths of secs.
- */
- {
- unsigned long sleep;
-
- sleep = duration;
- sleep *= 10; /* convert from hsecs to milliseconds */
- DosSleep(sleep);
- }
- /* -------------------------------------------------------------------------- */
-
- static void os2_hSound(unsigned int pitch, unsigned int duration)
- /*
- Make a tone of given pitch for a duration given in hundredths of secs.
- */
- {
- if (os2hdata->soundon) {
- /* convert from hsecs to milliseconds */
- DosBeep(pitch, duration * 10);
- }
- }
- /* -------------------------------------------------------------------------- */
- /* -------------------------------------------------------------------------- */
-
- static int DIGPRIV os2_eventwait(unsigned wait)
- /*
- Returns event code if a key/mouse event occurs within the wait time.
- Returns KEY_NONE if it times out.
- */
- {
- unsigned which;
- long lwait;
-
- /* Convert wait from short hsecs to long millisecs */
- if (wait != -1) {
- lwait = wait;
- lwait *= 10;
- }
- else {
- lwait = -1;
- }
-
- /* Throw out stale mouse event (if mouse is off, this will never clear) */
- /* (mousem may already be set if no stale mouse event is waiting, but */
- /* it's ok if we set it again anyway) */
- DosSemSet(&mousem);
-
- /* Block until a key or mouse event strikes */
- /* (gosem may already be clear because we're still waiting from a */
- /* previous try, but it's ok if we clear it again anyway) */
- DosSemClear(&gosem);
-
- if (DosMuxSemWait((PUSHORT)&which, &os2data->kmsemlist, lwait) != 0) {
- return(KEY_NONE); /* Timeout or Error */
- }
- if (which == 0) { /* Key was received first */
- DosSemSet(&keysem);
-
- switch(os2data->key) {
-
- /* The "Grey-Enter" key */
- case 0xE00D:
- os2data->key = ENTER;
- break;
-
- /* Strip low-byte E0 from non-ascii scancodes that might have it */
- case ((unsigned) LEFT | 0xE0):
- case ((unsigned) RIGHT| 0xE0):
- case ((unsigned) UP | 0xE0):
- case ((unsigned) DOWN | 0xE0):
- case ((unsigned) HOME | 0xE0):
- case ((unsigned) END | 0xE0):
- case ((unsigned) PGUP | 0xE0):
- case ((unsigned) PGDN | 0xE0):
- case ((unsigned) INS | 0xE0):
- case ((unsigned) DEL | 0xE0):
- case ((unsigned) CTRL_LEFT | 0xE0):
- case ((unsigned) CTRL_RIGHT| 0xE0):
- case ((unsigned) CTRL_UP | 0xE0):
- case ((unsigned) CTRL_DOWN | 0xE0):
- case ((unsigned) CTRL_HOME | 0xE0):
- case ((unsigned) CTRL_END | 0xE0):
- case ((unsigned) CTRL_PGUP | 0xE0):
- case ((unsigned) CTRL_PGDN | 0xE0):
- case ((unsigned) CTRL_INS | 0xE0):
- case ((unsigned) CTRL_DEL | 0xE0):
- os2data->key &= 0xFF00;
- break;
- }
- return((int) os2data->key);
- }
- else { /* Mouse was received first */
- /* mousem is reset above where we throw out the stale mouse event. */
- /* We don't reset it here so hide & show will know mthread isn't blocked.*/
- memmove(&kminfo->oldpos, &kminfo->moupos, sizeof(moupos_struct));
- return(HARD_MEV);
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static boolean DIGPRIV initkeythread()
- {
- TID tid;
- KBDINFO kbstatus;
-
- os2data->hkbd = 0;
- os2data->evstash = KEY_NONE;
-
- /* Set up kmsemlist */
- os2data->kmsemlist.cmxs = 2;
- os2data->kmsemlist.amxs[0].zero = 0;
- os2data->kmsemlist.amxs[0].hsem = &keysem;
- os2data->kmsemlist.amxs[1].zero = 0;
- os2data->kmsemlist.amxs[1].hsem = &mousem;
-
- /* Start key thread */
- gosem = 0;
- keysem = 0;
- DosSemSet(&gosem);
- DosSemSet(&keysem);
- mousem = 0;
- DosSemSet(&mousem); /* Set mousem now; we want to mux-wait on it */
- kmexit = FALSE;
- if (DosCreateThread(keythread, &tid, &os2data->kstack[THREADSTACKSIZE]) == 0) {
- DosSemWait(&keysem, -1L); /* Make sure thread is going before we continue */
- DosSemSet(&keysem); /* Thread is now waiting for gosem */
-
- /* Make KbdCharIn report shift keys so we can keep up w/ shift state */
- kbstatus.cb = sizeof(KBDINFO);
- KbdGetStatus(&kbstatus, os2data->hkbd);
- kbstatus.fsMask &= ~KEYBOARD_ASCII_MODE;
- kbstatus.fsMask |= (KEYBOARD_BINARY_MODE | KEYBOARD_SHIFT_REPORT);
- KbdSetStatus(&kbstatus, os2data->hkbd);
-
- return(TRUE);
- }
- return(FALSE);
- }
- /* -------------------------------------------------------------------------- */
-
- static int DIGPRIV mousecheck()
- /*
- Return 1 for mouse, 0 for not installed.
- */
- {
- TID tid;
- USHORT hval;
-
- if (kminfo != NULL) {
- return(TRUE);
- }
- kminfo = (os2minfo_type) omalloc(OA_OS2KMDATA, sizeof(struct os2minfo_struct));
- if (kminfo == NULL) {
- return(FALSE);
- }
- if (MouOpen(0L, &kminfo->hmou) == 0) {
- kminfo->mousehide = 1;
- kminfo->hid = TRUE;
-
- kminfo->mouserect.row = 0;
- kminfo->mouserect.col = 0;
- kminfo->mouserect.cRow = os2data->info.dispmap->height - 1;
- kminfo->mouserect.cCol = os2data->info.dispmap->width - 1;
-
- hval = 0x0000; /* Enable mouse ptr */
- MouSetDevStatus(&hval, kminfo->hmou);
- hval = 0xFFFF; /* Enable mouse events */
- MouSetEventMask(&hval, kminfo->hmou);
-
- kminfo->oldpos.event = (unsigned)-1;
-
- /* Start mouse thread */
- if (DosCreateThread(mousethread, &tid, &kminfo->mstack[THREADSTACKSIZE]) == 0) {
- DosSemWait(&mousem, -1L); /* Make sure thread is going before we continue */
- return(TRUE);
- }
- }
- ofree(OA_OS2KMDATA, (VOID *)kminfo);
- kminfo = NULL;
- return(FALSE);
- }
- /* -------------------------------------------------------------------------- */
-
- void DIGPRIV os2_dohide()
- /*
- This function hides the mouse pointer. However, there is a bug in
- MouRemovePtr where it doesn't hide the pointer or return until the next
- mouse event strikes, if MouReadEventQue is blocked waiting for the next
- mouse event. Therefore, this funtion activates hidethread to call
- MouRemovePtr so that we can go about our business while MouRemovePtr
- is erroneously blocked.
- */
- {
- if (kminfo->mousehide != -1) { /* Protect against overflow wraparound */
- if (kminfo->mousehide++ == 0) {
- /* wait == 0 means semaphore is not set; not waiting for event */
- if (DosSemWait(&mousem, 0L) == 0) {
- /* Not waiting for mouse event; it can only be made to start */
- /* waiting by this thread */
- MouRemovePtr(&kminfo->mouserect, kminfo->hmou);
- kminfo->hid = TRUE;
- }
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- void DIGPRIV os2_doshow()
- /*
- See above function (dohide) for comments.
- */
- {
- if (kminfo->mousehide != 0) { /* Protect against underflow wraparound */
- if (--kminfo->mousehide == 0) {
- /* wait == 0 means semaphore is not set; not waiting for event */
- if (DosSemWait(&mousem, 0L) == 0) {
- MouDrawPtr(kminfo->hmou);
- kminfo->hid = FALSE;
- }
- }
- }
- }
- /* -------------------------------------------------------------------------- */
- /* Turn off Microsoft stack checking for threads */
- #pragma check_stack(off)
- /* -------------------------------------------------------------------------- */
-
- static void FAR keythread()
- {
- KBDKEYINFO keyinfo;
-
- for (;;) {
- DosSemSet(&gosem); /* Set this now so ReadEvent can't re-clear it before we've blocked on it (??) */
- DosSemClear(&keysem); /* let ReadEvent know we're ready */
- DosSemWait(&gosem, -1L);
- if (kmexit) {
- break; /* kminfo may no longer be valid */
- }
-
- for (;;) {
- KbdCharIn(&keyinfo, IO_WAIT, os2data->hkbd);
- if (kmexit) {
- break; /* kminfo may no longer be valid */
- }
- os2data->shift = keyinfo.fsState;
- /* Don't return shift keys */
- if (!(keyinfo.fbStatus & SHIFT_KEY_IN)) {
- break;
- }
- }
- os2data->key = MAKEUSHORT(keyinfo.chChar, keyinfo.chScan);
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void FAR mousethread()
- {
- for (;;) {
- DosEnterCritSec(); /* Reset mouse and clear mousem atomically */
- mouse_drawremov();
- DosSemClear(&mousem); /* let ReadEvent know we're ready */
- DosExitCritSec();
-
- DosSemWait(&gosem, -1L);
- if (kmexit) {
- break; /* kminfo may no longer be valid */
- }
-
- getmouevent();
- if (kmexit) {
- break; /* kminfo may no longer be valid */
- }
-
- /* Set this now rather than earlier so that ReadEvent can't re-clear it */
- /* while we're still waiting for the mouse before we've blocked on it. */
- DosSemSet(&gosem);
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV getmouevent()
- {
- MOUEVENTINFO mouev;
- MOUQUEINFO numevents;
- boolean wait = TRUE;
-
- MouGetNumQueEl(&numevents, kminfo->hmou);
- if (numevents.cEvents == 0) {
- if (newpos2(kminfo->moupos)) {
- return; /* Return if recent event is not last one returned */
- }
- if (os2data->evstash == HARD_MEV) {
- return; /* Not fresh event, but return anyway if we promised to */
- }
- }
- for (;;) { /* Slurp all pending events out of the queue */
- MouReadEventQue(&mouev, (PUSHORT)&wait, kminfo->hmou);
- if (kmexit) {
- return; /* kminfo may no longer be valid */
- }
-
- MouGetNumQueEl(&numevents, kminfo->hmou);
- if (numevents.cEvents == 0) {
-
- /* Do it now because ReadEventQue is no longer blocked */
- mouse_drawremov();
-
- if (newpos(mouev)) {
- /* The queue is sucked dry; return the last event */
- kminfo->moupos.x = mouev.col;
- kminfo->moupos.y = mouev.row;
- kminfo->moupos.event = mouev.fs;
- break;
- }
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV mouse_drawremov()
- {
- if (kminfo->hid != (kminfo->mousehide != 0)) {
- if (kminfo->mousehide != 0) {
- MouRemovePtr(&kminfo->mouserect, kminfo->hmou);
- kminfo->hid = TRUE;
- }
- else {
- MouDrawPtr(kminfo->hmou);
- kminfo->hid = FALSE;
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- #else /* ifndef OAK_OS2 */
- /* A dummy so compilers won't freak if everything else is ifdef'ed out. */
- int os2harddummy(void);
- int os2harddummy() { return(0); }
- #endif
-
-