home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / CSAPE32.ARJ / SOURCE / OWLSCR / PCHARD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-31  |  18.7 KB  |  658 lines

  1. /*
  2.     pchard.c
  3.  
  4.     % PC keyboard, mouse, timer, and speaker routines
  5.  
  6.     5/16/88  by Ted.
  7.  
  8.     OWL-PC 1.2
  9.     Copyright (c) 1988, by Oakland Group, Inc.
  10.     ALL RIGHTS RESERVED.
  11.  
  12.     Revision History:
  13.     -----------------
  14.      9/09/88 jmd    Fixed kRead and kCheck
  15.     10/19/88 ted    Changed how dopause works, extracted dig_SubHsecs
  16.     11/22/88 ted    Merged key & hard structures, added ReadEvent.
  17.     12/12/88 ted    Merged CheckKey and CheckMouse into CheckEvent.
  18.     12/14/88 ted    Changed CheckEvent to unsigned so it can return MOU_EVENT.
  19.      2/07/89 Ted    added timeout wait arg to hCheckEvent function.
  20.      2/09/89 Ted    added setmousebox implementation
  21.      2/28/89 ted    moved Control, CheckEvent and ReadEvent out to pcevent.c
  22.      3/26/89 ted    Added wait feature for CheckEvent.
  23.      4/04/89 ted    Added mouse de-initialization feature.
  24.      4/22/89 ted    moved Control, CheckEvent and ReadEvent back in.
  25.      7/10/89 ted    moved pchdatastruc back in here (it was in its own file).
  26.      7/12/89 ted    Added OSTATIC's and '_func' macros.
  27.      8/11/89 ted    Added SETMOUSESHAPE.
  28.      8/24/89 ted    Added GETMOUSESHAPE.
  29.      8/31/89 ted    Added CLEAREVENTS.
  30.      8/31/89 jmd    Added call to disp_EvCheck
  31.      9/12/89 ted    Removed ref. to pcdata in mouseshape that messed up FAMILYAPI.
  32.  
  33.     11/05/89 ted    Added DOS_ZEROSEG macro.
  34.     11/08/89 ted    Initialized xdata and xdatasize pchdata elements.
  35.     12/08/89 ted    Added eventchecked = TRUE in ReadEvent.
  36.      2/22/90 ted    Got rid of static dopause function.
  37.      2/22/90 ted    Made pc_hControl public.
  38.      2/24/90 ted    Indirected getmoupos through an fptr so MGR can share it.
  39.      2/28/90 ted    Added desqview detect and pauses.
  40.      3/28/90 jmd    ansi-fied
  41.      5/11/90 jmd    converted to new scancode scheme
  42.      6/22/90 ted    added "void"s to no-parameter functions per ansii.
  43.      7/25/90 jmd    added test for numlock state to pc_CvtScancode
  44.      9/06/90 jmd    removed pc_CvtScancode
  45.      9/09/90 ted    Added extended BIOS kb-int support.
  46.     10/11/90 ted    Added ctrl-break KEY_SIGNAL return option.
  47. */
  48.  
  49. #include "pcpriv.h"
  50. #include "scancode.h"    /* for mouse pseudo-scancodes */
  51. #include "dpref.h"        /* for dpref_GetPcCbrk() */
  52.  
  53. OGLOBAL pchdata_struct pchdatastruc;
  54.  
  55. OSTATIC dig_hCheckEvent_func (pc_hCheckEvent);
  56. OSTATIC dig_hReadEvent_func    (pc_hReadEvent);
  57. OSTATIC dig_hGetShift_func    (pc_hGetShift);
  58. OSTATIC dig_hPause_func        (pc_hPause);
  59. OSTATIC dig_hSound_func        (pc_hSound);
  60.  
  61. OSTATIC getmoupos_func        (getmoupos);
  62.  
  63. OSTATIC int     DIGPRIV mousecheck(void);
  64. OSTATIC boolean DIGPRIV setmousebox(opbox *mbox);
  65. OSTATIC boolean DIGPRIV setmouseshape(mouseshape_struct *mshape);
  66. OSTATIC boolean DIGPRIV makemasks(mouseshape_struct *mshape, unsigned short *msmask);
  67. OSTATIC byte    DIGPRIV pc_xkbtest(void);
  68.  
  69. #ifdef OAK_DESQVIEW
  70. #    define dv_pause()    ((pchdata->desqview) ? (regs.x.ax = DVC_PAUSE, oakint86(DV_INT, ®s)) : 0)
  71. #    define dvregs        OREGS regs
  72. #else
  73. #    define dvregs
  74. #    define dv_pause()
  75. #endif
  76. /* -------------------------------------------------------------------------- */
  77.  
  78. void pc_hOpen(dig_struct *digp)
  79. /*
  80.     Init hardware pointers.
  81.     Note: not declared digpriv so it can be called from os2hard, which may be
  82.     in a different segment.
  83. */
  84. {
  85.     digp->hCheckEvent = pc_hCheckEvent;
  86.     digp->hReadEvent  = pc_hReadEvent;
  87.     digp->hGetShift = pc_hGetShift;
  88.     digp->hTimer   = pc_hTimer;
  89.     digp->hPause   = pc_hPause;
  90.     digp->hSound   = pc_hSound;
  91.     digp->hControl = pc_hControl;
  92. }
  93. /* -------------------------------------------------------------------------- */
  94.  
  95. static int pc_hCheckEvent(unsigned wait)
  96. /* 
  97.     Return scancode if pending key event, HARD_MEV if no key but mouse event pending,
  98.     or KEY_NONE if no event is available before the wait time expires.
  99. */
  100. {
  101.     OREGS regs;
  102.     unsigned itime;
  103.  
  104.     if (wait != 0 && wait != (unsigned) -1) {
  105.         itime = pc_hTimer();
  106.     }
  107.     for (;;) {        /* loop until timeout */
  108. #ifdef OAK_CBRK
  109.         /* If control-break was detected, return KEY_SIGNAL */
  110.         if (pc_checkcbrk(FALSE)) {
  111.             return(KEY_SIGNAL);
  112.         }
  113. #endif
  114.         regs.h.ah = (byte)KBINT_STATUS + pchdata->xkbint;
  115.         if (oakint86(BIOS_KBINT, ®s) & PC_ZFLAG) {    /* no key ready */
  116.             if (pchdata->ismouse) {
  117.                 if ((*pchdata->getmoupos)(NULL)) {                    /* mouse ready */
  118.                     pchdata->eventchecked = TRUE;
  119.                     return(HARD_MEV);    /* no key, but mouse ready */
  120.                 }
  121.             }
  122.         /*    else no mouse or key ready */
  123.         }
  124.         else {        /* key ready */
  125.             pchdata->eventchecked = TRUE;
  126.             return((int) regs.x.ax);
  127.         }
  128.         /* No key or mouse ready - see if wait duration has expired */
  129.         if (wait == 0) {
  130.             break;
  131.         }
  132.         else if (wait != (unsigned) -1) {
  133.             if (dig_SubHsecs(itime, pc_hTimer()) > wait) {
  134.                 break;        /* break out of the loop and give up if time out */
  135.             }
  136.         }
  137.         dv_pause();        /* Give up time slice if DESQview's running */
  138.     }
  139.     return(KEY_NONE);
  140. }
  141. /* -------------------------------------------------------------------------- */
  142.  
  143. static int pc_hReadEvent(moupos_struct *mouposp)
  144. /*
  145.     Returns key scancode if key event is available first, or HARD_MEV if
  146.     mouse event is available first. Returns key event if both key and mouse
  147.     event are available when it is called.
  148. */
  149. {
  150.     OREGS regs;
  151.  
  152.     for (;;) {
  153.  
  154. #ifdef OAK_CBRK
  155.         /* If control-break was detected, return KEY_SIGNAL */
  156.         if (pc_checkcbrk(TRUE)) {
  157.             return(KEY_SIGNAL);
  158.         }
  159. #endif
  160.     /* Return when keyboard character is available */
  161.         regs.h.ah = (byte)KBINT_STATUS + pchdata->xkbint;
  162.         if (!(oakint86(BIOS_KBINT, ®s) & PC_ZFLAG)) {
  163.             regs.h.ah = (byte)KBINT_READ + pchdata->xkbint;
  164.             oakint86(BIOS_KBINT, ®s);
  165.             pchdata->eventchecked = FALSE;
  166.  
  167.             if (pchdata->xkbint != 0) {
  168.                 switch(regs.x.ax) {
  169.  
  170.                 /* The "Grey-Enter" key */
  171.                 case 0xE00D:
  172.                     regs.x.ax = ENTER;
  173.                     break;
  174.  
  175.                 /* Strip low-byte E0 from non-ascii scancodes that might have it */
  176.                 case ((unsigned) LEFT | 0xE0):
  177.                 case ((unsigned) RIGHT| 0xE0):
  178.                 case ((unsigned) UP   | 0xE0):
  179.                 case ((unsigned) DOWN | 0xE0):
  180.                 case ((unsigned) HOME | 0xE0):
  181.                 case ((unsigned) END  | 0xE0):
  182.                 case ((unsigned) PGUP | 0xE0):
  183.                 case ((unsigned) PGDN | 0xE0):
  184.                 case ((unsigned) INS  | 0xE0):
  185.                 case ((unsigned) DEL  | 0xE0):
  186.                 case ((unsigned) CTRL_LEFT | 0xE0):
  187.                 case ((unsigned) CTRL_RIGHT| 0xE0):
  188.                 case ((unsigned) CTRL_UP   | 0xE0):
  189.                 case ((unsigned) CTRL_DOWN | 0xE0):
  190.                 case ((unsigned) CTRL_HOME | 0xE0):
  191.                 case ((unsigned) CTRL_END  | 0xE0):
  192.                 case ((unsigned) CTRL_PGUP | 0xE0):
  193.                 case ((unsigned) CTRL_PGDN | 0xE0):
  194.                 case ((unsigned) CTRL_INS  | 0xE0):
  195.                 case ((unsigned) CTRL_DEL  | 0xE0):
  196.                     regs.x.ax &= 0xFF00;
  197.                     break;
  198.                 }
  199.             }
  200.             return((int) regs.x.ax);
  201.         }
  202.         if (mouposp != NULL && pchdata->ismouse) {
  203.             if ((*pchdata->getmoupos)(NULL)) {                    /* mouse ready */
  204.                 pchdata->eventchecked = TRUE;
  205.                 (*pchdata->getmoupos)(mouposp);
  206.  
  207.                 if (pchdata->eventchecked) {
  208.                     pchdata->eventchecked = FALSE;
  209.                 /* If we promised a mouse return but the mouse was deinitted */
  210.                 /*  before we could return it, just return a KEY_NONE event. */
  211.                     if (!pchdata->ismouse) {
  212.                         return(KEY_NONE);
  213.                     }
  214.                 }
  215.                 return(HARD_MEV);
  216.             }
  217.         }
  218.         dv_pause();        /* Give up time slice if DESQview's running */
  219.     }
  220. }
  221. /* -------------------------------------------------------------------------- */
  222.  
  223. int pc_hControl(dig_hcmsg msg, VOID *indata, VOID *outdata)
  224. {
  225.     /* static default cursor masks - needed in case of first 'getcursorshape' */
  226.     static bmap_struct(16,16) arrowimage = {
  227.         16, 16,
  228.         0x00,0x00, 0x40,0x00, 0x60,0x00, 0x70,0x00,
  229.         0x78,0x00, 0x7C,0x00, 0x7E,0x00, 0x7F,0x00,
  230.         0x7F,0x80, 0x7C,0x00, 0x6C,0x00, 0x46,0x00,
  231.         0x06,0x00, 0x03,0x00, 0x03,0x00, 0x00,0x00
  232.     };
  233.     static bmap_struct(16,16) arrowmask = {
  234.         16, 16,
  235.         0x3F,0xFF, 0x1F,0xFF, 0x0F,0xFF, 0x07,0xFF,
  236.         0x03,0xFF, 0x01,0xFF, 0x00,0xFF, 0x00,0x7F,
  237.         0x00,0x3F, 0x00,0x1F, 0x01,0xFF, 0x10,0xFF,
  238.         0x30,0xFF, 0xF8,0x7F, 0xF8,0x7F, 0xFC,0x7F
  239.     };
  240.     static mouseshape_struct defmouseshape = {
  241.         (bmap_type)(&arrowimage), (bmap_type)(&arrowmask), 0, 0, 0x77FF, 0x7700
  242.     };
  243.  
  244.     switch (msg) {
  245.     case HC_OPEN:
  246.         pchdata->soundon = TRUE;
  247.         pchdata->ismouse = FALSE;
  248.         pchdata->xkbint = pc_xkbtest();
  249.         pchdata->curmouseshape = &defmouseshape;    /* not in initmouse so mgr can share it */
  250.         pchdata->xdata = NULL;    /* Terminate the data block chain for now */
  251.         pchdata->xdatasize = 0;
  252.     /*  rest of mouse vars handled in HC_INITMOUSE method */
  253. #ifdef OAK_DESQVIEW
  254.         pchdata->desqview = pch_IsDESQview();
  255. #endif
  256. #ifdef OAK_CBRK
  257.         if (dp_GetPcCbrk()) {
  258.             pc_catchcbrk();
  259.         }
  260. #endif
  261.         break;
  262.  
  263. #ifdef OAK_CBRK
  264.     case HC_CLOSE:
  265.         pc_restorecbrk();
  266.         break;
  267. #endif
  268.  
  269.     case HC_INITMOUSE:
  270.         if ((pchdata->ismouse = mousecheck()) != 0) { /* remember if mouse found */
  271.             pchdata->xlastmou  = pchdata->ylastmou = 0;
  272.             pchdata->blastmou = 0;
  273.             pchdata->eventchecked = FALSE;
  274.             pchdata->getmoupos = getmoupos;
  275.         }
  276.         /* no break; */
  277.     case HC_ISMOUSEON:
  278.         return((int)pchdata->ismouse);
  279.  
  280.     case HC_DEINITMOUSE:
  281.         pchdata->ismouse = FALSE;
  282.         break;
  283.  
  284.     case HC_SETMOUSEBOX:
  285.         if (pchdata->ismouse) {
  286.             return((int)setmousebox((opbox *) indata));
  287.         }
  288.         break;
  289.  
  290.     case HC_SETMOUSESHAPE:
  291.         /*
  292.         Note: any bmaps passed here must not be freed as long as someone
  293.          might call 'getmouseshape' and then 'setmouseshape' again with the
  294.          gotten shape struct and its pointers to your old bmaps.
  295.         */
  296.         if (pchdata->ismouse) {
  297.             if (setmouseshape((mouseshape_struct *) indata)) {
  298.                   memmove((VOID *)pchdata->curmouseshape, indata, sizeof(mouseshape_struct));
  299.                 break;
  300.             }
  301.         }
  302.         return(FALSE);
  303.  
  304.     case HC_GETMOUSESHAPE:
  305.           memmove(outdata, (VOID *)pchdata->curmouseshape, sizeof(mouseshape_struct));
  306.         break;
  307.  
  308.     case HC_SETSOUNDON:
  309.         pchdata->soundon = TRUE;
  310.         break;
  311.     case HC_SETSOUNDOFF:
  312.         pchdata->soundon = FALSE;
  313.         break;
  314.     case HC_GETSOUNDON:
  315.         return((int)pchdata->soundon);
  316.     case HC_CLEAREVENTS:
  317.     {    /* Call ReadEvent until nothing in kb buffer */
  318.         moupos_struct mouposdum;
  319.  
  320.         if (disp_EvCheck()) {
  321.             while (pc_hCheckEvent(0) != KEY_NONE) {
  322.                 pc_hReadEvent(&mouposdum);
  323.             }
  324.         }
  325.         break;
  326.     }
  327.     }
  328.     return(TRUE);
  329. }
  330. /* -------------------------------------------------------------------------- */
  331.  
  332. static unsigned pc_hGetShift(void)
  333. /*
  334.     effects:    gets the state of the keyboard shift keys.
  335.     returns:    an encoding of the shift keys as follows:
  336.                 LSB    bit 0 - right shift
  337.                     bit 1 - left shift
  338.                     bit 2 - control
  339.                     bit 3 - alt
  340.                     bit 4 - scroll lock
  341.                     bit 5 - num lock
  342.                     bit 6 - caps lock
  343.                     bit 7 - insert
  344.                 MSB bits 8-15 - not used
  345. */
  346. {
  347.     OREGS regs;
  348.     
  349.     regs.h.ah = (byte)KBINT_GETSHIFT + pchdata->xkbint;
  350.     oakint86(BIOS_KBINT, ®s);
  351.     return((unsigned)regs.h.al);
  352. }
  353. /* -------------------------------------------------------------------------- */
  354.  
  355. unsigned pc_hTimer(void)
  356. /*
  357.     effects:    Calculates current time stamp with 1/100 sec. resolution.
  358.                 Events with duration up to TIMER_LIMIT / 100 seconds
  359.                 can be timed.
  360.     returns:    An integer between 0 and TIMER_LIMIT - 1, which represents
  361.                 a time stamp. This time stamp can be compared to previous
  362.                 time stamps to calculate elapsed time in hundredths of
  363.                 seconds. The timer 'rolls over' at TIMER_LIMIT - 1.
  364. */
  365. {
  366.     OREGS regs;
  367.     unsigned hsecs, secs, mins;
  368.  
  369.     regs.h.ah = DOS_GETTIME;
  370.     oakint86(DOS_INT, ®s);
  371.  
  372.     hsecs = regs.h.dl;
  373.     secs = regs.h.dh;
  374.     mins = regs.h.cl % 10;
  375.  
  376.     return((unsigned)(hsecs + secs * 100 + mins * 6000));
  377. }
  378. /* -------------------------------------------------------------------------- */
  379.  
  380. static void pc_hPause(unsigned duration)
  381. /*
  382.     This function uses the system clock and causes a delay 
  383.     of the specified duration.
  384.     'duration' is duration in hundredths of secs
  385. */
  386. {
  387.     unsigned tstart;
  388.     dvregs;
  389.  
  390.     tstart = pc_hTimer();
  391.     while (dig_SubHsecs(tstart, pc_hTimer()) < duration) {
  392.         dv_pause();        /* Give up time slice if DESQview's running */
  393.     }
  394. }
  395. /* -------------------------------------------------------------------------- */
  396.  
  397. static void pc_hSound(unsigned pitch, unsigned duration)
  398. {
  399.     if (pchdata->soundon) {
  400.         outp( SPKR_CNTRL2, SPKR_MODE3);                /* put timer 2 into mode 3 */
  401.         outp( SPKR_TIMER2, pitch & 0x00FF);            /* wavelength for timer 2 */
  402.         outp( SPKR_TIMER2, pitch / 0x00FF);
  403.  
  404.         outp(DOS_PORTB, inp(DOS_PORTB) | 0x03);        /* turn on speaker */
  405.         pc_hPause(duration);                            /* wait... */
  406.         outp(DOS_PORTB, inp(DOS_PORTB) & 0xFC);        /* turn off speaker */
  407.     }
  408. }
  409. /* -------------------------------------------------------------------------- */
  410.  
  411. static int DIGPRIV mousecheck(void)
  412. /*
  413.     Return 1 for mouse, 0 for not installed
  414. */
  415. {
  416.     OREGS regs;
  417.     long mousevec;
  418.  
  419.     /* Peek at mouse interrupt vector to see if it is null */
  420.     ram_segtomem(DOS_ZEROSEG, 4 * BIOS_MOUSEINT, (byte *) &mousevec, 4);
  421.     if (mousevec == 0) {
  422.         return 0;    /* if no seg or offset return 0 */
  423.     }
  424.  
  425.     /* Try the mouse interupt - if it leaves ax alone it's not real */
  426.     regs.x.ax = BMOU_INIT;
  427.     oakint86(BIOS_MOUSEINT, ®s);
  428.     return(regs.x.ax != BMOU_INIT);
  429. }
  430. /* -------------------------------------------------------------------------- */
  431.  
  432. static boolean DIGPRIV getmoupos(moupos_struct *mouposp)
  433. /*
  434.     If mouposp != NULL, wait for a mouse event and return it in mouposp.
  435.     Otherwise, don't wait and return whether an event is ready or not.
  436. */
  437. {
  438.     opcoord mx, my;
  439.     unsigned buttons;
  440.     boolean motion;
  441.     OREGS regs;
  442.  
  443.     if (mouposp == NULL) {    /* CheckEvent call */
  444.         if (pchdata->eventchecked) {
  445.             return(TRUE);
  446.         }
  447.     }
  448.     for (;;) {
  449.         regs.x.ax = BMOU_GETPOS;
  450.         oakint86(BIOS_MOUSEINT, ®s);
  451.  
  452.         mx = regs.x.cx / pchdata->xmouscale;
  453.         my = regs.x.dx / pchdata->ymouscale;
  454.         buttons = regs.x.bx;
  455.  
  456.         motion = (mx != pchdata->xlastmou || my != pchdata->ylastmou);
  457.  
  458.         if (!motion && pchdata->blastmou == buttons) {
  459.         /* If no change in mouse position or buttons: try again */
  460.             if (mouposp == NULL) {    /* CheckEvent call */
  461.                 return(FALSE);    /* Return if this is just a CheckMouse */
  462.             }
  463.         /* If we previously reported a change, return an */
  464.         /* event now, even though the change went away again */
  465.         /* Otherwise, go around for another mouse read */
  466.             if (!pchdata->eventchecked) {
  467.                 continue;
  468.             }
  469.             else {
  470.                 motion = TRUE;    /* Fudge it: report motion anyway */
  471.             }
  472.         }
  473.         else {    /* Motion or button change */
  474.             if (mouposp == NULL) {    /* CheckEvent call */
  475.                 return(TRUE);
  476.             }
  477.         }
  478.         pchdata->xlastmou = mx;
  479.         pchdata->ylastmou = my;
  480.         pchdata->blastmou = buttons;
  481.  
  482.         mouposp->x = mx;
  483.         mouposp->y = my;
  484.         mouposp->event = 0;
  485.         if (buttons & 0x01) {    /* Left button */
  486.             if (motion) {
  487.                 mouposp->event |= MEV_BUT1MOVE;
  488.             }
  489.             else {
  490.                 mouposp->event |= MEV_BUT1;
  491.             }
  492.         }
  493.         if (buttons & 0x02) {    /* Right button */
  494.             if (motion) {
  495.                 mouposp->event |= MEV_BUT2MOVE;
  496.             }
  497.             else {
  498.                 mouposp->event |= MEV_BUT2;
  499.             }
  500.         }
  501.         if (buttons & 0x04) {    /* Middle button */
  502.             if (motion) {
  503.                 mouposp->event |= MEV_BUT3MOVE;
  504.             }
  505.             else {
  506.                 mouposp->event |= MEV_BUT3;
  507.             }
  508.         }
  509.         if (motion && mouposp->event == 0) {
  510.             mouposp->event |= MEV_MOVE;
  511.         }
  512.         break;
  513.     }
  514.     return(TRUE);
  515. }
  516. /* -------------------------------------------------------------------------- */
  517.  
  518. static boolean DIGPRIV setmousebox(opbox *mbox)
  519. {
  520.     OREGS regs;
  521.  
  522.     regs.x.ax = BMOU_XRANGE;
  523.     regs.x.cx = mbox->xmin * pchdata->xmouscale;
  524.     regs.x.dx = (mbox->xmax-1) * pchdata->xmouscale;
  525.     oakint86(BIOS_MOUSEINT, ®s);
  526.  
  527.     regs.x.ax = BMOU_YRANGE;
  528.     regs.x.cx = mbox->ymin * pchdata->ymouscale;
  529.     regs.x.dx = (mbox->ymax-1) * pchdata->ymouscale;
  530.     oakint86(BIOS_MOUSEINT, ®s);
  531.  
  532.     return(TRUE);
  533. }
  534. /* -------------------------------------------------------------------------- */
  535.  
  536. static boolean DIGPRIV setmouseshape(mouseshape_struct *mshape)
  537. /*
  538.     Return TRUE if graphics cursor shape was set, FALSE if not. Text cursor is
  539.     always set in any case.
  540. */
  541. {
  542.     OREGS regs;
  543.     unsigned short msmask[2*16];
  544.  
  545.     if (ofont_GetWidth(disp_GetDefFont()) == 1) {    /* text mode */
  546.         if (mshape->tsmask == 0 && mshape->tcmask == 0) {
  547.             return(FALSE);    /* Fail if 0 cursor and mask given */
  548.         }
  549.         /* Set software text mode mouse cursor in text mode */
  550.         regs.x.ax = BMOU_TMSHAPE;
  551.         regs.x.bx = 0;
  552.         regs.x.cx = mshape->tsmask;
  553.         regs.x.dx = mshape->tcmask;
  554.         oakint86(BIOS_MOUSEINT, ®s);
  555.     }
  556.     else {
  557.         /* Convert given pmaps to cursor shape and mask bit arrays */
  558.         if (!makemasks(mshape, msmask)) {
  559.             return(FALSE);
  560.         }
  561.         /* Set graphics mode cursor shape and mask */
  562.         regs.x.ax = BMOU_MSHAPE;
  563.         regs.x.bx = mshape->xhot * pchdata->xmouscale;
  564.         regs.x.cx = mshape->yhot * pchdata->ymouscale;
  565.         regs.a.esdx = msmask;
  566.         oakint86es(BIOS_MOUSEINT, ®s, sizeof(msmask));
  567.     }
  568.     return(TRUE);
  569. }
  570. /* -------------------------------------------------------------------------- */
  571.  
  572. static boolean DIGPRIV makemasks(mouseshape_struct *mshape, unsigned short *msmask)
  573. {
  574.     odim i;
  575.     byte *inb, *outb;
  576.  
  577.     if (mshape->mask == NULL || mshape->image == NULL) {
  578.         return(FALSE);
  579.     }
  580.     outb = (byte *)msmask;
  581.     for (i = 0; i < 16; i++) {
  582.         if (i < mshape->mask->height) {
  583.             inb = bmap_GetLine(mshape->mask, i);
  584.             *(outb++) = *(inb+1); *(outb++) = *inb;
  585.         }
  586.         else {
  587.             *(outb++) = 0xFF; *(outb++) = 0xFF;
  588.         }
  589.     }
  590.     for (i = 0; i < 16; i++) {
  591.         if (i < mshape->image->height) {
  592.             inb = bmap_GetLine(mshape->image, i);
  593.             *(outb++) = *(inb+1); *(outb++) = *inb;
  594.         }
  595.         else {
  596.             *(outb++) = 0x00; *(outb++) = 0x00;
  597.         }
  598.     }
  599.     return(TRUE);
  600. }
  601. /* -------------------------------------------------------------------------- */
  602.  
  603. static byte DIGPRIV pc_xkbtest(void)
  604. /*    Detect whether extended BIOS KBINT funcs are available.
  605. */
  606. {
  607.     OREGS regs;
  608.     byte kbstatus, xkboffs;
  609.  
  610.     xkboffs = 0;
  611.  
  612.     /* Get kb status byte from BIOS data area */
  613.     ram_segtomem(0x40, 0x17, &kbstatus, 1);
  614.  
  615.     /* Try to get kb shift state from extended BIOS call */
  616.     regs.h.ah = KBINT_GETSHIFT + 0x10;
  617.     oakint86(BIOS_KBINT, ®s);
  618.  
  619.     /* If same, change it in data area and see if call returns the new value. */
  620.     if (regs.h.al == kbstatus) {
  621.         /* Change kb status byte in BIOS data area */
  622.         kbstatus ^= 0x10;    /* Twiddle scroll lock bit in shift state */
  623.         ram_memtoseg(0x40, 0x17, &kbstatus, 1);
  624.  
  625.         /* Try again */
  626.         regs.h.ah = KBINT_GETSHIFT + 0x10;
  627.         oakint86(BIOS_KBINT, ®s);
  628.         if (regs.h.al == kbstatus) {
  629.             xkboffs = 0x10;
  630.         }
  631.         /* Restore kb status byte in BIOS data area */
  632.         kbstatus ^= 0x10;    /* Un-twiddle scroll lock bit in shift state */
  633.         ram_memtoseg(0x40, 0x17, &kbstatus, 1);
  634.  
  635.         /* Do this read again so BIOS can restore keyboard scroll lock light */
  636.         regs.h.ah = KBINT_GETSHIFT + 0x10;
  637.         oakint86(BIOS_KBINT, ®s);
  638.     }
  639.     return(xkboffs);
  640. }
  641. /* -------------------------------------------------------------------------- */
  642. #ifdef OAK_DESQVIEW
  643. boolean DIGPRIV pch_IsDESQview(void)
  644. {
  645.     OREGS regs;
  646.     static char badvals[] = "DESQ";
  647.  
  648.     regs.x.ax = DOS_DVPRESENT;
  649.     regs.x.bx = 0;
  650.     regs.x.cx = *((unsigned short *) &badvals[0]);
  651.     regs.x.dx = *((unsigned short *) &badvals[2]);
  652.     oakint86(DOS_INT, ®s);
  653.     return(regs.x.bx != 0);
  654. }
  655. #endif
  656. /* -------------------------------------------------------------------------- */
  657.  
  658.