home *** CD-ROM | disk | FTP | other *** search
- Turbo and Microsoft C Mouse Routines - Release 1.05
- ---------------------------------------------------
-
- Thu 27-Jan-1991
-
- CONTENTS
-
- 1. What do these routines do?
- 2. How it works.
- 3. Variable and definition reference.
- 4. Function reference.
- 5. The test program.
- 6. Disclaimer and other stuff.
- 7. Modification history.
-
-
- 1. What do these routines do?
- -----------------------------
-
- These routines will allow you to interface with the mouse driver in your
- programs. It works with Microsoft compatible mouse drivers (i.e. Logitech,
- PC Mouse, Dexxa, etc). The routines have the added feature of displaying a
- 'true' mouse cursor in text mode on an EGA or VGA by reprogramming the font
- on the fly.
-
- The routines consist of several functions used to initialize, draw the
- cursor, and get mouse events (button presses).
-
- These routines do not handle drawing the mouse cursor in graphics mode,
- only text mode. If the routines detect the presence of an EGA/VGA adapter,
- it will use the 'true' mouse cursor, if not it will use a simple block
- cursor implemented by switch the foreground/background colors of the
- position the cursor is.
-
- The routines are distributed in a ZIP file with the following files:
-
- MOU.DOC - This documentation file.
- MOU.C - Turbo C/MSC source code.
- MOU.H - Turbo C/MSC header file.
- TEST.C - Turbo C/MSC test program.
- MOU.PAS - Turbo Pascal unit.
- PTEST.PAS - Turbo Pascal test program.
- MAKEFILE - Makefile for creating TC/MSC versions.
- TTEST.EXE - Turbo C test program.
- MTEST.EXE - Microsoft C test program.
- PTEST.EXE - Turbo Pascal test program.
-
- 2. How it works.
- ---------------
-
- All character coordinates used by the mouse driver are zero based. I.e. in
- 80x25 text mode the range of values for x and y are 0-79 and 0-24. The
- routines should work in all memory models.
-
- The routines first check for the presence of a mouse driver, and if none is
- present, they return without doing anything. It is safe to call the
- routines such as MOUhide() and others even if a mouse is not installed,
- they will simply return.
-
- Once the presence of a Microsoft compatible mouse driver is verified, the
- routine checks the presence of DESQview and an EGA/VGA. If an EGA/VGA is
- in the system, and the program is not running under DESQview, the routines
- will choose to use a 'true' cursor, otherwise a simple block cursor will be
- used. A 'true' cursor is not used under DESQview because DESQview doesn't
- really like having it's font changed on the fly by a program. The 'true'
- mouse cursor would probably interfere with other programs running at the
- same time.
-
- The mouse driver does have a glitch that these routines have to work
- around, that being that when in text mode, the mouse driver returns the
- coordinates as multiples of 8 (i.e. 0, 8, 16, 24 ...). Since the 'true'
- cursor has a pixel resolution, we need to get the mouse driver to return
- coordinates in pixels (i.e. 0, 1, 2, 3 ...). To do this, we 'trick' the
- mouse driver into thinking it is in graphics mode (where coordinates are
- returned in pixels) by changing the current video mode. This is done by
- placing a value of 6 in memory location 0x0040:0x0049, 6 being the number
- for CGA 640x200 2 color graphics mode. We then tell the mouse driver to
- initialize again (using mouse driver function 0), and the mouse driver
- checks the video mode, sees that we are in graphics mode, and sets itself
- up accordingly. We then restore the mode byte at 0x0040:0x0049 to it's
- previous value. After this, the mouse driver returns all coordinates in
- pixels. I had to hack out this fix on my own, I called Microsoft and got
- nothing from them, but I remembered that when you are running the mouse
- driver in graphics mode on a Hercules graphics adapter, you have to do this
- 'trick.' It worked in this case as well.
-
- Next the initialization routine sets up the maximum x and y ranges for the
- mouse cursor based on the dimensions of the video mode. Lastly it installs a
- mouse function handler using mouse driver function 12 -- define handler.
- The handler is installed for mouse movement, and left or right button
- presses and releases.
-
- The handler is defined in the function 'void far mousehandler(void)'. This
- function is called by the mouse driver upon one of the events happening as
- defined in the call to mouse driver function 12. The handler will
- automatically update the mouse cursor, change the global variables mousex
- and mousey to the character (not pixel) coordinates of the mouse. It also
- checks for mouse events (button presses and releases) and stores them into
- a buffer if an event happens. This event is later retrieved with a call to
- MOUpreview() or MOUget().
-
- The drawing of the mouse cursor on non EGA/VGA adapters is quite simple.
- It reverses the foreground and background color of the character where the
- mouse is located. This is the default text cursor that the mouse driver
- uses itself.
-
- On an EGA/VGA adapter, things get a little more complicated. A 3x3
- character arrangement is used to draw the cursor. The function
- plotegavgacursor() handles saving the 3x3 character array, restoring it
- later, and drawing the 3x3 array of characters that is redefined. The
- redefinition consists of reading the definitions of the characters,
- preforming an AND and OR of the mouse cursor onto the existing definitions,
- then copying those modified definitions to a new location. I copy to
- characters 0xd0 to 0xd8. Then the characters 0xd0 to 0xd8 are placed in
- the 3x3 grid where the mouse cursor is located, thereby drawing the cursor.
-
- The mouse cursor is a simple array of dwords (32 bit unsigned long) that is
- used to update the character definitions. The cursor can be changed from
- the default one provided, as defined in the mouse driver documentation for
- defining graphics cursors. It consists of two masks: the screen mask, and
- the cursor mask. The screen mask is bitwise AND'ed to the existing character
- definitions, then the cursor mask is bitwise OR'ed to the existing character
- definitions.
-
- The functions MOUshow(), MOUhide() and MOUconditionalhide() perform as
- their counterpart functions provided by the mouse driver.
- MOUconditionalhide() is a special function (that some 'clone' drivers
- _don't_ have) that allows you to update a rectangular region on the screen
- without disturbing the mouse (if it is not in the region). It is called
- with the character coordinates of a rectangular region on the screen. If
- the mouse is in that region, or if the mouse moves into that region, the
- mouse cursor will automatically turn off. A call to MOUshow() cancels the
- rectangular region. You can't make multiple calls to MOUconditionalhide()
- between calls to MOUshow().
-
- Various 'glitches' arise by using a 'true' mouse cursor. They are listed
- as follows:
-
- 1. On the VGA adapter, standard text mode consists of 9 by 16 characters.
- The character are not actually 9 bits wide, but 8. The VGA duplicates
- the rightmost bit for the border characters (characters 176 to 218).
- The 'true' cursor uses (rather redefines) characters 208 to 216 (0xd0
- to 0xd8 hex), thereby having its rightmost bit duplicated. If another
- set of characters is used, the cursor appears to have a 'gap' in the
- middle of it. The problem lies in that if the cursor is moved over a
- character that has some of its rightmost bit set, the rightmost bit
- will be duplicated. Characters such as the lower case 'm' are
- examples of this. It is much easier to see the effect of this than
- explain it. Run the TEST program that comes with the routines and
- place the cursor over a lower case m on the screen. You will notice
- the effect. I can't see any way around this. This doesn't happen on
- an EGA as the EGA uses 8 pixel width characters (not 9).
-
- 2. Since the 'true' mouse cursor is larger than one character, moving the
- cursor into areas of the screen with different foreground colors will
- cause the cursor to take on that color. If the cursor is at the
- border of two different foreground colors, it will appear that the
- cursor is in two colors. I got around this by always using the same
- foreground color for all characters on the screen (i.e. WHITE) and
- just using different background colors to show differences on the
- screen.
-
- 3. DESQview doesn't like its font changed on the fly. It interferes with
- the 'true' cursor to the point where it's dysfunctional. The mouse
- routines will automatically detect DESQview and fall back to a normal
- block cursor if running under DV.
-
- 4. Since the font is changed, characters 0xd0 to 0xd8 are not available
- for use by the program. These characters are the IBM border
- characters used to connect double line and single line boxes together.
- I don't use these characters in my programs, and they aren't really
- needed. If you need to have a single line join a double line graphics
- character, just place them side by side. They won't actually 'join'
- as it would by using a double to single line character, but they will
- line up closely. I find it an acceptable loss to provide a 'true'
- mouse cursor on the EGA/VGA.
-
- For a description of how to change fonts on the EGA/VGA adapters, I highly
- recommend the book by Richard Wilton, _Programmer's Guide to PC & PS/2
- Video Systems_. An excellent book if you are doing any kind of video
- programming. For a description of the mouse driver interface, I can
- recommend Logitech's Mouse Programmer's Toolkit, Microsoft Press's Mouse
- Reference Guide, and Ralf Brown's Interrupt List (updated periodically).
- I initially learned the interface to the mouse driver from an article in PC
- Magazine (I can't remember what issue), and I use Ralf Brown's Interrupt
- List for reference now.
-
- 3. Variable and definition reference.
- -------------------------------------
-
- The following variables and definitions are included in MOU.H:
-
- C: MOUINFOREC
-
- Pascal: mouinforectype
-
- This is the definition for the structure returned by the functions
- MOUpreview() and MOUget(). It contains the following fields:
-
- word buttonstat: bits in this field indicate what event occurred. See them
- below.
- int cx, cy: character coordinates of where this event occurred.
- byte shiftshate: the status of the shift keys at the time of the event.
- See definitions below.
-
- ---------------------------------------
-
- C: MOUBUFFERSIZE
-
- Pascal: MOUBUFFERSIZE
-
- This is the size of the mouse buffer. The buffer is where mouse events are
- held for the program until is retrieves them with MOUget().
-
- ---------------------------------------
-
- C: MOUSEMOVE, LEFTBPRESS, LEFTBRELEASE, RIGHTBPRESS, RIGHTBRELEASE,
- MIDBPRESS, MIDBRELEASE
-
- Pascal: MOUSEMOVE, LEFTBPRESS, LEFTBRELEASE, RIGHTBPRESS, RIGHTBRELEASE,
- MIDBPRESS, MIDBRELEASE
-
- These defines are for the field buttonstat in the MOUINFOREC structure. By
- checking the bits of buttonstat, you can find out what event occurred, for
- example, "if (m.buttonstat & LEFTBPRESS)" will be true if the event was
- caused by the press of the left mouse button.
-
- ---------------------------------------
-
- C: LEFTBDOWN, RIGHTBDOWN
-
- Pascal: LEFTBDOWN, RIGHTBDOWN
-
- These defines are used for the value returned by the function
- MOUbuttonstatus(). I.e. "if (MOUbuttonstatus() & LEFTBDOWN)" will be TRUE
- if the left mouse button is currently down.
-
- ---------------------------------------
-
- C: SHIFT_RIGHTSHIFT, SHIFT_LEFTSHIFT, SHIFT_SHIFT, SHIFT_CTRL, SHIFT_ALT,
- SHIFT_SCROLLLOCK, SHIFT_NUMLOCK, SHIFT_CAPSLOCK, SHIFT_INS
-
- Pascal: SHIFT_RIGHTSHIFT, SHIFT_LEFTSHIFT, SHIFT_SHIFT, SHIFT_CTRL, SHIFT_ALT,
- SHIFT_SCROLLLOCK, SHIFT_NUMLOCK, SHIFT_CAPSLOCK, SHIFT_INS
-
- These defines are for the shiftstate field in the MOUINFOREC structure. It
- allows you to check for such things as shift-clicks. I.e.
- "if (m.shiftstate & SHIFT_LEFTSHIFT)" will be TRUE if the left shift key
- was held down during the mouse event. SHIFT_SHIFT is defined as both shift
- keys.
-
- ---------------------------------------
-
- C: word mousehidden;
-
- Pascal: mousehidden : word;
-
- This variable will be true (non-zero) if the mouse is currently hidden. It
- is undefined if mouseinstalled is false. Don't write to this variable,
- it's just provided for your reference.
-
- ---------------------------------------
-
- C: boolean mouseinstalled;
-
- Pascal: mouseinstalled : boolean;
-
- This variable will be true (non-zero) if a mouse driver is installed and
- operating and the mouse routines are active and reading the mouse and
- drawing the cursor. If it is false, the mouse driver routines will not
- operate, calling them will do nothing (but calling them is not harmful).
-
- ---------------------------------------
-
- C: volatile int mousex, mousey;
-
- Pascal mousex, mousey : integer;
-
- These variables hold the current location of the mouse cursor. They are
- updated by the mouse handler. Note that their value may changed at _any_
- time. Don't depend on them being constant. If you need to reference them,
- I recommend declaring a couple of variables to hold their values (i.e. int
- x, y; x = mousex; y = mousey;) and using those instead of mousex and
- mousey. Only reference mousex and mousey when you need to update the
- position.
-
-
- 4. Function reference.
- ----------------------
-
- C: void FAST MOUinit(void);
-
- Pascal: procedure MOUinit;
-
- This function initializes the mouse routines, checks for presence of the
- mouse driver, DESQview and an EGA/VGA. What it does is described above in
- "How does it work?".
-
- ---------------------------------------
-
- C: void FAST MOUdeinit(void);
-
- Pascal: procedure MOUdeinit;
-
- This function will deinitialize the mouse routines. It will stop the mouse
- driver from calling the handler, and erase the mouse cursor. You can call
- MOUinit() if you wish to use the mouse driver routines again. You MUST call
- this function before you quit your program. Failure to do so will most
- likely cause your computer to crash next time the mouse is moved. If you
- don't call it, the mouse driver still calls the mouse hander, even after
- the program has quit.
-
- ---------------------------------------
-
- C: void FAST MOUhide(void);
-
- Pascal: procedure MOUhide;
-
- This hides the mouse cursor. The mouse cursor must be hidden with this
- function (or MOUconditionalhide() below) before doing any screen updating.
- This prevents overwriting the mouse cursor. The preferred way to hide the
- mouse is MOUconditionalhide(). But if you are clearing the screen, or
- updating all of it at once, use this function. This function counts how
- many times it has been called, i.e. if you call it twice, you have to call
- MOUshow() twice to get the cursor back on the screen.
-
- ---------------------------------------
-
- C: void FAST MOUconditionalhide(int x1, int y1, int x2, int y2);
-
- Pascal: procedure MOUconditionalhide(x1, y1, x2, y2 : integer);
-
- This function hides the mouse automatically if it is in, or is moved in,
- the rectangular region defined by this function. If possible use this
- function to hide the mouse, as if the mouse isn't near the area being
- updated, it won't 'blink' like it would calling MOUhide(). The coordinates
- are zero based and x1 must be <= x2 and y1 must be <= y2. Call MOUshow()
- after you have finished updating the region you defined. If the mouse was
- hidden, MOUshow() will turn it back on.
-
- ---------------------------------------
-
- C: void FAST MOUshow(void);
-
- Pascal: procedure MOUshow;
-
- This turns on the mouse cursor after a previous call to MOUhide() or
- MOUconditionalhide(). This function may be called as many times as you
- like, once the cursor is not hidden, any other calls will have no effect.
-
- ---------------------------------------
-
- C: boolean FAST MOUcheck(void);
-
- Pascal: function MOUcheck : boolean;
-
- This function returns true (non-zero) if there are events in the buffer, if
- not it returns false (zero).
-
- ---------------------------------------
-
- C: void FAST MOUpreview(MOUINFOREC *mouinforec);
-
- Pascal: procedure MOUpreview(var mouinforec : mouinforectype);
-
- This function passes the next event to the MOUINFOREC passed to it. It
- does not remove the event from the buffer. If there are no events in the
- buffer, the MOUINFOREC returned will have the current mouse position in the
- cx and cy fields of the MOUINFOREC, the shiftstate field set to the current
- state of the shift keys, and the buttonstat field blank (zero, or no
- events).
-
- ---------------------------------------
-
- C: void FAST MOUget(MOUINFOREC *mouinforec);
-
- Pascal: procedure MOUget(var mouinforec : mouinforectype);
-
- This function passes the next event to the MOUINFOREC passed to it. It
- will remove the event from the buffer. If there are no events in the
- buffer, the MOUINFOREC returned will have the current mouse position in the
- cx and cy fields of the MOUINFOREC, the shiftstate field set to the current
- state of the shift keys, and the buttonstat field blank (zero, or no
- events).
-
- ---------------------------------------
-
- C: word FAST MOUbuttonstatus(void);
-
- Pascal: function MOUbuttonstatus : word;
-
- This will return the current status of the mouse buttons. It can be
- ANDed with LEFTBDOWN, MIDBDOWN or RIGHTBDOWN to see if either button is
- currently being held down. This function could be used to detect
- dragging of the mouse.
-
- ---------------------------------------
-
- C: void FAST MOUsetpos(word x, word y);
-
- Pascal: procedure MOUsetpos(x, y : integer);
-
- Sets the current mouse position. Mouse will move to the new coordinates on
- the call. Parameters are character coordinates, not pixel coordinates.
-
- 5. The test program.
- --------------------
-
- Included with the routines is a small test program that will allow you to
- see the 'true' mouse cursor (if you have an EGA/VGA adapter). Included is
- a makefile for NDMake and Turbo C/Microsoft C. The makefile defaults to
- Turbo C, you have to make a simple edit for Microsoft C. If you don't have
- a makefile, you can compile it like this:
-
- tcc -ml test.c mou.c
-
- or under MSC as:
-
- cl /AL test.c mou.c
-
- or under Turbo Pascal:
-
- tpc ptest.pas
-
- Note: with Turbo C, you will require to have TASM in your path as the
- routines have inline assembler in them. MASM isn't required for MSC (MSC
- has a built in assembler, though it's a bit dumb at times).
-
- It's a simple program that will tell you the current mouse position and the
- status of the mouse buttons.
-
- The mouse routines will work in ALL EGA/VGA text modes. I've run it in
- 80x25 and 80x50 mode and the 'true' cursor will be drawn in both those
- modes. My VGA supports a 132x60 mode as well, and the 'true' mouse cursor
- works perfectly in that mode as well.
-
- The C version of the test program requires ANSI.SYS to be installed.
-
- 6. Disclaimer and other stuff.
- ------------------------------
-
- I originally started working on these routines when I first saw the new
- version of Norton's Utilities (version 5.0). I was impressed with the
- 'true' mouse cursor it was drawing in text mode, and wanted to know if I
- could write a set of routines to do the same thing.
-
- In Jan. of '91, a discussion on the group comp.os.msdos.programmer about the
- way Norton does the 'true' mouse cursor arose. I replied to a message by
- Brian K. W. Hook who indicated that he doubted Norton changed the font on
- the fly to implement a 'true' mouse cursor in text mode. He stated he was
- 'baffled' by the way that Norton did it. I stated that Norton did do it by
- changing the font on the fly, and that I had written some routines to do it
- as well.
-
- Brian asked me for the routines, as well as a couple of other users, so I
- cleaned them up, made them independent of my text window library (I've
- written a library for text window routines that I use in my programs) and
- otherwise prepared to unleash them on unsuspecting Usenet victims. :)
-
- These routines also illustrate interfacing to mouse driver function 12,
- which seems to be a common question on comp.os.msdos.programmer (How to I do
- interface to the mouse driver?).
-
- I'll supply support for these routines as my time permits, and I can be
- reached by any of the following methods of communication:
-
- Email: UUCP: {uunet,ubc-cs}!van-bc!rsoft!mindlink!a563
- Internet/Usenet: Zoid@mindlink.bc.ca
-
- Zoid@mindlink.bc.ca is preferred.
-
- Mail: #801-9835 King George Hwy.
- Surrey, BC Canada
- V3T 5H6
-
- Phone: 604-585-8844.
-
- Duncan Murdoch converted the routines to Turbo Pascal 6.0 for me. He can
- be reached at:
-
- dmurdoch@watstat.waterloo.edu
-
- I do hope you enjoy these routines, and have an 'edge' on the competition
- by having a flashy 'true' cursor on the EGA/VGA. Wow!
-
-
-
- DISCLAIMER
-
- Dave Kirsch makes no warranty of any kind, either express or implied,
- including but not limited to implied warranties of merchantability
- and fitness for a particular purpose, with respect to this software
- and accompanying documentation.
-
- IN NO EVENT SHALL DAVE KIRSCH BE LIABLE FOR ANY DAMAGES (INCLUDING
- DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF
- BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OUT OF THE
- USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF DAVE KIRSCH HAS BEEN
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
- Programmers may incorporate any or all code into their programs,
- giving proper credit within the source. Publication of the
- source routines is permitted so long as proper credit is given
- to Dave Kirsch.
-
- Copyright (C) 1990, 1991 by Dave Kirsch.
-
-
- 7. Modification history.
- ------------------------
-
- Date Version
- 91-10-25 1.05 Fixed the documentation a bit.
-
- 91-03-15 1.04 Added a function to set the current mouse position. From a
- suggestion by Gary Tepel.
-
- 91-01-27 1.03 Added the Turbo Pascal version and cleaned up the code and
- documentation. Fixed so it _does_ work under MSC 6.0.
-
- 91-01-17 1.02 Added support for the middle mouse button, from diffs sent
- to me from acero@quads.uchicago.edu (Tony Acero).
-
- 91-01-10 1.01 Fixed bug when referencing POINTS in the mouse handler.
-
- 91-01-08 1.00 Initial release.
-
- Planned enhancements:
-
- 1. It's currently untested with Turbo C++, can anyone verify it works with
- it? It should.
- 2. Functions to redefine the mouse cursor on the fly.
- 3. Convert it for use with other C/C++ compilers (i.e. Zortech).
- 4. I've had a report or two of a 'grid' appearing with the cursor on Sigma
- VGA cards. I want to investigate this.
- 5. Make it work on Hercules RAMFont.