home *** CD-ROM | disk | FTP | other *** search
- /*
- os2hard.c
-
- % OS/2 keyboard, mouse, timer, and speaker routines
-
- 11/13/88 by Ted.
-
- OWL
- 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
- */
-
- #include "os2priv.h"
-
- #ifdef OAK_OS2 /* Only compile this for OS2 */
-
- #include "scancode.h" /* for mouse pseudo-scancodes */
-
- pchdata_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 unsigned DIGPRIV os2_eventwait(_arg1(unsigned wait));
- OSTATIC boolean DIGPRIV initkeythread(_arg1(void));
- OSTATIC void far keythread(_arg1(void));
- OSTATIC int DIGPRIV mousecheck(_arg1(void));
- OSTATIC void far mousethread(_arg1(void));
- OSTATIC void DIGPRIV getmouevent(_arg1(void));
- OSTATIC void far hidethread(_arg1(void));
-
- #define newpos(mouev) (mouev.col != kminfo->oldpos.x || \
- mouev.row != kminfo->oldpos.y || \
- mouev.fs != 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 RAMSEM hsem; /* hide cursor thread control semaphore */
-
- static os2minfo_type kminfo = NULL; /* mouse info ptr */
- /* -------------------------------------------------------------------------- */
-
- void DIGPRIV os2_hOpen(digp)
- 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 unsigned os2_hCheckEvent(wait)
- 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 unsigned os2_hReadEvent(mouposp)
- 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.
- */
- {
- unsigned 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);
- }
- /* -------------------------------------------------------------------------- */
-
- int os2_hControl(msg, indata, outdata)
- 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
- */
- {
- KBDKEYINFO keyinfo;
-
- KbdPeek(&keyinfo, os2data->hkbd);
- return(keyinfo.fsState);
- }
- /* -------------------------------------------------------------------------- */
-
- 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(duration)
- unsigned duration; /* duration in hundredths of secs */
- {
- unsigned long sleep;
-
- sleep = duration;
- sleep *= 10; /* convert from hsecs to milliseconds */
- DosSleep(sleep);
- }
- /* -------------------------------------------------------------------------- */
-
- static void os2_hSound(pitch, duration)
- unsigned int pitch;
- unsigned int duration; /* duration in hundredths of secs */
- {
- if (os2hdata->soundon) {
- DosBeep(pitch, duration);
- }
- }
- /* -------------------------------------------------------------------------- */
- /* -------------------------------------------------------------------------- */
-
- static unsigned DIGPRIV os2_eventwait(wait)
- 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) {
- case (HOME + 0xE0):
- case (END + 0xE0):
- case (LEFT + 0xE0):
- case (RIGHT+ 0xE0):
- case (UP + 0xE0):
- case (DOWN + 0xE0):
- case (PGUP + 0xE0):
- case (PGDN + 0xE0):
- case (INS + 0xE0):
- case (DEL + 0xE0):
- case (CTRL_HOME + 0xE0):
- case (CTRL_END + 0xE0):
- case (CTRL_LEFT + 0xE0):
- case (CTRL_RIGHT+ 0xE0):
- case (CTRL_PGUP + 0xE0):
- case (CTRL_PGDN + 0xE0):
- os2data->key -= 0xE0;
- break;
- /* This is for the "Grey-Enter" key */
- case 0xE00D:
- os2data->key = 0x1C0D;
- break;
- }
- return(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 & check will know mthread isn't blocked.*/
- return(HARD_MEV);
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static boolean DIGPRIV initkeythread()
- {
- TID tid;
-
- 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 */
- return(TRUE);
- }
- return(FALSE);
- }
- /* -------------------------------------------------------------------------- */
-
- static void far keythread(void)
- {
- 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 */
-
- KbdCharIn(&keyinfo, IO_WAIT, os2data->hkbd);
- if (kmexit) break; /* kminfo may no longer be valid */
- os2data->key = MAKEUSHORT(keyinfo.chChar, keyinfo.chScan);
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static int DIGPRIV mousecheck()
- /*
- Return 1 for mouse, 0 for not installed.
- */
- {
- TID tid;
- unsigned 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) {
- os2data->mousehide = 1;
-
- 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((PUSHORT)&hval, kminfo->hmou);
-
- kminfo->oldpos.event = (unsigned)-1;
-
- /* Start mouse and hide threads */
- hsem = 0;
- DosSemSet(&hsem);
-
- if (DosCreateThread(hidethread, &tid, &kminfo->hstack[THREADSTACKSIZE]) == 0) {
- if (DosCreateThread(mousethread, &tid, &kminfo->mstack[THREADSTACKSIZE]) == 0) {
- DosSemWait(&mousem, -1L); /* Make sure thread is going before we continue */
- return(TRUE);
- }
- /* Kill hidethread if mousethread failed to start */
- kmexit = TRUE;
- DosSemClear(&hsem);
- }
- }
- ofree(OA_OS2KMDATA, (VOID *)kminfo);
- return(FALSE);
- }
- /* -------------------------------------------------------------------------- */
-
- static void far mousethread(void)
- {
- for (;;) {
- DosSemClear(&mousem); /* let ReadEvent know we're ready */
- DosSemWait(&gosem, -1L);
- if (kmexit) break; /* kminfo may no longer be valid */
-
- getmouevent();
- if (kmexit) break; /* kminfo may no longer be valid */
-
- DosSemSet(&gosem); /* Set this now so ReadEvent can't re-clear it before we've blocked on it (??) */
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV getmouevent(void)
- {
- MOUEVENTINFO mouev;
- MOUQUEINFO numevents;
- boolean wait = TRUE;
-
- MouGetNumQueEl(&numevents, kminfo->hmou);
- if (numevents.cEvents == 0) {
- if (os2data->evstash == HARD_MEV) {
- /* Not fresh event, but return anyway if we promised to */
- kminfo->moupos.x = kminfo->oldpos.x;
- kminfo->moupos.y = kminfo->oldpos.y;
- kminfo->moupos.event = kminfo->oldpos.event;
- return;
- }
- }
- 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) {
- 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;
-
- /* no memmove because it might not be reentrant */
- kminfo->oldpos.x = kminfo->moupos.x;
- kminfo->oldpos.y = kminfo->moupos.y;
- kminfo->oldpos.event = kminfo->moupos.event;
- break;
- }
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- 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 (os2data->mousehide != -1) {
- if (os2data->mousehide++ == 0) {
- /* wait != 0 means semaphore is set; waiting for event */
- if (DosSemWait(&mousem, 0L) != 0) {
- kminfo->hide = TRUE;
- DosSemClear(&hsem);
- }
- else {
- /* Not waiting for event; it can only be made to start waiting */
- /* by this thread */
- /* Also, hsem can only be cleared by this thread, so hsem will not */
- /* be cleared unexpectedly */
- DosSemSet(&hsem); /* keep hidethread from going around again */
- MouRemovePtr(&kminfo->mouserect, kminfo->hmou);
- }
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- void DIGPRIV os2_doshow()
- /*
- See above function (dohide) for comments.
- */
- {
- if (os2data->mousehide != 0) {
- if (--os2data->mousehide == 0) {
- if (DosSemWait(&mousem, 0L) != 0) {
- kminfo->hide = FALSE;
- DosSemClear(&hsem);
- }
- else {
- DosSemSet(&hsem); /* keep hidethread from going around again */
- MouDrawPtr(kminfo->hmou);
- }
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void far hidethread(void)
- {
- boolean lhide;
-
- for (;;) {
- DosSemRequest(&hsem, -1L);
- if (kmexit) break; /* kminfo may no longer be valid */
-
- /* If hsem was cleared again before here, the hide flag was also changed already */
- /* and we will perform the new request instead of the old one. */
- /* If it is cleared after here, we will go around again and do the new one the */
- /* next time through. */
- DosEnterCritSec(); /* Make decision and reset hsem atomically */
- lhide = kminfo->hide;
- if (DosSemWait(&hsem, 0L) == 0) { /* If hsem is clear again reset it */
- DosSemSet(&hsem);
- }
- DosExitCritSec();
-
- if (lhide) {
- MouRemovePtr(&kminfo->mouserect, kminfo->hmou);
- }
- else {
- MouDrawPtr(kminfo->hmou);
- }
- if (kmexit) break; /* kminfo may no longer be valid */
- }
- }
- /* -------------------------------------------------------------------------- */
-
- #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
-
-