This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
fte/portdos.c
Gered 43d7eb4f73 properly hook up ScreenSizeX/Y global options & fix related mouse issues
note that 80x43 text mode is not currently working. if the int 10h can
be adjusted to set this mode correctly, the mouse fixes should all work
properly with it too ...
2019-03-31 17:13:55 -04:00

1037 lines
25 KiB
C

/*
* portdos.c: Portable calls for DOS
* ==================================
* (C)1996 by F.Jalvingh; Public domain.
* (C)1997 by Markus F.X.J. Oberhumer; Public domain.
*
* $Header: /cvsroot/fte/fte/src/portdos.c,v 1.1.1.1 2000/01/30 17:23:45 captnmark Exp $
*
* $Log: portdos.c,v $
* Revision 1.1.1.1 2000/01/30 17:23:45 captnmark
* initial import
*
*/
#include "port.h"
#include <assert.h>
#include <string.h>
#if defined(DOS) || defined(DOSP32)
#include <dos.h>
#if defined(__DJGPP__)
#include <pc.h>
#include <dpmi.h>
#include <go32.h>
#include <sys/movedata.h>
#define inp inportb
#define outp outportb
#endif
struct plScnInfo
{
int s_inited; // T when current status is known.
int s_wid, s_hig; // Current screen size
enum ePlScnType s_type; // Current screen type,
boolean s_ismono; // T when black- and white.
boolean s_isbright;
//** Cursor info,
boolean s_curinit;
boolean s_curon; // T when cursor is visible
int s_cur_x, s_cur_y; // Current cursor position,
int s_curstart, // Start of cursor blob,
s_curend; // End of blob;
UWORD s_iobase;
#if defined(__DOS4G__) || defined(__DJGPP__)
ULONG s_pbase; // Physical base address of video memory
#else
UWORD s_pseg; // Segment of video memory
#endif
};
/*--------------------------------------------------------------------------*/
/* STATIC GLOBALS.. */
/*--------------------------------------------------------------------------*/
static struct plScnInfo plScnI;
static void plScnInit(void);
/*
* between() returns a # between bounds.
*/
static int between(int x, int low, int hig)
{
if(x < low)
return low;
else if(x > hig)
return hig;
return x;
}
/****************************************************************************/
/* */
/* CODING: Screen type determination for DOS.. */
/* */
/****************************************************************************/
/*
* This is very important for the working of the DOS interface. It determines
* the screen type, and derives some stuff from that:
* - screen base address (i/o port)
* - video memory address (for direct I/O to the screen).
*/
/*
* VgaMonoMonitor() returns T if the monitor attached to a VGA adaptor is a
* monochrome monitor.
*/
static boolean VgaMonoMonitor(void)
{
union dosxReg r;
memset(&r, 0, sizeof(r)); // Clear all unused regs,
r.w.ax = 0x1a00; // Function 1A subfunction 00
dosxIntr(0x10, &r); // Call VGA BIOS,
if(r.h.al != 0x1a) return FALSE; // Assume color if call not supported,
if(r.h.bl == 0x01 || r.h.bl == 0x05 || r.h.bl == 0x07 ||r.h.bl == 0x0B)
return TRUE; // These types are MONO,
else
return FALSE;
}
/*
* biosisVGA() returns TRUE if a VGA-card is found.
*/
static boolean biosisVGA(void)
{
boolean isvga;
outp(0x3ce, 8); // Bit mask register,
outp(0x3cf, 1); // Test mask, (1)
outp(0x3ce, 8); // Bit mask register again,
if(inp(0x3cf) == 1) // Can we read the same value?
isvga = TRUE; // Yes -> is VGA!
else
isvga = FALSE;
outp(0x3ce, 8); // Bit mask register last time,
outp(0x3cf, 0xff); // All on (default value)
return isvga;
}
/*
* biosisEGA() returns TRUE if the card is an EGA card (or a VGA card).
*/
static boolean biosisEGA(void)
{
union dosxReg r;
UBYTE ega;
//** Get EGA BIOS byte.
dosxMemRead(&ega, 0x00400087ul, 1); // Read EGA BIOS sysvar,
if(! (ega & 0x08)) // There's an active EGA in the system!
{
//** EGA is active: do EGA bios call..
memset(&r, 0, sizeof(r));
r.h.ah = 0x12; // EGA BIOS Get info,
r.h.bl = 0x10; // Get info
r.h.bh = 0xff; // Inpossible return value,
dosxIntr(0x10, &r); // Call EGA BIOS,
if(r.h.bh != 0xff) // EGA found?
return TRUE; // Yes!
}
return FALSE;
}
/*
* biosisMono() returns TRUE if the BIOS is currently in MONO mode. This
* is the mode selected with the MODE co80 or MODE MONO command. For EGA and
* VGA cards this mode doesn't tell a thing about the MONITOR attached!!!
*/
static boolean biosisMono(void)
{
union dosxReg r;
//** Call the BIOS get video mode
memset(&r, 0, sizeof(r));
r.w.ax = 0x0f00;
dosxIntr(0x10, &r);
r.h.al &= 0x7f; // Mask out DONT-CLEAR bit,
if(r.h.al == 7) return TRUE; // Monochrome screen
if(r.h.al == 2 || r.h.al == 3) return FALSE;// Color screen,
return TRUE; // All else: return MONO
}
/*
* getPrimaryType() returns the primary card type.
*/
static enum ePlScnType getPrimaryType()
{
if(biosisEGA()) // Minimal EGA?
return biosisVGA() ? plsctVGA : plsctEGA;
return biosisMono() ? plsctMono : plsctCGA;
}
/*
* getType() determines the screen type.
*/
static void getType(void)
{
enum ePlScnType sct;
sct = getPrimaryType(); // Get primary screen type;
switch(sct)
{
default: plScnI.s_ismono = biosisMono(); break;
case plsctVGA: plScnI.s_ismono = VgaMonoMonitor(); break;
}
//** Determine hardware addresses..
#if defined(__DJGPP__)
plScnI.s_pbase = ScreenPrimary;
#elif defined(__DOS4G__)
plScnI.s_pbase = plScnI.s_ismono ? 0xb0000 : 0xb8000;
#elif defined(__MSDOS__)
plScnI.s_pseg = plScnI.s_ismono ? 0xb000 : 0xb800;
#endif
plScnI.s_iobase = plScnI.s_ismono ? 0x3b4 : 0x3d4;
plScnI.s_type = sct;
}
/****************************************************************************/
/* */
/* CODING: Screen - Other base helper calls.. */
/* */
/****************************************************************************/
/*
* getSize() inquires the BIOS about the screen size.
*/
static void getSize(void)
{
union dosxReg r;
//** Get the current width of the screen,
memset(&r, 0, sizeof(r));
r.w.ax = 0x0f00; // Get current video mode,
dosxIntr(0x10, &r); // Video BIOS
plScnI.s_wid = between(r.h.ah, 80, 256);
if(plScnI.s_type < plsctEGA) // For all lower as EGA use 25 height
plScnI.s_hig = 25;
else
{
r.w.ax = 0x1130; // Get FONT information,
r.w.bx = 0;
dosxIntr(0x10, &r);
r.h.dl += 1; // For some reason it reports 1 too small,
plScnI.s_hig = between(r.h.dl, 25, 128);
}
}
/*
* getCurInfo() gets the current cursor info: position and shape, visibility.
*/
static void getCurInfo(void)
{
union dosxReg r;
//** Ask the BIOS for the current cursor shape,
memset(&r, 0, sizeof(r));
r.w.ax = 0x0300; // Get cursor shape,
r.w.bx = 0; // Page 0
dosxIntr(0x10, &r);
plScnI.s_cur_x = r.h.dl;
plScnI.s_cur_y = r.h.dh;
plScnI.s_curstart = r.h.ch;
plScnI.s_curend = r.h.cl;
if(! plScnI.s_curinit) // Cursor state not initialized?
{
plScnI.s_curon = TRUE; // Default to cursor ON,
plScnI.s_curinit= TRUE;
}
}
/*
* plScnSetSize() sets the screen textmode to correspond to the specified
* dimensions. note that it only actually supports standard DOS textmodes
* 80x25, 80x43 and 80x50
*/
void plScnSetSize(int xSize, int ySize) {
union dosxReg r;
// set text mode
memset(&r, 0, sizeof(r));
r.w.ax = 0x0003;
dosxIntr(0x10, &r);
memset(&r, 0, sizeof(r));
if (xSize == 80 && ySize == 25) {
// the previous int 10h call already set 80x25. do nothing here
} else if (xSize == 80 && ySize == 43) {
// TODO: doesn't work? what is the correct way to set 8x14 font?
// i know my video card supports this as i can use 80x43 in other
// applications ... will revisit this
r.w.ax = 0x1122;
dosxIntr(0x10, &r);
} else if (xSize == 80 && ySize == 50) {
r.w.ax = 0x1112;
dosxIntr(0x10, &r);
}
//plScnI.s_inited = FALSE;
getType();
getSize();
getCurInfo();
}
/*
* plScnInit() is called to get most of the info required to do screen I/O.
* Depending on the "inited" flag it will get the current screen size, the
* mode, cursor shape and visibility etc.
*/
static void plScnInit(void)
{
if(plScnI.s_inited) return; // Exit immediately if already inited,
getType(); // ALWAYS get TYPE 1st!
getSize(); // Get current mode (screen size)
getCurInfo();
plScnI.s_inited = TRUE; // Don't init again.
}
/*
* plScnSetFlash() is called to SET/CLEAR the flash/bright indicator.
*/
void plScnSetFlash(boolean on)
{
union dosxReg r;
memset(&r, 0, sizeof(r));
r.w.ax = 0x1003;
r.w.bx = on ? 1 : 0; // Set HILITE or FLASH mode.
dosxIntr(0x10, &r);
plScnI.s_isbright = !on; // Set ISBRIGHT mode flag.
}
#if defined(__DJGPP__)
static void ScreenSetCursorShape(int shape)
{
__dpmi_regs reg;
reg.h.ah = 0x01;
reg.h.al = ScreenMode();
reg.x.cx = shape & 0x7f1f;
__dpmi_int(0x10, &reg);
}
#else
/*
* cardOut()..
*/
static void cardOut(int port, int val)
{
outp(plScnI.s_iobase, port);
outp(plScnI.s_iobase + 1, val);
}
#endif
/*
* plScnCursorOn() switches the cursor ON or OFF.
*/
void plScnCursorOn(boolean on)
{
UWORD v;
plScnInit();
plScnI.s_curon = on;
v = (UWORD) ( ((plScnI.s_curstart & 0xff) << 8) | (plScnI.s_curend & 0xff));
if(! on) v |= 0x2000; // Disable if required..
#if defined(__DJGPP__)
ScreenSetCursorShape(v);
#else
dosxDisable();
cardOut(10, v >> 8);
cardOut(11, v & 0xff);
if(! on)
{
cardOut(14, 20);
cardOut(15, 0);
}
dosxEnable();
#endif
}
/*
* plScnCursorShape() sets the cursor shape.
*/
void plScnCursorShape(int start, int end)
{
plScnInit();
plScnI.s_curstart = start;
plScnI.s_curend = end;
plScnCursorOn(plScnI.s_curon); // Switch cursor on/off; sets shape.
}
/*
* plScnCursorShapeGet()
*/
void plScnCursorShapeGet(int* sp, int* ep)
{
getCurInfo();
*sp = plScnI.s_curstart;
*ep = plScnI.s_curend;
}
/*
* plScnCursorPos() sets the cursor's position.
*/
void plScnCursorPos(int x, int y)
{
#if defined(__DJGPP__)
ScreenSetCursor(y,x);
#else
UWORD soff;
plScnInit();
soff= (UWORD) (y * plScnI.s_wid + x);
dosxDisable();
cardOut(14, (soff >> 8));
cardOut(15, soff & 0xff);
dosxEnable();
plScnI.s_cur_x = x;
plScnI.s_cur_y = y;
#endif
}
/*
* plScnCursorPosGet()
*/
void plScnCursorPosGet(int* xp, int* yp)
{
// getCurInfo();
*xp = plScnI.s_cur_x;
*yp = plScnI.s_cur_y;
}
/****************************************************************************/
/* */
/* DJGPP implementation. */
/* */
/****************************************************************************/
#if defined(__DJGPP__) // Protected Mode
void plScnWrite(unsigned x, unsigned y, unsigned short* buf, unsigned nch)
{
plScnInit();
movedata(_my_ds(), (unsigned) buf, _dos_ds, plScnI.s_pbase+(((y * plScnI.s_wid) + x)*2), nch*2);
}
void plScnRead(unsigned x, unsigned y, unsigned short* buf, unsigned nch)
{
plScnInit();
movedata(_dos_ds, plScnI.s_pbase+((y * plScnI.s_wid) + x)*2, _my_ds(), (unsigned) buf, nch*2);
}
static void moveVm(unsigned to, unsigned from, unsigned len)
{
movedata(_dos_ds, plScnI.s_pbase + from*2, _dos_ds, plScnI.s_pbase + to*2, len*2);
}
/****************************************************************************/
/* */
/* CODING: Dos4GW implementation.. */
/* */
/****************************************************************************/
#elif defined(__DOS4G__)
void plScnWrite(unsigned x, unsigned y, unsigned short* buf, unsigned nch)
{
plScnInit();
memcpy((UBYTE*) plScnI.s_pbase+(((y * plScnI.s_wid) + x)*2), buf, nch<<1);
}
void plScnRead(unsigned x, unsigned y, unsigned short* buf, unsigned nch)
{
plScnInit();
memcpy(buf, (UBYTE*)plScnI.s_pbase+(((y * plScnI.s_wid) + x)*2), nch<<1);
}
static void moveVm(unsigned to, unsigned from, unsigned len)
{
memcpy((UBYTE*) plScnI.s_pbase+to*2, (UBYTE*) plScnI.s_pbase+from*2, len*2);
}
/****************************************************************************/
/* */
/* REAL MODE implementation. */
/* */
/****************************************************************************/
#elif defined(__MSDOS__) // REAL Mode
#include <dos.h>
void plScnWrite(unsigned x, unsigned y, unsigned short* buf, unsigned nch)
{
plScnInit();
memcpy(MK_FP(plScnI.s_pseg, ((y * plScnI.s_wid) + x)*2), buf, nch<<1);
}
void plScnRead(unsigned x, unsigned y, unsigned short* buf, unsigned nch)
{
plScnInit();
memcpy(buf, MK_FP(plScnI.s_pseg, ((y * plScnI.s_wid) + x)*2), nch<<1);
}
static void moveVm(unsigned to, unsigned from, unsigned len)
{
memcpy(MK_FP(plScnI.s_pseg, to*2), MK_FP(plScnI.s_pseg, from*2), len << 1);
}
#endif
/****************************************************************************/
/* */
/* CODING: Screen - Shared Base functions. */
/* */
/****************************************************************************/
/*
* plScnWidth() returns the width of the screen.
*/
int plScnWidth(void)
{
plScnInit();
return plScnI.s_wid;
}
/*
* plScnHeight() returns the current height of the screen.
*/
int plScnHeight(void)
{
plScnInit();
return plScnI.s_hig;
}
/*
* plScnType() returns the current screen type.
*/
enum ePlScnType plScnType(void)
{
plScnInit();
return plScnI.s_type;
}
/*
* plScnIsMono() returns T if the screen is a MONO screen.
*/
boolean plScnIsMono(void)
{
plScnInit();
return plScnI.s_ismono;
}
/****************************************************************************/
/* */
/* CODING: Screen - Set and Scroll functions. */
/* */
/****************************************************************************/
#define BUFSZ 150
/*
* plScnSetCell()
*/
void plScnSetCell(unsigned x, unsigned y, unsigned wid, unsigned hig, UWORD cell)
{
UWORD buf[BUFSZ], *p, *pend;
unsigned len, lleft, px;
//** Fill buffer,
len = wid;
if(len > BUFSZ) len = BUFSZ;
p = buf;
pend= p + len;
while(p < pend) *p++ = cell; // Set as much as needed,
//** For all lines,
while(hig-- > 0)
{
//** For the current line,
lleft = wid;
px = x;
while(lleft > 0)
{
len = lleft; // Determine #bytes from buf to use,
if(len > BUFSZ) len = BUFSZ;
plScnWrite(px, y, buf, len);
px += len;
lleft -= len;
}
y++;
}
}
/*
* plScnScrollUp() scrolls the region specified UP.
*/
void plScnScrollUp(int x, int y, int ex, int ey, int nlines, UWORD fill)
{
int from, to;
//** Calculate the from and to offsets;
to = y*plScnI.s_wid + x; // TO is top-of-window,
from= to + nlines*plScnI.s_wid; // FROM is #lines further down,
while(y < ey-nlines)
{
moveVm(to, from, (ex-x));
to += plScnI.s_wid;
from+= plScnI.s_wid;
y++;
}
plScnSetCell(x, y, (ex-x), nlines, fill); // Clear bottom.
}
/*
* plScnScrollDown() scrolls the region DOWN.
*/
void plScnScrollDown(int x, int y, int ex, int ey, int nlines, UWORD fill)
{
int from, to, len;
//** Scrolling down: move from bottom to top;
to = ey * plScnI.s_wid + x;
from= to - plScnI.s_wid*nlines;
while(ey > y)
{
ey--; // Back one line;
from -= plScnI.s_wid;
to -= plScnI.s_wid;
moveVm(to, from, (ex-x));
}
plScnSetCell(x, y, (ex-x), nlines, fill);
}
/****************************************************************************/
/* */
/* CODING: Keyboard interface for DOS and DOS extender(s).. */
/* */
/****************************************************************************/
/*
* Memo to self: I've changed the "get character" request code from the 00h
* and 01h to 10h and 11h (extended keyboard). I should inquire the BIOS about
* the availability of these calls, but preliminary tests show that most
* BIOSes lie about the keyboard type, or do not implement the required
* int15 calls proper.
* Should work for most modern machines!
*/
/*
* kbHasChar() returns T if a character is present in the keyboard buffer. It
* is checked by comparing the keyboard queue ptrs in the bios segment.
*/
static boolean kbHasChar(void)
{
UWORD p1, p2;
union dosxReg r;
#if 0 // Switched off for extended kbd support.
dosxMemRead(&p1, 0x0040001aul, 2); // Get 1st keybd pointer,
dosxMemRead(&p2, 0x0040001cul, 2); // And 2nd,
if(p1 == p2) return FALSE; // Exit if not ok;
#endif
//** Now ask if a real code is available by non-destructive qry of bios.
memset(&r, 0, sizeof(r)); // Clear unused registers,
r.w.ax = 0x1100; // !! Was 0x0100
dosxIntr(0x16, &r); // Call keyboard shit.
if(r.w.flags & 0x40) return FALSE; // Z flag SET -> no data
return TRUE;
}
/*
* kbDosRead() does a destructive read by calling BIOS call 16H code 0.
*/
static boolean kbDosRead(struct plKbdInfo* ki)
{
union dosxReg r;
UBYTE v;
memset(&r, 0, sizeof(r)); // Make sure all segregs are 0
r.w.ax = 0x1000; // Was 0x0, now extended
dosxIntr(0x16, &r);
if((r.x.flags & 0x40) == 0) // Z flag NOT set?
{
ki->ki_scan = r.h.ah;
ki->ki_ascii= r.h.al;
dosxMemRead(&v, 0x00400017ul, 1);
ki->ki_flags= (v & 0x03) ? PLKF_SHIFT : 0;
if(v & 0x08) ki->ki_flags |= PLKF_ALT;
if(v & 0x04) ki->ki_flags |= PLKF_CTRL;
if(v & 0x10) ki->ki_flags |= PLKF_SCROLLLOCK;
if(v & 0x20) ki->ki_flags |= PLKF_NUMLOCK;
if(v & 0x40) ki->ki_flags |= PLKF_CAPSLOCK;
return TRUE;
}
return FALSE;
}
/*
* kbDosIdle()
*/
static void kbDosIdle(void)
{
union dosxReg r;
memset(&r, 0, sizeof(r));
dosxIntr(0x28, &r);
}
/*
* plKbdReadF() does a non-waiting read of the keyboard.
*/
boolean plKbdReadF(struct plKbdInfo* ki)
{
if(kbHasChar())
{
if(kbDosRead(ki))
return TRUE;
}
kbDosIdle();
return FALSE;
}
/****************************************************************************/
/* */
/* CODING: Mouse - Dos MOUSE interface (Mou calls). */
/* */
/****************************************************************************/
/*--------------------------------------------------------------------------*/
/* DEFINES: Mouse command codes. */
/*--------------------------------------------------------------------------*/
#define MC_RESET 0x0000
#define MC_CURSEN 0x0001 /* Enable cursor position */
#define MC_CURSDI 0x0002 /* Disable cursor */
#define MC_GETCUR 0x0003 /* Get cursor position */
#define MC_SETCUR 0x0004 /* Set cursor position */
#define MC_GETBPRESS 0x0005 /* Get button press state */
#define MC_GETBRELEASE 0x0006 /* Button release state */
#define MC_SETXRANGE 0x0007 /* Set X cursor range */
#define MC_SETYRANGE 0x0008 /* Set Y cursor range */
#define MC_GRCURSOR 0x0009 /* Set Graphic cursor style */
#define MC_TXCURSOR 0x000a /* Set text mode cursor style */
#define MC_GETMOTION 0x000b /* Get mouse motion # */
#define MC_SETEVENT 0x000c /* DefiNE event handler location */
#define MC_LPENABLE 0x000d /* Enable light pen emulation */
#define MC_LPDISABLE 0x000e /* Disable light pen emulation */
#define MC_SETSENS 0x000f /* Set sensitivity (mousemove/pixel) */
#define MC_CDRANGE 0x0010 /* Disable cursor in given range */
#define MC_DBLSPEEDTH 0x0013 /* DefiNE double-speed treshold */
static ULONG MouseCursorState; /* Mouse saved cursor state */
static boolean MousePresent; // T if mouse was located at init.
static ULONG MousePressCount; // #times the mouse was clicked.
/*
* MOUSIsPresent() returns T if the mouse is present. It can be called only
* when the MOUSInit call has been done.
*/
boolean MOUSIsPresent(void)
{
return MousePresent;
}
/*
* MOUSPressCount()
*/
ULONG MOUSPressCount(void)
{
return MousePressCount;
}
/*
* MOUSInit() initializes the mouse driver. It returns FALSE if no mouse's
* present. When it's not called by the user program no mouse support
* is given..
*/
boolean MOUSInit(void)
{
// UBYTE *p;
union dosxReg r;
if(! MousePresent) /* If not already called */
{
#if 0 // No vector for EXTENDERS
/**** Get the contents of interrupt 33H ****/
p = (UBYTE *)getvect(0x33);
if(p == NULL || *p == 0xcf) return FALSE;
#endif
/**** Mouse driver present: Call the mouse driver ****/
memset(&r, 0, sizeof(r));
r.w.ax = MC_RESET;
dosxIntr(0x33, &r);
if(r.w.ax != 0) /* Mouse attached? */
{
MousePresent = TRUE;
MOUSSetTextCursor(0, 0); /* Use default text cursor */
}
MouseCursorState= 0; /* Cursor invisible */
}
else
assert(0);
return MousePresent; /* Return mouse state */
}
/*
* MOUSExit() doesn't do a thing but is called to maintain compatibility.
*/
void MOUSExit(void)
{
MousePresent = FALSE;
MouseCursorState= 0;
}
/*
* MOUSCursen() enables/disables the mouse cursor. It takes notice of the
* previous state and calls the routine ONLY if the state needs a change.
*/
void MOUSCursen(boolean enable)
{
union dosxReg r;
if(MousePresent)
{
if( (enable && !(MouseCursorState & 1)) ||
(!enable && (MouseCursorState & 1)))
{
memset(&r, 0, sizeof(r));
r.w.ax = enable ? MC_CURSEN : MC_CURSDI;
dosxIntr(0x33, &r);
if(enable)
MouseCursorState |= 1;
else
MouseCursorState &= ~1;
}
}
}
/*
* MOUSSaveCurs() saves the current cursor state.
*/
void MOUSSaveCurs(void)
{
ULONG state;
state = MouseCursorState & 1;
MouseCursorState = (MouseCursorState << 1) | state;
}
/*
* MOUSRestCurs() restores the last cursor state.
*/
void MOUSRestCurs(void)
{
ULONG nstate;
nstate = MouseCursorState >> 1; // Get new state of cursor,
MOUSCursen((boolean) (nstate & 1) ); // Make mouse's new state,
MouseCursorState = nstate; // And set the new state.
}
/*
* MOUSPos() returns the current mouse position and the button states.
*/
void MOUSPos(UWORD *x, UWORD *y, boolean *leftbutton, boolean *rightbutton)
{
union dosxReg r;
if(MousePresent)
{
memset(&r, 0, sizeof(r));
r.w.ax = MC_GETCUR;
dosxIntr(0x33, &r);
if(leftbutton != NULL) *leftbutton = (r.w.bx & 1) != 0;
if(rightbutton != NULL) *rightbutton = (r.w.bx & 2) != 0;
if(x != NULL) *x = r.w.cx;
if(y != NULL) *y = r.w.dx;
}
}
/*
* MOUSSetpos() sets a new mouse cursor position
*/
void MOUSSetpos(UWORD x, UWORD y)
{
union dosxReg r;
if(MousePresent)
{
r.w.ax = MC_SETCUR;
r.w.cx = x;
r.w.dx = y;
dosxIntr(0x33, &r);
}
}
/*
* MOUSSetTextCursor() sets the text cursor style. It always selects a
* software cursor and, if both screenmask and cursormask are zero it
* selects an inverse 'o' (0x09) as cursor character.
*/
void MOUSSetTextCursor(UWORD screenmask, UWORD cursormask)
{
union dosxReg r;
if(MousePresent)
{
memset(&r, 0, sizeof(r));
r.w.ax = MC_TXCURSOR; /* Define text cursor command */
r.w.bx = 0; /* Software text cursor */
if(screenmask == 0 && cursormask == 0)
{
#if 0
r.w.cx = 0x0000; /* Screen mask value: all bits OFF */
r.w.dx = 0x1f09; /* Cursor mask: an 'o' */
#endif
r.w.cx = 0x7700; /* Screen mask value */
r.w.dx = 0x77fe; /* Cursor: a blob */
}
else
{
r.w.cx = screenmask;
r.w.dx = cursormask;
}
dosxIntr(0x33, &r);
}
}
/*
* MOUSPressed() returns TRUE when the mouse key was pressed AND:
* a. The mouse key has been released since the last call OR
* b. The mouse position has changed.
* It returns the new mouse coordinates in character positions.
*/
boolean MOUSPressed(UWORD *x, UWORD *y)
{
boolean leftbutton;
static boolean waspressed;
static UWORD lx, ly;
if(MousePresent)
{
MOUSPos(x, y, &leftbutton, NULL); /* Get current mouse pos & state */
*x /= 8; /* Scale to characters */
*y /= 8; /* Idem */
if(leftbutton) /* Key pressed? */
{
/**** Key was pressed! Have the coords changed since the last ****/
/**** time? ****/
if(*x == lx && *y == ly && waspressed) return FALSE; /* Nothing changed */
lx = *x;
ly = *y;
waspressed= TRUE;
return TRUE;
}
else
waspressed = FALSE;
}
return FALSE;
}
/*
* MOUSSetBounds() attempts to automatically set appropriate mouse cursor
* boundaries based on the current screen textmode.
* NOTE: This is currently written assuming 80 column text modes, with
* the only possible screen heights being 25, 43 or 80.
*/
boolean MOUSSetBounds(void)
{
union dosxReg r;
int rows;
int height;
rows = plScnHeight();
if (rows == 43) {
height = 350;
} else if (rows == 50) {
height = 400;
} else {
height = 200;
}
if(MousePresent)
{
memset(&r, 0, sizeof(r));
r.w.ax = MC_SETXRANGE;
r.w.cx = 0;
r.w.dx = 639;
dosxIntr(0x33, &r);
memset(&r, 0, sizeof(r));
r.w.ax = MC_SETYRANGE;
r.w.cx = 0;
r.w.dx = (height - 1);
dosxIntr(0x33, &r);
return TRUE;
}
return FALSE;
}
#endif // DOS || DOSP32