⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mouse.doc

📁 这是一个C++编程文档
💻 DOC
📖 第 1 页 / 共 4 页
字号:
	0000000001111111	0111111100000000
	0000000000111111	0111111110000000
	0000000000011111	0111111111000000
	0000000111111111	0111110000000000
	0001000011111111	0100011000000000
	0011000011111111	0000011000000000
	1111100001111111	0000001100000000
	1111100001111111	0000001100000000
	1111110000111111	0000000110000000

	  Screen Mask		  Cursor Mask

Figure 1: Example graphics cursor
-----------------------------------------------------------------------

    The  graphics mask pair are defined together in a single  array  of
type unsigned integer.  For clarity,  comment fields were added in cur-
sor.h to show what the masks will actually produce. This is helpful not
only in identifying what a cursor looks like, but also in designing new
cursors.  The GraphicsCursor class constructor is used for declaring  a
cursor.  It takes as arguments the cursor hot spot,  mask array,  width
and height. The width and height are the actual pixel dimensions of the
image.  In Figure 1,  the width is 11 and the height is 16 -  these are
the  maximum  dimensions of the defined screen mask,  even  though  the
overall array is 16x16.  An instance of GraphicsCursor can be passed to
SetCursor() to make it the current cursor.

    SetCursor() can also set the text cursor type and shape.  There are
two  cursor types in text mode.  The hardware cursor places the  normal
video  cursor (the cursor normally associated with the keyboard)  under
the  control of the mouse.  The software cursor is independent  of  the
video cursor and behaves similarly to the graphics cursor. The software
cursor is used in most applications so that the user is presented  with
the  normal video cursor for typing and a mouse cursor for menu  selec-
tion, etc.  The cursor type - 0 for software, 1 for hardware - is  part
of the TextCursor class.

    Like the graphics cursor,  the text software cursor also requires a
screen and cursor mask,  but no hot spot since the cursor always  takes
up  a  whole character cell,  regardless of where the mouse  cursor  is
actually positioned in that cell. (If a hardware cursor is implemented,
the  starting  and ending scan lines for the cursor are required.)  The
two  masks operate only on a character cell,  not a 16x16 pixel  array.
Each cell consists of a one-byte character value and a one-byte charac-
ter attribute (which sets the foreground and background colors), so the
masks must each be two bytes long.  The upper byte masks the attribute,
and  the lower byte masks the character.  Like the graphics masks,  the
screen mask is XORed with the underlying character cell, and the cursor
mask is ANDed with the resulting value.  The difference is that in text
mode, both the character value and its color can be changed, whereas in
graphics mode, the pixel colors cannot be controlled.

    To get a better understanding of what the masks will do, we need to
look at an example of a screen character:

      6B24h = 0110 1011 0010 0100 b
              |--- ---- ---------
              | |   |       |__ character value  (24h)
              | |   |__________ foreground color (11d)
              | |______________ background color (6d)
              |________________ blinking bit (1=blinking)

This  value will display a '$' (24h) with a background color  of  brown
(6) and a foreground color of lightcyan (11).  With the text cursor, we
can  mask each bit of the character and attribute,  so not only can  we
set the mouse cursor character,  but we can also control the foreground
and background colors (and even blinking).  The cursor masks default to
a reverse box, which is

	Screen Mask = 77FFh = 0111 0111 1111 1111 b
	Cursor Mask = 7700h = 0111 0111 0000 0000 b

The first byte of the screen mask,  77h in this example,  is ANDed with
the  underlying characters attribute.  The first 7h is ANDed  with  the
background  color  so that all colors but the blinking bit  are  passed
through.  Masking the blinking bit to 0 will allow the mouse cursor  to
rest on a blinking character without itself blinking.  The second 7h is
ANDed  with the foreground color so that those colors are also  passed,
except  that the high intensity colors will be converted to low  inten-
sity. The FFh also passes the screen character. In the cursor mask, the
77h  will invert both the foreground and background colors,  while  the
00h  creates an "empty" character, which is a character cell  with  no-
thing in it (a box).

    If  you  want to create a cursor with a  particular  character  and
color,  you would set the screen mask to 0000h and the cursor  mask  to
whatever color and character values desired.  For example,

	Screen Mask = 0000h = 0000 0000 0000 0000b
	Cursor Mask = 0F23h = 0000 1111 0010 0011b

will set the cursor character to a '#' with a background color of black
and a foreground color of white.  More complex combinations are  possi-
ble,  such as setting the cursor's foreground color to a constant value
but allowing the screen's background color to show through.  Again, the
best  way to understand it is to try it,  and cursor.h defines  several
text cursors.

    In graphics mode, the mouse driver takes care of drawing the cursor
and restoring the image under the cursor when it moves. One drawback to
this  is that you cannot use color cursors in graphics mode  using  the
mouse driver. You can instead create a color image, manually draw it to
the screen, and manually restore the underlying image.  This is exactly
how  the  ColorGraphicsCursors work.  If a CGC is installed  using  the
SetCursor()  command,  then the special drawing functions will  trigger
off of the event handler, thereby drawing the cursor whenever the mouse
moves. CGC cursors are defined just like standard graphics cursors, ex-
cept that the screen mask is split into the four video bit planes.  See
cursor.h for examples.

    The color drawing functions in cgc.cpp were written purely in  C++,
with no assembly language.  The reason for this was to clearly show how
the  methods work.  The results are that the color cursor image  has  a
slight flicker, but overall the speed is acceptable.  Also, these func-
tions do not make any attempt to save and restore the video card state.
This could be a problem because the drawing functions are triggered  by
the  mouse event handler and could therefore be activated at any  time,
even  during another graphics draw.  You can avoid problems by  turning
the cursor off (using Hide()) before drawing any graphics,  which is  a
good  idea anyway.  Finally, these functions only support standard  EGA
and VGA resolutions.

    A  better method is to use your favorite graphics library  to  draw
the cursor and restore the screen.  This will probably result in better
speed and might also support higher resolutions such as  SuperVGA/VESA.
(This approach also solves another drawback of the mouse drivers - they
also do not support high-res modes.) To implement another graphics  li-
brary, you need only modify the VideoRead(), VideoWrite(),  and Cursor-
Write() funtions. An example using the BGI is provided in cgc_bgi.cpp.

-----------------------------------------------------------------------

The Event Handler

    There is another way to capture mouse events. The mouse event hand-
ler  is  similar to a TSR program in that it can be set up  to  capture
events in background.  The handler can be set to trigger off any combi-
nation of mouse events (Table 1),  and can then execute any user  code,
providing it does not issue a DOS or I/O call.  However, since the main
program  is suspended during the event handler execution,  the  handler
code  should  be fast so it does not to noticeably slow down  the  main
program.  When an event occurs,  certain mouse information is automati-
cally  placed  in the registers for the handler to  use.  The  function
Save() can be used to stuff these parameters into the event buffer  for
later use.  Any event handler routines you write must be declared as an
interrupt type and terminate with a far return.  The macro  EventExit()
provides  the proper exit code and should be the last statement in  the
handler function:

	void interrupt lb_handler()
	{
	  mouse.Save();
	  do_something();
	  EventExit();
	}

    You  can then use this function and an event mask to create an  in-
stance of a MouseEventHandler.  Installing it is accomplished  with the
function InstallHandler():

	#include "mouse.h"

	void interrupt lb_handler();

	main()
	{
	  unsigned char eventmask = LB_PRESSED | LB_RELEASED;
          MouseEventHandler myHandler(eventmask, lb_handler);

	  if(mouse.Exists())
	  {
	    mouse.InstallHandler(myHandler);
	    mouse.Enable();
	    mouse.Show();
	    ...
	  }
	}

eventmask determines which mouse events will trigger the event handler.
In the example above, the handler will execute whenever the left button
is  pressed or released.  Because the event handler should be  kept  as
small  as possible,  you normally only want to call Save() for  storing
the mouse information and then exit.  The MouseEventHandler class  pro-
vides  such a handler by default if you do not specify a handler  func-
tion name:

	main()
	{
          MouseEventHandler myHandler(LB_PRESSED | LB_RELEASED);

	  if(mouse.Exists())
	  {
	    mouse.InstallHandler(myHandler);

         // Here's another way of doing it:
	 // mouse.InstallHandler(LB_PRESSED | LB_RELEASED);

	    mouse.Enable();
	    mouse.Show();
	    ...
	  }
	}

There  might be some cases where you want the handler to do more,  such
as when the program is waiting for user input and not doing much  other
processing.  In such cases you may want to load different handlers, de-
pending on what the program is doing.  A more functional handler can be
loaded for pulldown menus, for instance,  and a bare-bones handler  (or
none  at all) can be installed in speed critical areas where the  mouse
has little use.

    The  Save() function called by the event handler stores  the  mouse
information in a buffer instead of writing it directly into the  class.
This allows events to be captured even while your program is busy doing
something else.  (The keyboard has a similar buffer that provides type-
ahead capability.)  Save() also calls the ColorGraphicsCursor funtions,
so  if you are using CGC's and also want to define custom  event  hand-
lers, you will need to consider this.  To get the event information out
of the buffer, you must call the function GetEvent():

	for(;;)
	{
	  mouse.GetEvent();		// get an event from the buffer
	  if(mouse.LB_Dn())		// check for left button down
	  {
	    if(mouse.x() > 320 || mouse.y() > 100)
	      do_something();
	  }
	  else
	    do_something_else();
	}

    When using the event handler you also have access to two other fea-
tures: MultiClick detection and the Repeater.  MultiClicks occur when a
mouse button is rapidly clicked more than once. You can set up the but-
tons  for MultiClicks by calling the SetClickThreshold()  function  and
then check them with the DoubleClick() and MultiClick() functions:

        mouse.SetClickThreshold(250);	// set threshold to 250ms

	for(;;)
	{
	  mouse.GetEvent();

	  if(mouse.DoubleClick(LEFTBUTTON))	// check for 2 clicks
	    do_something();

	  if(mouse.MultiClick(LEFTBUTTON) == 3)	// check for 3 clicks
	    do_something_else();
	}

When  using this feature, you should realize that multiple clicks  will
load  the buffer with several PRESSED and RELEASED events.  The  Multi-
Click  buffer does not get updated until a call to  GetEvent()  occurs.
Therefore,  it will take three passes through the loop above  before  a
triple click shows up. If the do_something() routine for a double click
clears the mouse buffer,  then the do_something_else() code will  never
execute because a triple click will never occur.

    The Repeater allows a button to be pressed and held down to  gener-
ate multiple PRESSED events,  much like the keyboard does.  This  would
typically be used for a scrollbar routine.  Unlike the MultiClick  fea-
ture,  the  Repeater  can be set up for  individual  buttons.  Use  the
SetRepeatRate() function to set up the Repeater,  and then simply check
for events:

	// This will set the intial delay to 250ms and the repeat rate
        // to 100ms for the left button:

        mouse.SetRepeatRate(LEFTBUTTON, 250, 100);

	for(;;)
	{
	  mouse.GetEvent();

	  if(mouse.LB_Dn())
	    do_something();
	}

The mouse class installs the Repeater by hooking it to the system clock
interrupt which is called every 18ms.

    Properly  used,  event handlers can add a whole new  dimension to a
mouse  driven interface.  However, there are some pitfalls to avoid. If
you set the event mask to trigger on mouse movement,  then the  handler
will execute quite often (every time the mouse is moved) and could  no-
ticeably  slow program execution during periods of  heavy  computation.
Reasons  to trigger on movement include updating a motion counter  such
as in the demo program,  having cursors that dynamically change  depen-
ding on the cursor position such as in a GUI,  or when using CGC's.  As
mentioned before, the handler should not issue a DOS, ROM, or I/O call.
The handler,  like a TSR,  is an interrupt routine that runs while  the
main DOS program is suspended.  DOS is not a re-entrant operating  sys-
tem  and issuing such a call will usually crash the system.  Also, some
standard C library routines make use of these system functions (such as 
printf()), so often the only way of finding out is by trial and reboot.

-----------------------------------------------------------------------
	0x01	MOUSE_MOVED
	0x02	LB_PRESSED
	0x04	LB_RELEASED
	0x08	RB_PRESSED
	0x10	RB_RELEASED
	0x20	CB_PRESSED

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -