home *** CD-ROM | disk | FTP | other *** search
- /*
- pchard.c
-
- % PC keyboard, mouse, timer, and speaker routines
-
- 5/16/88 by Ted.
-
- OWL-PC 1.2
- Copyright (c) 1988, by Oakland Group, Inc.
- ALL RIGHTS RESERVED.
-
- Revision History:
- -----------------
- 9/09/88 jmd Fixed kRead and kCheck
- 10/19/88 ted Changed how dopause works, extracted dig_SubHsecs
- 11/22/88 ted Merged key & hard structures, added ReadEvent.
- 12/12/88 ted Merged CheckKey and CheckMouse into CheckEvent.
- 12/14/88 ted Changed CheckEvent to unsigned so it can return MOU_EVENT.
- 2/07/89 Ted added timeout wait arg to hCheckEvent function.
- 2/09/89 Ted added setmousebox implementation
- 2/28/89 ted moved Control, CheckEvent and ReadEvent out to pcevent.c
- 3/26/89 ted Added wait feature for CheckEvent.
- 4/04/89 ted Added mouse de-initialization feature.
- 4/22/89 ted moved Control, CheckEvent and ReadEvent back in.
- 7/10/89 ted moved pchdatastruc back in here (it was in its own file).
- 7/12/89 ted Added OSTATIC's and '_func' macros.
- 8/11/89 ted Added SETMOUSESHAPE.
- 8/24/89 ted Added GETMOUSESHAPE.
- 8/31/89 ted Added CLEAREVENTS.
- 8/31/89 jmd Added call to disp_EvCheck
- 9/12/89 ted Removed ref. to pcdata in mouseshape that messed up FAMILYAPI.
-
- 11/05/89 ted Added DOS_ZEROSEG macro.
- 11/08/89 ted Initialized xdata and xdatasize pchdata elements.
- 12/08/89 ted Added eventchecked = TRUE in ReadEvent.
- 2/22/90 ted Got rid of static dopause function.
- 2/22/90 ted Made pc_hControl public.
- 2/24/90 ted Indirected getmoupos through an fptr so MGR can share it.
- 2/28/90 ted Added desqview detect and pauses.
- 3/28/90 jmd ansi-fied
- 5/11/90 jmd converted to new scancode scheme
- 6/22/90 ted added "void"s to no-parameter functions per ansii.
- 7/25/90 jmd added test for numlock state to pc_CvtScancode
- 9/06/90 jmd removed pc_CvtScancode
- 9/09/90 ted Added extended BIOS kb-int support.
- 10/11/90 ted Added ctrl-break KEY_SIGNAL return option.
- */
-
- #include "pcpriv.h"
- #include "scancode.h" /* for mouse pseudo-scancodes */
- #include "dpref.h" /* for dpref_GetPcCbrk() */
-
- OGLOBAL pchdata_struct pchdatastruc;
-
- OSTATIC dig_hCheckEvent_func (pc_hCheckEvent);
- OSTATIC dig_hReadEvent_func (pc_hReadEvent);
- OSTATIC dig_hGetShift_func (pc_hGetShift);
- OSTATIC dig_hPause_func (pc_hPause);
- OSTATIC dig_hSound_func (pc_hSound);
-
- OSTATIC getmoupos_func (getmoupos);
-
- OSTATIC int DIGPRIV mousecheck(void);
- OSTATIC boolean DIGPRIV setmousebox(opbox *mbox);
- OSTATIC boolean DIGPRIV setmouseshape(mouseshape_struct *mshape);
- OSTATIC boolean DIGPRIV makemasks(mouseshape_struct *mshape, unsigned short *msmask);
- OSTATIC byte DIGPRIV pc_xkbtest(void);
-
- #ifdef OAK_DESQVIEW
- # define dv_pause() ((pchdata->desqview) ? (regs.x.ax = DVC_PAUSE, oakint86(DV_INT, ®s)) : 0)
- # define dvregs OREGS regs
- #else
- # define dvregs
- # define dv_pause()
- #endif
- /* -------------------------------------------------------------------------- */
-
- void pc_hOpen(dig_struct *digp)
- /*
- Init hardware pointers.
- Note: not declared digpriv so it can be called from os2hard, which may be
- in a different segment.
- */
- {
- digp->hCheckEvent = pc_hCheckEvent;
- digp->hReadEvent = pc_hReadEvent;
- digp->hGetShift = pc_hGetShift;
- digp->hTimer = pc_hTimer;
- digp->hPause = pc_hPause;
- digp->hSound = pc_hSound;
- digp->hControl = pc_hControl;
- }
- /* -------------------------------------------------------------------------- */
-
- static int pc_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.
- */
- {
- OREGS regs;
- unsigned itime;
-
- if (wait != 0 && wait != (unsigned) -1) {
- itime = pc_hTimer();
- }
- for (;;) { /* loop until timeout */
- #ifdef OAK_CBRK
- /* If control-break was detected, return KEY_SIGNAL */
- if (pc_checkcbrk(FALSE)) {
- return(KEY_SIGNAL);
- }
- #endif
- regs.h.ah = (byte)KBINT_STATUS + pchdata->xkbint;
- if (oakint86(BIOS_KBINT, ®s) & PC_ZFLAG) { /* no key ready */
- if (pchdata->ismouse) {
- if ((*pchdata->getmoupos)(NULL)) { /* mouse ready */
- pchdata->eventchecked = TRUE;
- return(HARD_MEV); /* no key, but mouse ready */
- }
- }
- /* else no mouse or key ready */
- }
- else { /* key ready */
- pchdata->eventchecked = TRUE;
- return((int) regs.x.ax);
- }
- /* No key or mouse ready - see if wait duration has expired */
- if (wait == 0) {
- break;
- }
- else if (wait != (unsigned) -1) {
- if (dig_SubHsecs(itime, pc_hTimer()) > wait) {
- break; /* break out of the loop and give up if time out */
- }
- }
- dv_pause(); /* Give up time slice if DESQview's running */
- }
- return(KEY_NONE);
- }
- /* -------------------------------------------------------------------------- */
-
- static int pc_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.
- */
- {
- OREGS regs;
-
- for (;;) {
-
- #ifdef OAK_CBRK
- /* If control-break was detected, return KEY_SIGNAL */
- if (pc_checkcbrk(TRUE)) {
- return(KEY_SIGNAL);
- }
- #endif
- /* Return when keyboard character is available */
- regs.h.ah = (byte)KBINT_STATUS + pchdata->xkbint;
- if (!(oakint86(BIOS_KBINT, ®s) & PC_ZFLAG)) {
- regs.h.ah = (byte)KBINT_READ + pchdata->xkbint;
- oakint86(BIOS_KBINT, ®s);
- pchdata->eventchecked = FALSE;
-
- if (pchdata->xkbint != 0) {
- switch(regs.x.ax) {
-
- /* The "Grey-Enter" key */
- case 0xE00D:
- regs.x.ax = 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):
- regs.x.ax &= 0xFF00;
- break;
- }
- }
- return((int) regs.x.ax);
- }
- if (mouposp != NULL && pchdata->ismouse) {
- if ((*pchdata->getmoupos)(NULL)) { /* mouse ready */
- pchdata->eventchecked = TRUE;
- (*pchdata->getmoupos)(mouposp);
-
- if (pchdata->eventchecked) {
- pchdata->eventchecked = FALSE;
- /* If we promised a mouse return but the mouse was deinitted */
- /* before we could return it, just return a KEY_NONE event. */
- if (!pchdata->ismouse) {
- return(KEY_NONE);
- }
- }
- return(HARD_MEV);
- }
- }
- dv_pause(); /* Give up time slice if DESQview's running */
- }
- }
- /* -------------------------------------------------------------------------- */
-
- int pc_hControl(dig_hcmsg msg, VOID *indata, VOID *outdata)
- {
- /* static default cursor masks - needed in case of first 'getcursorshape' */
- static bmap_struct(16,16) arrowimage = {
- 16, 16,
- 0x00,0x00, 0x40,0x00, 0x60,0x00, 0x70,0x00,
- 0x78,0x00, 0x7C,0x00, 0x7E,0x00, 0x7F,0x00,
- 0x7F,0x80, 0x7C,0x00, 0x6C,0x00, 0x46,0x00,
- 0x06,0x00, 0x03,0x00, 0x03,0x00, 0x00,0x00
- };
- static bmap_struct(16,16) arrowmask = {
- 16, 16,
- 0x3F,0xFF, 0x1F,0xFF, 0x0F,0xFF, 0x07,0xFF,
- 0x03,0xFF, 0x01,0xFF, 0x00,0xFF, 0x00,0x7F,
- 0x00,0x3F, 0x00,0x1F, 0x01,0xFF, 0x10,0xFF,
- 0x30,0xFF, 0xF8,0x7F, 0xF8,0x7F, 0xFC,0x7F
- };
- static mouseshape_struct defmouseshape = {
- (bmap_type)(&arrowimage), (bmap_type)(&arrowmask), 0, 0, 0x77FF, 0x7700
- };
-
- switch (msg) {
- case HC_OPEN:
- pchdata->soundon = TRUE;
- pchdata->ismouse = FALSE;
- pchdata->xkbint = pc_xkbtest();
- pchdata->curmouseshape = &defmouseshape; /* not in initmouse so mgr can share it */
- pchdata->xdata = NULL; /* Terminate the data block chain for now */
- pchdata->xdatasize = 0;
- /* rest of mouse vars handled in HC_INITMOUSE method */
- #ifdef OAK_DESQVIEW
- pchdata->desqview = pch_IsDESQview();
- #endif
- #ifdef OAK_CBRK
- if (dp_GetPcCbrk()) {
- pc_catchcbrk();
- }
- #endif
- break;
-
- #ifdef OAK_CBRK
- case HC_CLOSE:
- pc_restorecbrk();
- break;
- #endif
-
- case HC_INITMOUSE:
- if ((pchdata->ismouse = mousecheck()) != 0) { /* remember if mouse found */
- pchdata->xlastmou = pchdata->ylastmou = 0;
- pchdata->blastmou = 0;
- pchdata->eventchecked = FALSE;
- pchdata->getmoupos = getmoupos;
- }
- /* no break; */
- case HC_ISMOUSEON:
- return((int)pchdata->ismouse);
-
- case HC_DEINITMOUSE:
- pchdata->ismouse = FALSE;
- break;
-
- case HC_SETMOUSEBOX:
- if (pchdata->ismouse) {
- return((int)setmousebox((opbox *) indata));
- }
- break;
-
- case HC_SETMOUSESHAPE:
- /*
- Note: any bmaps passed here must not be freed as long as someone
- might call 'getmouseshape' and then 'setmouseshape' again with the
- gotten shape struct and its pointers to your old bmaps.
- */
- if (pchdata->ismouse) {
- if (setmouseshape((mouseshape_struct *) indata)) {
- memmove((VOID *)pchdata->curmouseshape, indata, sizeof(mouseshape_struct));
- break;
- }
- }
- return(FALSE);
-
- case HC_GETMOUSESHAPE:
- memmove(outdata, (VOID *)pchdata->curmouseshape, sizeof(mouseshape_struct));
- break;
-
- case HC_SETSOUNDON:
- pchdata->soundon = TRUE;
- break;
- case HC_SETSOUNDOFF:
- pchdata->soundon = FALSE;
- break;
- case HC_GETSOUNDON:
- return((int)pchdata->soundon);
- case HC_CLEAREVENTS:
- { /* Call ReadEvent until nothing in kb buffer */
- moupos_struct mouposdum;
-
- if (disp_EvCheck()) {
- while (pc_hCheckEvent(0) != KEY_NONE) {
- pc_hReadEvent(&mouposdum);
- }
- }
- break;
- }
- }
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- static unsigned pc_hGetShift(void)
- /*
- 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
- */
- {
- OREGS regs;
-
- regs.h.ah = (byte)KBINT_GETSHIFT + pchdata->xkbint;
- oakint86(BIOS_KBINT, ®s);
- return((unsigned)regs.h.al);
- }
- /* -------------------------------------------------------------------------- */
-
- unsigned pc_hTimer(void)
- /*
- 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.
- */
- {
- OREGS regs;
- unsigned hsecs, secs, mins;
-
- regs.h.ah = DOS_GETTIME;
- oakint86(DOS_INT, ®s);
-
- hsecs = regs.h.dl;
- secs = regs.h.dh;
- mins = regs.h.cl % 10;
-
- return((unsigned)(hsecs + secs * 100 + mins * 6000));
- }
- /* -------------------------------------------------------------------------- */
-
- static void pc_hPause(unsigned duration)
- /*
- This function uses the system clock and causes a delay
- of the specified duration.
- 'duration' is duration in hundredths of secs
- */
- {
- unsigned tstart;
- dvregs;
-
- tstart = pc_hTimer();
- while (dig_SubHsecs(tstart, pc_hTimer()) < duration) {
- dv_pause(); /* Give up time slice if DESQview's running */
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void pc_hSound(unsigned pitch, unsigned duration)
- {
- if (pchdata->soundon) {
- outp( SPKR_CNTRL2, SPKR_MODE3); /* put timer 2 into mode 3 */
- outp( SPKR_TIMER2, pitch & 0x00FF); /* wavelength for timer 2 */
- outp( SPKR_TIMER2, pitch / 0x00FF);
-
- outp(DOS_PORTB, inp(DOS_PORTB) | 0x03); /* turn on speaker */
- pc_hPause(duration); /* wait... */
- outp(DOS_PORTB, inp(DOS_PORTB) & 0xFC); /* turn off speaker */
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static int DIGPRIV mousecheck(void)
- /*
- Return 1 for mouse, 0 for not installed
- */
- {
- OREGS regs;
- long mousevec;
-
- /* Peek at mouse interrupt vector to see if it is null */
- ram_segtomem(DOS_ZEROSEG, 4 * BIOS_MOUSEINT, (byte *) &mousevec, 4);
- if (mousevec == 0) {
- return 0; /* if no seg or offset return 0 */
- }
-
- /* Try the mouse interupt - if it leaves ax alone it's not real */
- regs.x.ax = BMOU_INIT;
- oakint86(BIOS_MOUSEINT, ®s);
- return(regs.x.ax != BMOU_INIT);
- }
- /* -------------------------------------------------------------------------- */
-
- static boolean DIGPRIV getmoupos(moupos_struct *mouposp)
- /*
- If mouposp != NULL, wait for a mouse event and return it in mouposp.
- Otherwise, don't wait and return whether an event is ready or not.
- */
- {
- opcoord mx, my;
- unsigned buttons;
- boolean motion;
- OREGS regs;
-
- if (mouposp == NULL) { /* CheckEvent call */
- if (pchdata->eventchecked) {
- return(TRUE);
- }
- }
- for (;;) {
- regs.x.ax = BMOU_GETPOS;
- oakint86(BIOS_MOUSEINT, ®s);
-
- mx = regs.x.cx / pchdata->xmouscale;
- my = regs.x.dx / pchdata->ymouscale;
- buttons = regs.x.bx;
-
- motion = (mx != pchdata->xlastmou || my != pchdata->ylastmou);
-
- if (!motion && pchdata->blastmou == buttons) {
- /* If no change in mouse position or buttons: try again */
- if (mouposp == NULL) { /* CheckEvent call */
- return(FALSE); /* Return if this is just a CheckMouse */
- }
- /* If we previously reported a change, return an */
- /* event now, even though the change went away again */
- /* Otherwise, go around for another mouse read */
- if (!pchdata->eventchecked) {
- continue;
- }
- else {
- motion = TRUE; /* Fudge it: report motion anyway */
- }
- }
- else { /* Motion or button change */
- if (mouposp == NULL) { /* CheckEvent call */
- return(TRUE);
- }
- }
- pchdata->xlastmou = mx;
- pchdata->ylastmou = my;
- pchdata->blastmou = buttons;
-
- mouposp->x = mx;
- mouposp->y = my;
- mouposp->event = 0;
- if (buttons & 0x01) { /* Left button */
- if (motion) {
- mouposp->event |= MEV_BUT1MOVE;
- }
- else {
- mouposp->event |= MEV_BUT1;
- }
- }
- if (buttons & 0x02) { /* Right button */
- if (motion) {
- mouposp->event |= MEV_BUT2MOVE;
- }
- else {
- mouposp->event |= MEV_BUT2;
- }
- }
- if (buttons & 0x04) { /* Middle button */
- if (motion) {
- mouposp->event |= MEV_BUT3MOVE;
- }
- else {
- mouposp->event |= MEV_BUT3;
- }
- }
- if (motion && mouposp->event == 0) {
- mouposp->event |= MEV_MOVE;
- }
- break;
- }
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- static boolean DIGPRIV setmousebox(opbox *mbox)
- {
- OREGS regs;
-
- regs.x.ax = BMOU_XRANGE;
- regs.x.cx = mbox->xmin * pchdata->xmouscale;
- regs.x.dx = (mbox->xmax-1) * pchdata->xmouscale;
- oakint86(BIOS_MOUSEINT, ®s);
-
- regs.x.ax = BMOU_YRANGE;
- regs.x.cx = mbox->ymin * pchdata->ymouscale;
- regs.x.dx = (mbox->ymax-1) * pchdata->ymouscale;
- oakint86(BIOS_MOUSEINT, ®s);
-
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- static boolean DIGPRIV setmouseshape(mouseshape_struct *mshape)
- /*
- Return TRUE if graphics cursor shape was set, FALSE if not. Text cursor is
- always set in any case.
- */
- {
- OREGS regs;
- unsigned short msmask[2*16];
-
- if (ofont_GetWidth(disp_GetDefFont()) == 1) { /* text mode */
- if (mshape->tsmask == 0 && mshape->tcmask == 0) {
- return(FALSE); /* Fail if 0 cursor and mask given */
- }
- /* Set software text mode mouse cursor in text mode */
- regs.x.ax = BMOU_TMSHAPE;
- regs.x.bx = 0;
- regs.x.cx = mshape->tsmask;
- regs.x.dx = mshape->tcmask;
- oakint86(BIOS_MOUSEINT, ®s);
- }
- else {
- /* Convert given pmaps to cursor shape and mask bit arrays */
- if (!makemasks(mshape, msmask)) {
- return(FALSE);
- }
- /* Set graphics mode cursor shape and mask */
- regs.x.ax = BMOU_MSHAPE;
- regs.x.bx = mshape->xhot * pchdata->xmouscale;
- regs.x.cx = mshape->yhot * pchdata->ymouscale;
- regs.a.esdx = msmask;
- oakint86es(BIOS_MOUSEINT, ®s, sizeof(msmask));
- }
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- static boolean DIGPRIV makemasks(mouseshape_struct *mshape, unsigned short *msmask)
- {
- odim i;
- byte *inb, *outb;
-
- if (mshape->mask == NULL || mshape->image == NULL) {
- return(FALSE);
- }
- outb = (byte *)msmask;
- for (i = 0; i < 16; i++) {
- if (i < mshape->mask->height) {
- inb = bmap_GetLine(mshape->mask, i);
- *(outb++) = *(inb+1); *(outb++) = *inb;
- }
- else {
- *(outb++) = 0xFF; *(outb++) = 0xFF;
- }
- }
- for (i = 0; i < 16; i++) {
- if (i < mshape->image->height) {
- inb = bmap_GetLine(mshape->image, i);
- *(outb++) = *(inb+1); *(outb++) = *inb;
- }
- else {
- *(outb++) = 0x00; *(outb++) = 0x00;
- }
- }
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- static byte DIGPRIV pc_xkbtest(void)
- /* Detect whether extended BIOS KBINT funcs are available.
- */
- {
- OREGS regs;
- byte kbstatus, xkboffs;
-
- xkboffs = 0;
-
- /* Get kb status byte from BIOS data area */
- ram_segtomem(0x40, 0x17, &kbstatus, 1);
-
- /* Try to get kb shift state from extended BIOS call */
- regs.h.ah = KBINT_GETSHIFT + 0x10;
- oakint86(BIOS_KBINT, ®s);
-
- /* If same, change it in data area and see if call returns the new value. */
- if (regs.h.al == kbstatus) {
- /* Change kb status byte in BIOS data area */
- kbstatus ^= 0x10; /* Twiddle scroll lock bit in shift state */
- ram_memtoseg(0x40, 0x17, &kbstatus, 1);
-
- /* Try again */
- regs.h.ah = KBINT_GETSHIFT + 0x10;
- oakint86(BIOS_KBINT, ®s);
- if (regs.h.al == kbstatus) {
- xkboffs = 0x10;
- }
- /* Restore kb status byte in BIOS data area */
- kbstatus ^= 0x10; /* Un-twiddle scroll lock bit in shift state */
- ram_memtoseg(0x40, 0x17, &kbstatus, 1);
-
- /* Do this read again so BIOS can restore keyboard scroll lock light */
- regs.h.ah = KBINT_GETSHIFT + 0x10;
- oakint86(BIOS_KBINT, ®s);
- }
- return(xkboffs);
- }
- /* -------------------------------------------------------------------------- */
- #ifdef OAK_DESQVIEW
- boolean DIGPRIV pch_IsDESQview(void)
- {
- OREGS regs;
- static char badvals[] = "DESQ";
-
- regs.x.ax = DOS_DVPRESENT;
- regs.x.bx = 0;
- regs.x.cx = *((unsigned short *) &badvals[0]);
- regs.x.dx = *((unsigned short *) &badvals[2]);
- oakint86(DOS_INT, ®s);
- return(regs.x.bx != 0);
- }
- #endif
- /* -------------------------------------------------------------------------- */
-
-