📄 mouse.doc
字号:
Mouse++ Version 4.0
Copyright (c)1992 by Carl Moreland
10/06/92
-----------------------------------------------------------------------
Using the Mouse Class
To incorporate the mouse routines in your program, simply add
mouse.lib to your project or make file and #include mouse.h in any mo-
dule that calls a mouse function. mouse.lib contains all the functions
in mouse.cpp and cgc.cpp, but the functions are separated into differ-
ent object modules for greater efficiency. Note that mouse.lib is com-
piled for the large memory model.
An instance of the Mouse class (there can only be ONE instance) is
declared as extern in mouse.h, so any file that #includes mouse.h will
automatically have access to the mouse. You should NOT declare an in-
stance of the Mouse class in any part of your program. If you intend to
change the mouse cursor, then you also need to #include cursor.h.
When you link the mouse code into your program, an instance of the
mouse class is declared:
Mouse mouse;
The constructor Mouse::Mouse() calls the mouse driver reset function
(all mouse driver functions are called via interrupt 33h) and initia-
lizes the flags exists, enabled, and visible. exists is set to 1 if a
mouse was found and should be checked first. All other mouse class
functions check exists before issuing interrupt 33h calls and abort if
it is zero. enabled is initially zero meaning the mouse is disabled,
and visible is used by Show() and Hide() to keep track of the cursor
visibility. An example of initializing the mouse is:
#include "mouse.h"
main()
{
if(mouse.Exists()) // check for mouse
{
mouse.Enable(); // enable the mouse
mouse.Show(); // display the cursor
...
}
}
Again, including mouse.h automatically creates an instance of the
class, so all you have to do is start using it.
Once the mouse is initialized, it may be necessary to set some
parameters based on what video mode is being used. Strangely, the mouse
driver uses pixel coordinates for both text and graphics mode, with
(0,0) being the upper left hand corner of the screen, and (639,199)
being the default lower right hand corner. This would be correct for
CGA graphics mode and for normal 80x25 text mode - for text mode, this
means that each character cell is treated as an 8x8 pixel array. If you
are programming for the EGA or VGA as is the norm these days, you will
want to change the y-limit of 199 for high resolution graphics and 43
or 50 line text modes. Failure to do this means that the mouse cursor
will not move below the 200th line in graphics mode, or the 25th row in
text mode. (Older mouse drivers might not support more than 200 lines.
If this is the case, you will need to update your mouse driver.) For
640x480 VGA graphics, you need to set the y-limit to (0,479) by calling
yLimit(0,479). For 43 or 50 line text mode, the mouse driver still
treats each character cell as an 8x8 pixel array, so you need to set
the y-limit to (0,349) or (0,399), respectively. Since the default
width of 640 pixels is correct for most video modes, xLimit() is only
necessary when using SuperVGA graphics. (See the section on SuperVGA
support) Both xLimit() and yLimit() can also be used to limit the mouse
cursor to a small portion of the screen, such as a menu.
You may want to use a mouse cursor other than the default cursor.
To do this, call the function SetCursor() with the appropriate cursor
name. Many programs (especially graphics) will use several different
cursors depending on the location of the mouse (such as an arrow for
menus and an i-beam for text) or the particular function being pro-
cessed (such as an hourglass for wait). Several cursors are predefined
in the file cursor.h. To use them, simply include this header file in
whatever module changes the cursor. For more information on cursors,
see the Mouse Cursors section.
Finally, you may want to set the motion parameters, which include
the mickey-to-pixel ratio and the double-speed threshold. The mickey-
to-pixel ratio is set by MickToPix() and defines how many mickeys it
takes to move the mouse 8 pixels. (A mickey is single count of mouse
motion. Most mice are 200 "dots-per-inch", which means that one inch of
movement results in 200 mickeys.) If both the x and y parameters are
set to 8, then there will be a one-to-one correlation between mouse
motion and cursor motion. The default values are 8 in the horizontal
direction and 16 for the vertical. The vertical value of 16 means the
mouse must be moved twice as far vertically as horizontally to get the
same cursor movement. This is fine for text mode where the equivalent
screen resolution of 640x200 results in an equivalent pixel aspect
ratio of 2.4-to-1. In EGA/VGA graphics mode the y-direction will seem
noticeably slower, particularly for 640x480 which has an equivalent
pixel aspect ratio of 1-to-1. A vertical ratio of 8 will cure this.
The lower the ratio, the farther the cursor will move for a given mouse
movement. Setting either ratio lower than 8 means that the cursor can-
not be located on every pixel. For example, setting the ratio to 4 will
cause the cursor to move 2 pixels for every mickey. The double-speed
threshold is set by a call to SetSpeedThreshold(). When the speed of
the mouse (in mickeys per second) exceeds the speed parameter passed to
SetSpeedThreshold(), the motion speed of the cursor will double. A com-
plete initialization might look like this:
#include "mouse.h"
#include "cursor.h"
main()
{
{ initialize screen };
if(mouse.Exists())
{
mouse.SetCursor(cross);
mouse.yLimit(0,479); // VGA 640x480
mouse.MickToPix(8,8);
mouse.SetSpeedThreshold(32);
mouse.Enable();
mouse.Show();
...
}
}
The mouse should be reset before your program terminates so that
the calling program does not inherit any strange parameters. This is
particularly true of the event handler. Because it is an interrupt rou-
tine, failure to reset the mouse could lead to a system crash if the
handler is still pointing to the address of what used to be your hand-
ler routine. The destructor Mouse::~Mouse() first resets the mouse sta-
tus by calling function 00h, and then restores the original event hand-
ler with function 14h.
-----------------------------------------------------------------------
Reading the Mouse
Most of the standard mouse functions stuff any return values di-
rectly into the class variables and have a return type void. This is
because many mouse functions return more than one item of information.
You can then use the appropriate inline function to read the required
private variable. To check for the mouse position, for instance, you
would call Position() followed by either x() or y(), or both, such as:
for(;;)
{
mouse.Position();
if(mouse.x() > 320 || mouse.y() > 100)
do_something();
}
This method has the advantage of capturing both the x and y positions
with a single function call, and those variables can then be read at
your leisure. However, we generally don't care where the mouse is
located unless a button event that we are looking for has occurred.
Position() also returns the status of the mouse buttons, so we can also
check them:
for(;;)
{
mouse.Position();
if(mouse.LB_Dn()) // check for left button down
{
if(mouse.x() > 320 || mouse.y() > 100)
do_something();
}
else
do_something_else();
}
This loop will continuously check to see if the left button has been
pressed. If the do_something_else() code is slow then there is a pos-
sibility that a button press could be missed since Position() returns
the real-time status of the mouse. That is, during execution of the
do_something_else() code, the mouse button could be pressed and re-
leased and Position() would not capture it. The functions Pressed() and
Released() are best suited for checking for a button event because they
will return the button status since the last time they were called. For
example, this code
for(;;)
{
if(mouse.Pressed(LEFTBUTTON))
{
if(mouse.x() > 320 || mouse.y() > 100)
do_something();
}
else
do_something_else();
}
is guaranteed to capture a button press even if the do_something_else()
code is slow to execute. Since Pressed() and Released() also return the
cursor position, a separate call to Position() is not necessary.
In using the mouse, it is often necessary to know if the cursor is
located within a certain area of the screen. For example, in a menu
interface, you want to know if the cursor is located on a menu selec-
tion when a mouse button is clicked. The function InBox() adds this
capability. The parameters passed describe the upper left and lower
right corners of the box. The return value is 1 if the cursor is in the
box, 0 if not. Therefore, the code
if(mouse.InBox(40,40,100,100))
will be true if the mouse cursor is in a box with corners (40,40) and
(100,100). Like other mouse functions, the coordinates are pixels, even
if the screen is in text mode.
In some cases you may want to hide the cursor if it falls inside a
certain area. The mouse driver provides such a function which, in my
opinion, has two drawbacks. Function 10h defines an exclusion window in
which the mouse cursor will turn itself off. However, the programmer
must then manually turn the cursor back on once it is outside the ex-
clusion area, and this requires continuously checking the mouse posi-
tion, such as:
for(;;)
{
mouse.Exclude(40,40,100,100);
do_some_processing();
if(!mouse.InBox(40,40,100,100))
mouse.show();
}
The other problem with function 10h is that it only looks at the hot
spot when checking the cursor's position, so part of the cursor could
enter the exclusion area before the hot spot. The whole point of defin-
ing an exclusion area is to turn the cursor off if it enters the de-
fined area. The Mouse++ Exclude() function is based on the InBox() fun-
ction, taking into account the hot spot location, cursor image height
and width, and cursor visibility.
Finally, if your program is performing a time-consuming task in
which mouse input is not needed, you may want to disable the mouse. If
the mouse is not disabled, the user might become frustrated with a
mouse that does not respond, and the event buffer could become filled
with useless events. Calling the function Disable() will turn the mouse
off and disable the interrupt handler. The mouse and interrupt handler
are re-enabled with the next call to Enable(), although the mouse cur-
sor must be turned on with an explicit call to Show():
...
mouse.Disable();
do_some_long_processing();
mouse.Enable();
mouse.Show();
...
-----------------------------------------------------------------------
Mouse Cursors
Mouse++ currently supports standard text and graphics cursors, and
has rudimentary support for ColorGraphicsCursors. The mouse cursor type
and shape are set by the function SetCursor(). In graphics mode, the
cursor is initially set to the familiar upper left pointing arrow by
the mouse driver. A standard graphics cursor is up to 16x16 pixels in
size and moves in single pixel increments. It is defined by a screen
mask (background), an overlying cursor mask (foreground), and a hot
spot. Since the cursor is 16x16 pixels, a single-pixel hot spot must be
defined so that a unique pixel position can be determined for the cur-
sor. The hot spot has x and y values with valid ranges of 0 to 15.
The two masks determine how the screen will appear where the cursor
is located. The screen mask is first ANDed with the screen pixels, and
the cursor mask is then XORed with the resulting screen. If a screen
mask bit is 0 it will set the underlying screen pixel to 0 (black), and
if the screen mask bit is 1 the pixel color will not change. A cursor
mask bit of 0 does nothing, and a cursor mask bit of 1 will invert the
underlying pixel color. Since the masks have only values of 1 or 0 for
each pixel location, but each pixel can have a color, you cannot
achieve complete control of the cursor color using a standard cursor.
The two basic choices are a black and white cursor where the screen
mask bits are 0, or a cursor that inverts the screen colors where the
screen mask bits are 1.
Figure 1 shows the default cursor as an example. The screen mask
alone will set the screen pixels to black for the bits that are 0, cre-
ating a black arrow. The cursor mask bits that are 1 will then invert
the screen color, meaning part of the black arrow will become white. If
you lay the cursor mask directly over the screen mask, you will notice
that the screen mask arrow extends one pixel beyond the cursor mask
arrow. Because a screen mask bit 0 will create a black background for
the cursor mask, this has the effect of putting a one pixel black bor-
der around the cursor. The reason for doing this is to make the cursor
visible even where the screen background is white. Making the screen
mask bits all 1's so that the cursor XOR's with the underlying screen
is useful in creating a CAD cursor (such as a "+" or a "x") that must
be one pixel wide. The best way to get a better understanding of the
graphics cursor is to try some out. cursor.h defines several graphics
cursors.
-----------------------------------------------------------------------
0011111111111111 0000000000000000
0001111111111111 0100000000000000
0000111111111111 0110000000000000
0000011111111111 0111000000000000
0000001111111111 0111100000000000
0000000111111111 0111110000000000
0000000011111111 0111111000000000
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -