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