home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c185 / 2.ddi / OWLSRC.EXE / CSCAPE / SOURCE / OS2HARD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-11  |  16.2 KB  |  566 lines

  1. /*
  2.     os2hard.c
  3.  
  4.     % OS/2 keyboard, mouse, timer, and speaker routines
  5.  
  6.     11/13/88  by Ted.
  7.  
  8.     OWL
  9.     Copyright (c) 1988, by Oakland Group, Inc.
  10.     ALL RIGHTS RESERVED.
  11.  
  12.     Revision History:
  13.     -----------------
  14.     12/01/88 ted    extracted event stuff.
  15.      2/07/89 Ted    added timeout wait arg to hCheckEvent function.
  16.      4/03/89 ted    Changed == 0 to != 0 for Kbd_Peek result in CheckEvent.
  17.      4/09/89 ted    converted for static digdata.
  18.      4/22/89 ted    merged in event stuff again, added digpriv's.
  19.      7/10/89 ted    put os2hdatastruc in here (we used to share w/ pchdatastruc.
  20.      8/31/89 ted    Added CLEAREVENTS.
  21.      9/10/89 gam    Added check for extended keys.
  22.      9/11/89 gam    added some casts for Version 1.1
  23. */
  24.  
  25. #include "os2priv.h"
  26.  
  27. #ifdef OAK_OS2            /* Only compile this for OS2 */
  28.  
  29. #include "scancode.h"    /* for mouse pseudo-scancodes */
  30.  
  31. pchdata_struct os2hdatastruc;
  32.  
  33. OSTATIC dig_hCheckEvent_func (os2_hCheckEvent);
  34. OSTATIC dig_hReadEvent_func (os2_hReadEvent);
  35. OSTATIC dig_hControl_func     (os2_hControl);
  36. OSTATIC dig_hGetShift_func    (os2_hGetShift);
  37. OSTATIC dig_hTimer_func        (os2_hTimer);
  38. OSTATIC dig_hPause_func        (os2_hPause);
  39. OSTATIC dig_hSound_func        (os2_hSound);
  40.  
  41. OSTATIC unsigned DIGPRIV os2_eventwait(_arg1(unsigned wait));
  42. OSTATIC boolean    DIGPRIV initkeythread(_arg1(void));
  43. OSTATIC void far keythread(_arg1(void));
  44. OSTATIC int     DIGPRIV mousecheck(_arg1(void));
  45. OSTATIC void far mousethread(_arg1(void));
  46. OSTATIC void     DIGPRIV getmouevent(_arg1(void));
  47. OSTATIC void far hidethread(_arg1(void));
  48.  
  49. #define newpos(mouev)    (mouev.col != kminfo->oldpos.x || \
  50.                          mouev.row != kminfo->oldpos.y || \
  51.                          mouev.fs  != kminfo->oldpos.event)
  52.  
  53. static boolean kmexit = TRUE;    /* thread termination flag */
  54. static RAMSEM psem;        /* re-entrancy protection semaphore */
  55. static RAMSEM gosem;    /* key/mouse thread start up semaphore */
  56. static RAMSEM keysem;    /* keystroke ready semaphore */
  57.  
  58. static RAMSEM mousem;    /* mouse event ready semaphore */
  59. static RAMSEM hsem;        /* hide cursor thread control semaphore */
  60.  
  61. static os2minfo_type kminfo = NULL;    /* mouse info ptr */
  62. /* -------------------------------------------------------------------------- */
  63.  
  64. void DIGPRIV os2_hOpen(digp)
  65.     dig_struct *digp;
  66. /* init keyboard pointers */
  67. {
  68.     digp->hCheckEvent = os2_hCheckEvent;
  69.     digp->hReadEvent  = os2_hReadEvent;
  70.     digp->hControl      = os2_hControl;
  71.     digp->hGetShift = os2_hGetShift;
  72.     digp->hTimer    = os2_hTimer;
  73.     digp->hPause    = os2_hPause;
  74.     digp->hSound    = os2_hSound;
  75. }
  76. /* -------------------------------------------------------------------------- */
  77.  
  78. static unsigned os2_hCheckEvent(wait)
  79.     unsigned wait;
  80. /* 
  81.     Return scancode if pending key event, HARD_MEV if no key but mouse event pending,
  82.     or KEY_NONE if no event is available before the wait time expires.
  83. */
  84. {
  85.     /* If event already checked positive, repeat the message */
  86.     if (os2data->evstash == KEY_NONE) {
  87.         return(os2data->evstash = os2_eventwait(wait));
  88.     }
  89.     else return(os2data->evstash);
  90. }
  91. /* -------------------------------------------------------------------------- */
  92.  
  93. static unsigned os2_hReadEvent(mouposp)
  94.     moupos_struct *mouposp;
  95. /* 
  96.     Returns key scancode if key event is available first, or HARD_MEV if
  97.     mouse event is available first. Returns key event if both key and mouse
  98.     event are available when it is called.
  99. */
  100. {
  101.     unsigned tevent;
  102.  
  103.     /* If CheckEvent already stashed an event, use that one. */
  104.     /* (If the checked event was from the mouse, try for a fresher one) */
  105.     if (os2data->evstash != KEY_NONE && os2data->evstash != HARD_MEV) {
  106.         tevent = os2data->evstash;
  107.     }
  108.     /* Otherwise, get a new event */
  109.     /* Note: if evstash is HARD_MEV eventwait will return right away */
  110.     else {
  111.         if ((tevent = os2_eventwait(-1)) == HARD_MEV) {
  112.             memmove(mouposp, &kminfo->moupos, sizeof(moupos_struct));
  113.         }
  114.     }
  115.     os2data->evstash = KEY_NONE;
  116.     return(tevent);
  117. }
  118. /* -------------------------------------------------------------------------- */
  119.  
  120. int os2_hControl(msg, indata, outdata)
  121.     dig_hcmsg msg;
  122.     VOID *indata;
  123.     VOID *outdata;
  124. {
  125.     PIDINFO pidi;
  126.     /* indata not used here for now. */ oak_notused(indata);
  127.     /* outdata not used here for now. */ oak_notused(outdata);
  128.  
  129.     switch (msg) {
  130.     case HC_OPEN:
  131.         os2data->dosbox = FALSE;
  132.  
  133.         os2hdata->ismouse = FALSE;
  134.         os2hdata->soundon = TRUE;
  135.  
  136.         psem = 0L;
  137.         os2data->pnest = 0;
  138.  
  139.         return(initkeythread());
  140.  
  141.     case HC_CLOSE:
  142.         kmexit = TRUE;    /* kill the threads */
  143.         DosSemClear(&gosem);
  144.  
  145.         if (kminfo != NULL) {
  146.             ofree(OA_OS2KMDATA, (VOID *)kminfo);
  147.             kminfo = NULL;
  148.         }
  149.         break;
  150.     case HC_INITMOUSE:
  151.         os2hdata->ismouse = mousecheck();    /* remember if mouse found */
  152.         /* no break; */
  153.     case HC_ISMOUSEON:
  154.         return((int)os2hdata->ismouse);
  155.     case HC_DEINITMOUSE:
  156.         os2hdata->ismouse = FALSE;
  157.         break;
  158.     case HC_SETMOUSEBOX:
  159.         break;
  160.     case HC_SETSOUNDON:
  161.         os2hdata->soundon = TRUE;
  162.         break;
  163.     case HC_SETSOUNDOFF:
  164.         os2hdata->soundon = FALSE;
  165.         break;
  166.     case HC_GETSOUNDON:
  167.         return((int)os2hdata->soundon);
  168.  
  169.     case HC_CLEAREVENTS:
  170.     {    /* Call ReadEvent until nothing in kb buffer */
  171.         moupos_struct mouposdum;
  172.  
  173.         while (os2_hCheckEvent(0) != KEY_NONE) {
  174.             os2_hReadEvent(&mouposdum);
  175.         }
  176.         break;
  177.     }
  178.     case HC_PROTECT:
  179.         DosGetPID(&pidi);
  180.         if (os2data->pnest == 0 || pidi.tid != os2data->ptid) {
  181.             DosSemRequest(&psem, -1L);
  182.             DosGetPID(&pidi);
  183.             os2data->ptid = pidi.tid;
  184.         }
  185.         os2data->pnest++;
  186.         break;
  187.     case HC_UNPROTECT:
  188.         os2data->pnest--;
  189.         if (os2data->pnest == 0) {
  190.             DosSemClear(&psem);
  191.         }
  192.         break;
  193.     }
  194.     return(TRUE);
  195. }
  196. /* -------------------------------------------------------------------------- */
  197.  
  198. static unsigned os2_hGetShift()
  199. /*
  200.     effects:    gets the state of the keyboard shift keys.
  201.     returns:    an encoding of the shift keys as follows:
  202.                 LSB    bit 0 - right shift
  203.                     bit 1 - left shift
  204.                     bit 2 - control
  205.                     bit 3 - alt
  206.                     bit 4 - scroll lock
  207.                     bit 5 - num lock
  208.                     bit 6 - caps lock
  209.                     bit 7 - insert
  210.                 MSB bits 8-15 - not used
  211. */
  212. {
  213.     KBDKEYINFO keyinfo;
  214.  
  215.     KbdPeek(&keyinfo, os2data->hkbd);
  216.     return(keyinfo.fsState);
  217. }
  218. /* -------------------------------------------------------------------------- */
  219.  
  220. static unsigned os2_hTimer()
  221. /*
  222.     effects:    Calculates current time stamp with 1/100 sec. resolution.
  223.                 Events with duration up to TIMER_LIMIT / 100 seconds
  224.                 can be timed.
  225.     returns:    An integer between 0 and TIMER_LIMIT - 1, which represents
  226.                 a time stamp. This time stamp can be compared to previous
  227.                 time stamps to calculate elapsed time in hundredths of
  228.                 seconds. The timer 'rolls over' at TIMER_LIMIT - 1.
  229. */
  230. {
  231.     DATETIME time;
  232.     unsigned hsecs, secs, mins;
  233.  
  234.     DosGetDateTime(&time);
  235.  
  236.     hsecs = time.hundredths;
  237.     secs = time.seconds * 100;
  238.     mins = time.minutes % 10;
  239.  
  240.     return((unsigned)(hsecs + secs * 100 + mins * 6000));
  241. }
  242. /* -------------------------------------------------------------------------- */
  243.  
  244. static void os2_hPause(duration)
  245.     unsigned duration;                /* duration in hundredths of secs */
  246. {
  247.     unsigned long sleep;
  248.  
  249.     sleep = duration;
  250.     sleep *= 10;        /* convert from hsecs to milliseconds */
  251.     DosSleep(sleep);
  252. }
  253. /* -------------------------------------------------------------------------- */
  254.  
  255. static void os2_hSound(pitch, duration)
  256.     unsigned int pitch;
  257.     unsigned int duration;        /* duration in hundredths of secs */
  258. {
  259.     if (os2hdata->soundon) {
  260.         DosBeep(pitch, duration);
  261.     }
  262. }
  263. /* -------------------------------------------------------------------------- */
  264. /* -------------------------------------------------------------------------- */
  265.  
  266. static unsigned DIGPRIV os2_eventwait(wait)
  267.     unsigned wait;
  268. /*
  269.     Returns event code if a key/mouse event occurs within the wait time.
  270.     Returns KEY_NONE if it times out.
  271. */
  272. {
  273.     unsigned which;
  274.     long lwait;
  275.  
  276.     /* Convert wait from short hsecs to long millisecs */
  277.     if (wait != -1) {
  278.         lwait = wait; lwait *= 10;
  279.     }
  280.     else lwait = -1;
  281.  
  282.     /* Throw out stale mouse event (if mouse is off, this will never clear) */
  283.     /* (mousem may already be set if no stale mouse event is waiting, but */
  284.     /*  it's ok if we set it again anyway) */
  285.     DosSemSet(&mousem);
  286.  
  287.     /* Block until a key or mouse event strikes */
  288.     /* (gosem may already be clear because we're still waiting from a */
  289.     /*  previous try, but it's ok if we clear it again anyway) */
  290.     DosSemClear(&gosem);
  291.  
  292.     if (DosMuxSemWait((PUSHORT)&which, &os2data->kmsemlist, lwait) != 0) {
  293.         return(KEY_NONE);        /* Timeout or Error */
  294.     }
  295.     if (which == 0) {    /* Key was received first */
  296.         DosSemSet(&keysem);
  297.         switch(os2data->key) {
  298.         case (HOME + 0xE0):
  299.         case (END  + 0xE0):
  300.         case (LEFT + 0xE0):
  301.         case (RIGHT+ 0xE0):
  302.         case (UP   + 0xE0):
  303.         case (DOWN + 0xE0):
  304.         case (PGUP + 0xE0):
  305.         case (PGDN + 0xE0):
  306.         case (INS  + 0xE0):
  307.         case (DEL  + 0xE0):
  308.         case (CTRL_HOME + 0xE0):
  309.         case (CTRL_END  + 0xE0):
  310.         case (CTRL_LEFT + 0xE0):
  311.         case (CTRL_RIGHT+ 0xE0):
  312.         case (CTRL_PGUP + 0xE0):
  313.         case (CTRL_PGDN + 0xE0):
  314.             os2data->key -= 0xE0;
  315.             break;
  316.         /* This is for the "Grey-Enter" key */
  317.         case 0xE00D:
  318.             os2data->key = 0x1C0D;
  319.             break;
  320.         }
  321.         return(os2data->key);
  322.     }
  323.     else {                /* Mouse was received first */
  324.     /*  mousem is reset above where we throw out the stale mouse event.    */
  325.     /* We don't reset it here so hide & check will know mthread isn't blocked.*/
  326.         return(HARD_MEV);
  327.     }
  328. }
  329. /* -------------------------------------------------------------------------- */
  330.  
  331. static boolean DIGPRIV initkeythread()
  332. {
  333.     TID tid;
  334.  
  335.     os2data->hkbd = 0;
  336.     os2data->evstash = KEY_NONE;
  337.  
  338.     /* Set up kmsemlist */
  339.     os2data->kmsemlist.cmxs = 2;
  340.     os2data->kmsemlist.amxs[0].zero = 0;
  341.     os2data->kmsemlist.amxs[0].hsem = &keysem;
  342.     os2data->kmsemlist.amxs[1].zero = 0;
  343.     os2data->kmsemlist.amxs[1].hsem = &mousem;
  344.  
  345.     /* Start key thread */
  346.     gosem = 0;
  347.     keysem = 0;
  348.     DosSemSet(&gosem);
  349.     DosSemSet(&keysem);
  350.     mousem = 0;
  351.     DosSemSet(&mousem);        /* Set mousem now; we want to mux-wait on it */
  352.     kmexit = FALSE;
  353.     if (DosCreateThread(keythread, &tid, &os2data->kstack[THREADSTACKSIZE]) == 0) {
  354.         DosSemWait(&keysem, -1L);    /* Make sure thread is going before we continue */
  355.         DosSemSet(&keysem);            /* Thread is now waiting for gosem */
  356.         return(TRUE);
  357.     }
  358.     return(FALSE);
  359. }
  360. /* -------------------------------------------------------------------------- */
  361.  
  362. static void far keythread(void)
  363. {
  364.     KBDKEYINFO keyinfo;
  365.  
  366.     for (;;) {
  367.         DosSemSet(&gosem);            /* Set this now so ReadEvent can't re-clear it before we've blocked on it (??) */ 
  368.         DosSemClear(&keysem);        /* let ReadEvent know we're ready */
  369.         DosSemWait(&gosem, -1L);
  370.         if (kmexit) break;    /* kminfo may no longer be valid */
  371.  
  372.         KbdCharIn(&keyinfo, IO_WAIT, os2data->hkbd);
  373.         if (kmexit) break;    /* kminfo may no longer be valid */
  374.         os2data->key = MAKEUSHORT(keyinfo.chChar, keyinfo.chScan);
  375.     }
  376. }
  377. /* -------------------------------------------------------------------------- */
  378.  
  379. static int DIGPRIV mousecheck()
  380. /*
  381.     Return 1 for mouse, 0 for not installed.
  382. */
  383. {
  384.     TID tid;
  385.     unsigned hval;
  386.  
  387.     if (kminfo != NULL) {
  388.         return(TRUE);
  389.     }
  390.     kminfo = (os2minfo_type) omalloc(OA_OS2KMDATA, sizeof(struct os2minfo_struct));
  391.     if (kminfo == NULL) {
  392.         return(FALSE);
  393.     }
  394.     if (MouOpen(0L, &kminfo->hmou) == 0) {
  395.         os2data->mousehide = 1;
  396.  
  397.         kminfo->mouserect.row = 0;
  398.         kminfo->mouserect.col = 0;
  399.         kminfo->mouserect.cRow = os2data->info.dispmap->height - 1;
  400.         kminfo->mouserect.cCol = os2data->info.dispmap->width - 1;
  401.  
  402.         hval = 0x0000;    /* Enable mouse ptr */
  403.         MouSetDevStatus((PUSHORT)&hval, kminfo->hmou);
  404.  
  405.         kminfo->oldpos.event = (unsigned)-1;
  406.  
  407.         /* Start mouse and hide threads */
  408.         hsem = 0;
  409.         DosSemSet(&hsem);
  410.  
  411.         if (DosCreateThread(hidethread, &tid, &kminfo->hstack[THREADSTACKSIZE]) == 0) {
  412.             if (DosCreateThread(mousethread, &tid, &kminfo->mstack[THREADSTACKSIZE]) == 0) {
  413.                 DosSemWait(&mousem, -1L);    /* Make sure thread is going before we continue */
  414.                 return(TRUE);
  415.             }
  416.             /* Kill hidethread if mousethread failed to start */
  417.             kmexit = TRUE;
  418.             DosSemClear(&hsem);
  419.         }
  420.     }
  421.     ofree(OA_OS2KMDATA, (VOID *)kminfo);
  422.     return(FALSE);
  423. }
  424. /* -------------------------------------------------------------------------- */
  425.  
  426. static void far mousethread(void)
  427. {
  428.     for (;;) {
  429.         DosSemClear(&mousem);        /* let ReadEvent know we're ready */
  430.         DosSemWait(&gosem, -1L);
  431.         if (kmexit) break;    /* kminfo may no longer be valid */
  432.  
  433.         getmouevent();
  434.         if (kmexit) break;    /* kminfo may no longer be valid */
  435.  
  436.         DosSemSet(&gosem);            /* Set this now so ReadEvent can't re-clear it before we've blocked on it (??) */ 
  437.     }
  438. }
  439. /* -------------------------------------------------------------------------- */
  440.  
  441. static void DIGPRIV getmouevent(void)
  442. {
  443.     MOUEVENTINFO mouev;
  444.     MOUQUEINFO numevents;
  445.     boolean wait = TRUE;
  446.  
  447.     MouGetNumQueEl(&numevents, kminfo->hmou);
  448.     if (numevents.cEvents == 0) {
  449.         if (os2data->evstash == HARD_MEV) {
  450.             /* Not fresh event, but return anyway if we promised to */
  451.             kminfo->moupos.x     = kminfo->oldpos.x;
  452.             kminfo->moupos.y     = kminfo->oldpos.y;
  453.             kminfo->moupos.event = kminfo->oldpos.event;
  454.             return;
  455.         }
  456.     }
  457.     for(;;) {    /* Slurp all pending events out of the queue */
  458.           MouReadEventQue(&mouev, (PUSHORT)&wait, kminfo->hmou);
  459.         if (kmexit) return;    /* kminfo may no longer be valid */
  460.  
  461.         MouGetNumQueEl(&numevents, kminfo->hmou);
  462.         if (numevents.cEvents == 0) {
  463.             if (newpos(mouev)) {
  464.                 /* The queue is sucked dry; return the last event */
  465.                 kminfo->moupos.x = mouev.col;
  466.                 kminfo->moupos.y = mouev.row;
  467.                 kminfo->moupos.event = mouev.fs;
  468.  
  469.                 /* no memmove because it might not be reentrant */
  470.                 kminfo->oldpos.x     = kminfo->moupos.x;
  471.                 kminfo->oldpos.y     = kminfo->moupos.y;
  472.                 kminfo->oldpos.event = kminfo->moupos.event;
  473.                 break;
  474.             }
  475.         }
  476.     }
  477. }
  478. /* -------------------------------------------------------------------------- */
  479.  
  480. void DIGPRIV os2_dohide()
  481. /*
  482.     This function hides the mouse pointer. However, there is a bug in
  483.     MouRemovePtr where it doesn't hide the pointer or return until the next
  484.     mouse event strikes, if MouReadEventQue is blocked waiting for the next
  485.     mouse event. Therefore, this funtion activates hidethread to call
  486.     MouRemovePtr so that we can go about our business while MouRemovePtr
  487.     is erroneously blocked.
  488. */
  489. {
  490.     if (os2data->mousehide != -1) {
  491.         if (os2data->mousehide++ == 0) {
  492.             /* wait != 0 means semaphore is set; waiting for event */
  493.             if (DosSemWait(&mousem, 0L) != 0) {
  494.                 kminfo->hide = TRUE;
  495.                 DosSemClear(&hsem);
  496.             }
  497.             else {
  498.             /* Not waiting for event; it can only be made to start waiting */
  499.             /* by this thread */
  500.             /* Also, hsem can only be cleared by this thread, so hsem will not */
  501.             /* be cleared unexpectedly */
  502.                 DosSemSet(&hsem);    /* keep hidethread from going around again */
  503.                 MouRemovePtr(&kminfo->mouserect, kminfo->hmou);
  504.             }
  505.         }
  506.     }
  507. }
  508. /* -------------------------------------------------------------------------- */
  509.  
  510. void DIGPRIV os2_doshow()
  511. /*
  512.     See above function (dohide) for comments.
  513. */
  514. {
  515.     if (os2data->mousehide != 0) {
  516.         if (--os2data->mousehide == 0) {
  517.             if (DosSemWait(&mousem, 0L) != 0) {
  518.                 kminfo->hide = FALSE;
  519.                 DosSemClear(&hsem);
  520.             }
  521.             else {
  522.                 DosSemSet(&hsem);    /* keep hidethread from going around again */
  523.                 MouDrawPtr(kminfo->hmou);
  524.             }
  525.         }
  526.     }
  527. }
  528. /* -------------------------------------------------------------------------- */
  529.  
  530. static void far hidethread(void)
  531. {
  532.     boolean lhide;
  533.  
  534.     for (;;) {
  535.         DosSemRequest(&hsem, -1L);
  536.         if (kmexit) break;    /* kminfo may no longer be valid */
  537.  
  538. /* If hsem was cleared again before here, the hide flag was also changed already */
  539. /* and we will perform the new request instead of the old one. */
  540. /* If it is cleared after here, we will go around again and do the new one the */
  541. /* next time through. */
  542.         DosEnterCritSec();    /* Make decision and reset hsem atomically */
  543.         lhide = kminfo->hide;
  544.         if (DosSemWait(&hsem, 0L) == 0) {    /* If hsem is clear again reset it */
  545.             DosSemSet(&hsem);
  546.         }
  547.         DosExitCritSec();
  548.  
  549.         if (lhide) {
  550.             MouRemovePtr(&kminfo->mouserect, kminfo->hmou);
  551.         }
  552.         else {
  553.             MouDrawPtr(kminfo->hmou);
  554.         }
  555.         if (kmexit) break;    /* kminfo may no longer be valid */
  556.     }
  557. }
  558. /* -------------------------------------------------------------------------- */
  559.  
  560. #else    /* ifndef OAK_OS2 */
  561. /* A dummy so compilers won't freak if everything else is ifdef'ed out. */
  562.     int os2harddummy(void);
  563.     int os2harddummy() { return(0); }
  564. #endif
  565.  
  566.