home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / cprog / mouspp30.zip / MOUSE.DOC < prev    next >
Text File  |  1992-02-21  |  41KB  |  951 lines

  1.  
  2.                        Mouse++ Version 3.0
  3.  
  4.                Copyright (c)1992 by Carl Moreland
  5.                             02/21/92
  6.  
  7. -----------------------------------------------------------------------
  8.  
  9. What is Mouse++ ?
  10.  
  11.     Mouse++ is a mouse interface class for Borland C++ or TurboC++.
  12. It consists of three source files: 
  13.  
  14.     mouse.h    header file for Mouse++
  15.     mouse.cpp  source code for Mouse++
  16.     cursor.h   text & graphic cursor definitions
  17.  
  18. A demonstration of most of the functions for both text mode and gra-
  19. phics (EGA/VGA) mode is contained in micedemo.cpp.
  20.  
  21.     To incorporate the mouse routines in your program, simply add 
  22. mouse.cpp to your project or make file, and #include mouse.h in any 
  23. module that calls a mouse function.  An instance of the Mouse class 
  24. (there can only be ONE instance) is declared as extern in mouse.h, so 
  25. any file that #includes mouse.h will automatically have access to the 
  26. mouse.  You should NOT declare an instance of the Mouse class in any 
  27. part of your program.  If you intend to change the mouse cursor, then 
  28. you also need to #include cursor.h.
  29.  
  30. -----------------------------------------------------------------------
  31.  
  32. Using the Mouse Class
  33.  
  34.     When you link the mouse code into your program, an instance of 
  35. the mouse class is declared:
  36.  
  37.     Mouse mouse;
  38.  
  39. The constructor Mouse::Mouse() calls the mouse driver reset function 
  40. (all mouse driver functions are called via interrupt 33h) and initia-
  41. lizes the flags exists, enabled, and visible.  exists is set to 1 if a 
  42. mouse was found and should be checked first.  All other mouse class 
  43. functions check exists before issuing interrupt 33h calls and abort if 
  44. it is zero.  enabled is initially zero meaning the mouse is disabled, 
  45. and visible is used by Show() and Hide() to keep track of the cursor 
  46. visibility.  An example of initializing the mouse is:
  47.  
  48.     #include "mouse.h"
  49.  
  50.     main()
  51.     {
  52.       if(mouse.Exists())        // check for mouse
  53.       {
  54.         mouse.Enable();        // enable the mouse
  55.         mouse.Show();        // display the cursor
  56.         ...
  57.       }
  58.     }
  59.  
  60. Again, including  mouse.h automatically creates an instance of the 
  61. class, so all you have to do is start using it.
  62.  
  63.     Once the mouse is initialized, it may be necessary to set some 
  64. parameters based on what video mode is being used.  Strangely, the 
  65. mouse driver uses pixel coordinates for both text and graphics mode, 
  66. with (0,0) being the upper left hand corner of the screen, and (639,199)
  67. being the default lower right hand corner.  This would be correct for 
  68. CGA graphics mode, and for normal 80x25 text mode, this means that each 
  69. character cell is treated as an 8x8 pixel array.  If you are program-
  70. ming for the EGA or VGA as is the norm these days, you will want to 
  71. change the y-limit of 199 for high resolution graphics and 43 or 50 
  72. line text modes.  Failure to do this means that the mouse cursor will 
  73. not move below the 200th line in graphics mode, or the 25th row in text 
  74. mode.  (Older mouse drivers might not support more than 200 lines.  If 
  75. this is the case, you will need to update your mouse driver.)  For 
  76. 640x480 VGA graphics, you need to set the y-limit to (0,479) by calling 
  77. yLimit(0,479).  For 43 or 50 line text mode, the mouse driver still 
  78. treats each character cell as an 8x8 pixel array, so you need to set 
  79. the y-limit to (0,349) or (0,399), respectively.  Since the default 
  80. width of 640 pixels is correct for most video modes, xLimit() is only 
  81. necessary when using SuperVGA graphics.  Both xLimit() and yLimit() can 
  82. also be used to limit the mouse cursor to a small portion of the screen,
  83. such as a menu.
  84.  
  85.     You may want to use a mouse cursor other than the default cur-
  86. sor.  To do this, call the function SetGraphicsCursor() or SetText-
  87. Cursor() with the appropriate cursor name.  Many programs (especially 
  88. graphics) will use several different cursors depending on the location 
  89. of the mouse (such as an arrow for menus and an i-beam for text) or the 
  90. particular function being processed (such as an hourglass for wait).  
  91. Several cursors are predefined in the file cursor.h.  To use them, sim-
  92. ply include this header file in whatever module changes the cursor.  
  93. For more information on cursors, see the Mouse Cursors section.
  94.  
  95.     Finally, you may want to set the motion parameters, which in-
  96. clude the mickey-to-pixel ratio and the double-speed threshold.  The 
  97. mickey-to-pixel ratio is set by MickToPix() and defines how many mic-
  98. keys it takes to move the mouse 8 pixels.  (A mickey is single count of 
  99. mouse motion.  Most mice are 200 "dots-per-inch", which meansthat one 
  100. inch of movement results in 200 mickeys.)  If both the x and y parame-
  101. ters are set to 8, then there will be a one-to-one correlation between 
  102. mouse motion and cursor motion.  The default values are 8 in the hori-
  103. zontal direction and 16 for the vertical.  The vertical value of 16 
  104. means the mouse must be moved twice as far vertically as horizontally 
  105. to get the same cursor movement.  This is fine for text mode where the 
  106. equivalent screen resolution of 640x200 results in an equivalent pixel 
  107. aspect ratio of 2.4-to-1.  In EGA/VGA graphics mode the y-direction 
  108. will seem noticeably slower, particularly for 640x480 which has an 
  109. equivalent pixel aspect ratio of 1-to-1.  A vertical ratio of 8 will 
  110. cure this.  The lower the ratio, the farther the cursor will move for a 
  111. given mouse movement. Setting either ratio lower than 8 means that the 
  112. cursor cannot be located on every pixel.  For example, setting the ra-
  113. tio to 4 will cause the cursor to move 2 pixels for every mickey.  The 
  114. double-speed threshold is set by a call to SetSpeedThreshold().  When 
  115. the speed of the mouse (in mickeys per second) exceeds the speed para-
  116. meter passed to SetSpeedThreshold(), the motion speed of the cursor 
  117. will double.  A complete initialization might look like this:
  118.  
  119.     #include "mouse.h"
  120.     #include "cursor.h"
  121.  
  122.     main()
  123.     {
  124.       { initialize screen };
  125.       if(mouse.Exists())
  126.       {
  127.         mouse.SetGraphicsCursor(cross);
  128.         mouse.yLimit(0,479);    // VGA 640x480
  129.         mouse.MickToPix(8,8);
  130.         mouse.SetSpeedThreshold(32);
  131.         mouse.Enable();
  132.         mouse.Show();
  133.         ...
  134.       }
  135.     }
  136.  
  137.     The mouse should be reset before your program terminates so 
  138. that the calling program does not inherit any strange parameters.  This 
  139. is particularly true of the event handler.  Because it is an interrupt 
  140. routine, failure to reset the mouse could lead to a system crash if the 
  141. handler is still pointing to the address of what used to be your hand-
  142. ler routine.  The destructor Mouse::~Mouse() first resets the mouse 
  143. status by calling function 00h, and then restores the original event 
  144. handler with function 14h.
  145.  
  146. -----------------------------------------------------------------------
  147.  
  148. Reading the Mouse
  149.  
  150.     Most of the standard mouse functions stuff any return values 
  151. directly into the class variables and have a return type void.  You can 
  152. then use the appropriate inline function to read the required private 
  153. variable.  To check for the mouse position, for instance, you would 
  154. call Position() followed by either xPos() or yPos(), or both, such as:
  155.  
  156.     for(;;)
  157.     {
  158.       mouse.Position();
  159.       if(mouse.xPos() > 320 || mouse.yPos() > 100)
  160.         do_something();
  161.     }
  162.  
  163. This method has the advantage of capturing both the x and y positions 
  164. with a single function call, and those variables can then be read at 
  165. your leisure.  However, we generally don't care where the mouse is 
  166. located unless a button event that we are looking for has occurred.  
  167. Position() also returns the status of the mouse buttons, so we can also 
  168. check them:
  169.  
  170.     for(;;)
  171.     {
  172.       mouse.Position();
  173.       if(mouse.LB_Dn())        // check for left button down
  174.       {
  175.         if(mouse.xPos() > 320 || mouse.yPos() > 100)
  176.           do_something();
  177.       }
  178.       else
  179.         do_something_else();
  180.     }
  181.  
  182. This loop will continuously check to see if the left button has been 
  183. pressed.  If the do_something_else() code is slow then there is a pos-
  184. sibility that a button press could be missed since Position() returns 
  185. the real-time status of the mouse.  That is, during execution of the 
  186. do_something_else() code, the mouse button could be pressed and re-
  187. leased and Position() would not capture it.  The functions Pressed() 
  188. and Released() are best suited for checking for a button event because 
  189. they will return the button status since the last time they were called.
  190. For example, this code
  191.  
  192.     for(;;)
  193.     {
  194.       if(mouse.Pressed(LEFTBUTTON))
  195.       {
  196.         if(mouse.xPos() > 320 || mouse.yPos() > 100)
  197.         do_something();
  198.       }
  199.       else
  200.         do_something_else();
  201.     }
  202.  
  203. is guaranteed to capture a button press even if the do_something_else() 
  204. code is slow to execute.  Since Pressed() and Released() also return 
  205. the cursor position, a separate call to Position() is not necessary.
  206.  
  207.     In using the mouse, it is often necessary to know if the cursor 
  208. is located within a certain area of the screen.  For example, in a menu 
  209. interface, you want to know if the cursor is located on a menu selec-
  210. tion when a mouse button is clicked.  The function InBox() adds this 
  211. capability.  The parameters passed describe the upper left and lower 
  212. right corners of the box.  The return value is 1 if the cursor is in 
  213. the box, 0 if not.  Therefore, the code
  214.  
  215.     if(mouse.InBox(40,40,100,100))
  216.  
  217. will be true if the mouse cursor is in a box with corners (40,40) and 
  218. (100,100).  Like other mouse functions, the coordinates are pixels, 
  219. even if the screen is in text mode.
  220.  
  221.     In some cases you may want to hide the cursor if it falls in-
  222. side a certain area.  The mouse driver provides such a function which, 
  223. in my opinion, has two drawbacks.  Function 10h defines an exclusion 
  224. window in which the mouse cursor will turn itself off.  However, the 
  225. programmer must then manually turn the cursor back on once it is out-
  226. side the exclusion area, and this requires continuously checking the 
  227. mouse position, such as:
  228.  
  229.     for(;;)
  230.     {
  231.       mouse.Exclude(40,40,100,100);
  232.       do_some_processing();
  233.       if(!mouse.InBox(40,40,100,100))
  234.         mouse.show();
  235.     }
  236.  
  237. The other problem with function 10h is that it only looks at the hot 
  238. spot when checking the cursor's position, so part of the cursor could 
  239. enter the exclusion area before the hot spot.  The whole point of de-
  240. fining an exclusion area is to turn the cursor off if it enters the 
  241. defined area.  The Mouse++ Exclude() function is based on the InBox() 
  242. function, taking into account the hot spot location and cursor visi-
  243. bility.
  244.  
  245.     Finally, if your program is performing a time-consuming task in 
  246. which mouse input is not needed, you may want to disable the mouse.  If 
  247. the mouse is not disabled, the user might become frustrated with a mouse
  248. that does not respond, and the event buffer could become filled with 
  249. useless events.  Calling the function Disable() will turn the mouse off 
  250. and disable the interrupt handler.  The mouse and interrupt handler are 
  251. re-enabled with the next call to Enable(), although the mouse cursor 
  252. must be turned on with an explicit call to Show():
  253.  
  254.     ...
  255.     mouse.Disable();
  256.     do_some_long_processing();
  257.     mouse.Enable();
  258.     mouse.Show();
  259.     ...
  260.  
  261. -----------------------------------------------------------------------
  262.  
  263. Mouse Cursors
  264.  
  265.     SetGraphicsCursor() sets the graphics cursor shape.  The cursor 
  266. is initially set to the familiar upper left pointing arrow by the mouse 
  267. driver.  A graphics cursor is 16x16 pixels in size and moves in single 
  268. pixel increments.  It is defined by a screen mask (background), an over-
  269. lying cursor mask (foreground), and a hot spot.  Since the cursor is 
  270. 16x16 pixels, a hot spot must be defined so that a unique pixel posi-
  271. tion can be determined for the cursor.  The hot spot has x and y values 
  272. with valid ranges of 0 to 15.
  273.  
  274.     The two masks determine how the screen will appear where the 
  275. cursor is located.  The screen mask is first ANDed with the screen 
  276. pixels, and the cursor mask is then XORed with the resulting screen.  
  277. If a screen mask bit is 0 it will set the underlying screen pixel to 0 
  278. (black), and if the screen mask bit is 1 the pixel color will not 
  279. change.  A cursor mask bit of 0 does nothing, and a cursor mask bit of 
  280. 1 will invert the underlying pixel color.  Since the masks have only 
  281. values of 1 or 0 for each pixel location, but each pixel can have a 
  282. color, you cannot achieve complete control of the cursor color.  The 
  283. two basic choices are a black and white cursor where the screen mask 
  284. bits are 0, or a cursor that inverts the screen colors where the screen 
  285. mask bits are 1.
  286.  
  287.     Figure 1 shows the default cursor as an example.  The screen 
  288. mask alone will set the screen pixels to black for the bits that are 0, 
  289. creating a black arrow.  The cursor mask bits that are 1 will then in-
  290. vert the screen color, meaning black will become white.  If you lay the 
  291. cursor mask directly over the screen mask, you will notice that the 
  292. screen mask arrow extends one pixel beyond the cursor mask arrow.   Be-
  293. cause a screen mask bit 0 will create a black background for the cursor 
  294. mask, this has the effect of putting a one pixel black border around 
  295. the cursor.  The reason for doing this is to make the cursor visible 
  296. even where the screen is white.  Making the screen mask bits all 1's so 
  297. that the cursor XOR's with the underlying screen is useful in creating 
  298. a CAD cursor (such as a "+" or a "x") that must be one pixel wide.  The 
  299. best way to get a better understanding of the graphics cursor is to try 
  300. some out.  cursor.h defines several graphics cursors.
  301.  
  302. -----------------------------------------------------------------------
  303.  
  304.     0011111111111111    0000000000000000
  305.     0001111111111111    0100000000000000
  306.     0000111111111111    0110000000000000
  307.     0000011111111111    0111000000000000
  308.     0000001111111111    0111100000000000
  309.     0000000111111111    0111110000000000
  310.     0000000011111111    0111111000000000
  311.     0000000001111111    0111111100000000
  312.     0000000000111111    0111111110000000
  313.     0000000000011111    0111111111000000
  314.     0000000111111111    0111110000000000
  315.     0001000011111111    0100011000000000
  316.     0011000011111111    0000011000000000
  317.     1111100001111111    0000001100000000
  318.     1111100001111111    0000001100000000
  319.     1111110000111111    0000000110000000
  320.  
  321.       Screen Mask          Cursor Mask
  322.  
  323. Figure 1: Example graphics cursor
  324. -----------------------------------------------------------------------
  325.  
  326.     The graphics mask pair are defined together in a single array 
  327. of type unsigned integer.  For clarity, comment fields were added in 
  328. cursor.h to show what the masks will actually produce.  This is helpful 
  329. not only in identifying what a cursor looks like, but also in designing 
  330. new cursors.  Since the graphics cursor is a 16x16 pixel image, it also 
  331. requires a hot spot for determining the exact position of the mouse.  
  332. The hot spot and the mask array are combined in the structure 
  333. GraphicsCursor (defined in mouse.h), which must be static.  The cursor 
  334. structure can then be passed as a unit to SetGraphicsCursor().
  335.  
  336.     SetTextCursor() sets the text cursor type and shape.  There are 
  337. two cursor types in text mode.  The hardware cursor places the normal 
  338. video cursor (the cursor you see even without a mouse) under the con-
  339. trol of the mouse.  The software cursor is independent of the video 
  340. cursor and behaves similarly to the graphics cursor.  The software cur-
  341. sor is used in most applications so that the user is presented with the 
  342. normal video cursor for typing and a mouse cursor for menu selection.  
  343. The cursor type - 0 for software, 1 for hardware - is part of the 
  344. TextCursor structure.
  345.  
  346.     Like the graphics cursor, the text software cursor also re-
  347. quires a screen and cursor mask, but no hot spot since the cursor al-
  348. ways takes up a whole character cell, regardless of where the mouse 
  349. cursor is actually positioned in that cell.  (If a hardware cursor is 
  350. implemented, the starting and ending scan lines for the cursor are 
  351. required.)  The two masks operate only on a character cell, not a 16x16 
  352. pixel array.  Each cell consists of a one-byte character value and a 
  353. one-byte character attribute (which sets the foreground and background 
  354. colors), so the masks must each be two bytes long.  The upper byte 
  355. masks the attribute, and the lower byte masks the character.  Like the 
  356. graphics masks, the screen mask is XORed with the underlying character 
  357. cell, and the cursor mask is ANDed with the resulting value.  The dif-
  358. ference is that in text mode, both the character value and its color 
  359. can be changed, whereas in graphics mode, the pixel colors cannot be 
  360. controlled.
  361.  
  362.     To get a better understanding of what the masks will do, we 
  363. need to look at an example of a screen character:
  364.  
  365.       6B24h = 0110 1011 0010 0100 b
  366.               |--- ---- ---------
  367.               | |   |       |__ character value
  368.               | |   |__________ foreground color
  369.               | |______________ background color
  370.               |________________ blinking bit (1=blinking)
  371.  
  372. This value will display a '$' (24h) with a background color of brown 
  373. (06h) and a foreground color of lightcyan (0Bh = 11).  With the text 
  374. cursor, we can mask each bit of the character and attribute, so not 
  375. only can we set the mouse cursor character, but we can also control the 
  376. foreground and background colors (and even blinking).  The cursor masks 
  377. default to a reverse box, which is
  378.  
  379.     Screen Mask = 77FFh = 0111 0111 1111 1111 b
  380.     Cursor Mask = 7700h = 0111 0111 0000 0000 b
  381.  
  382. The first byte of the screen mask, 77h in this example, is ANDed with 
  383. the underlying characters attribute. The first 7h is ANDed with the 
  384. background color so that all colors but the blinking bit are passed 
  385. through.  Masking the blinking bit to 0 will allow the mouse cursor to 
  386. rest on a blinking character without itself blinking.  The second 7h is 
  387. ANDed with the foreground color so that those colors are also passed, 
  388. except that the high intensity colors will be converted to low inten-
  389. sity.  The FFh also passes the screen character.  In the cursor mask, 
  390. the 77h will invert both the foreground and background colors, while 
  391. the 00h creates an "empty" character, which is a character cell with 
  392. nothing in it (a box).
  393.  
  394.     If you want to create a cursor with a particular character and 
  395. color, you would set the screen mask to 0000h and the cursor mask to 
  396. whatever color and character values desired.  For example,
  397.  
  398.     Screen Mask = 0000h = 0000 0000 0000 0000b
  399.     Cursor Mask = 0F23h = 0000 1111 0010 0011b
  400.  
  401. will set the cursor character to a '#' with a background color of black 
  402. and a foreground color of white.  More complex combinations are possi-
  403. ble, such as setting the cursor's foreground color to a constant value 
  404. but allowing the screen's background color to show through.  Again, the 
  405. best way to understand it is to try it, and cursor.h defines several 
  406. text cursors.
  407.  
  408. -----------------------------------------------------------------------
  409.  
  410. The Event Handler
  411.  
  412.     There is another way to capture mouse events.  The mouse event 
  413. handler is similar to a TSR program in that it can be set up to capture 
  414. events in background.  The handler can be set to trigger off any combi-
  415. nation of mouse events (Table 1), and can then execute any user code, 
  416. providing it does not issue a DOS or I/O call.  However, since the main 
  417. program is suspended during the event handler execution, the handler 
  418. code should be fast so it does not to noticeably slow down the main pro-
  419. gram.  When an event occurs, certain mouse information is automatically 
  420. placed in the registers for the handler to use.  The routine Save() can 
  421. be used to stuff these parameters into the Mouse class for later use.  
  422. Any event handler routines you write must be declared as an interrupt 
  423. type and terminate with a far return.  The macro EventExit() provides 
  424. the proper exit code and should be the last statement in the handler 
  425. function:
  426.  
  427.     void interrupt my_handler()
  428.     {
  429.       mouse.Save();
  430.       do_something();
  431.       EventExit();
  432.     }
  433.  
  434.     Installing an event handler is accomplished with the function 
  435. InstallHandler():
  436.     
  437.     #include "mouse.h"
  438.  
  439.     void interrupt my_handler();
  440.     
  441.     main()
  442.     {
  443.       unsigned char eventmask = LB_PRESSED || LB_RELEASED;
  444.       if(mouse.Exists())
  445.       {
  446.         mouse.InstallHandler(eventmask, myhandler);
  447.         mouse.Show();
  448.         ...
  449.       }
  450.     }
  451.  
  452. eventmask determines which mouse events will trigger the event handler. 
  453. In the example above, the handler will execute whenever the left button 
  454. is pressed or released.  Because the event handler should be kept as 
  455. small as possible, you normally only want to call Save() for storing 
  456. the mouse information and then exit.  The mouse class provides such a 
  457. handler by default if you do not specify a handler function name in the 
  458. call to InstallHandler():
  459.  
  460.     main()
  461.     {
  462.       if(mouse.Exists())
  463.       {
  464.         mouse.InstallHandler(LB_PRESSED || LB_RELEASED);
  465.         mouse.Show();
  466.         ...
  467.       }
  468.     }
  469.  
  470. There might be some cases where you want the handler to do more, such 
  471. as when the program is waiting for user input and not doing much other 
  472. processing.  In such cases you may want to load different handlers, 
  473. depending on what the program is doing.  A more functional handler can 
  474. be loaded for pulldown menus, for instance, and a bare-bones handler 
  475. (or none at all) can be installed in speed critical areas where the 
  476. mouse has little use.
  477.  
  478.     The Save() function called by the event handler stores the 
  479. mouse information in a buffer instead of writing it directly into the 
  480. class.  This allows events to be captured even while your program is 
  481. busy doing something else.  (The keyboard has a similar buffer that 
  482. provides type-ahead capability.)  To get the event information out of 
  483. the buffer, you must call the function GetEvent():
  484.  
  485.     for(;;)
  486.     {
  487.       mouse.GetEvent();        // get an event from the buffer
  488.       if(mouse.LB_Dn())        // check for left button down
  489.       {
  490.         if(mouse.xPos() > 320 || mouse.yPos() > 100)
  491.           do_something();
  492.       }
  493.       else
  494.         do_something_else();
  495.     }
  496.  
  497.     Properly used, event handlers can add a whole new dimension to 
  498. a mouse driven interface.  However, there are some pitfalls to avoid.  
  499. If you set the event mask to trigger on mouse movement, then the hand-
  500. ler will execute quite often (every time the mouse is moved) and could 
  501. noticeably slow program execution during periods of heavy computation.  
  502. Usually, the only reason to trigger on movement is to update a motion 
  503. counter such as in the demo program, or to have cursors that dynami-
  504. cally change depending on the cursor position such as in a GUI.  As 
  505. mentioned before, the handler should not issue a DOS, ROM, or I/O call. 
  506. The handler, like a TSR, is an interrupt routine that runs while the 
  507. main DOS program is suspended.  DOS is not a re-entrant operating sys-
  508. tem and issuing such a call will usually crash the system.  Also, some 
  509. standard C library routines make use of these system functions (such as 
  510. printf()), so often the only way of finding out is by trial and reboot.
  511.  
  512. -----------------------------------------------------------------------
  513.     0x01    MOUSE_MOVED
  514.     0x02    LB_PRESSED
  515.     0x04    LB_RELEASED
  516.     0x08    RB_PRESSED
  517.     0x10    RB_RELEASED
  518.     0x20    CB_PRESSED
  519.     0x40    CB_RELEASED
  520.     
  521.     Table 1: Mouse events
  522. -----------------------------------------------------------------------
  523.  
  524. A Demonstration
  525.  
  526.     micedemo.cpp is a demo program that utilizes most of the mouse 
  527. functions described.  main() installs the event handler, runs a text 
  528. mode demo, and a graphics mode demo.  The event mask is FFh which will 
  529. trigger the handler on any mouse event.  Since that includes mouse 
  530. movement, the default handler that only calls Save() is used to store 
  531. the parameters and keep execution time to a minimum.
  532.  
  533.     Both demos (textdemo() and graphicdemo()) call a function that 
  534. draws the screen and another that processes mouse events.  textscreen() 
  535. assumes a color video card and draws a screen with eight different 
  536. characters and colors to demonstrate how the cursor masks work.  Notice 
  537. that the loop that draws the screen actually writes 50 lines of video 
  538. even though the demo starts out with 25 lines.  A graphical represen-
  539. tation of a three-button mouse is drawn to show the cursor position and 
  540. button status.  After calling textscreen(), textdemo() prints the infor-
  541. mation from the mouse.Info structure to the screen.  The mouse y-limit 
  542. is set to full screen (25 lines, which is the default) and the cursor 
  543. is turned on with Show().  nexttdemo() is the processing loop for text 
  544. mode and is called with the name of text cursor structure and a title 
  545. string.  nexttdemo() is called with several different cursors and also 
  546. for 43/50 line mode.
  547.  
  548.     nexttdemo() first sets the text cursor and prints the title 
  549. string.  It then runs a loop that process mouse events.  A counter that 
  550. shows the mouse position calls xPos() and yPos() which read variables 
  551. that are continuously updated by the event handler via GetEvent().  
  552. Button status is also checked and displayed.  Released() is called to 
  553. check for a left button release event which will terminate the loop if 
  554. the cursor is inside the [Next] box at the time of release.  The loop 
  555. will also be terminated if the left button is double-clicked anywhere 
  556. on the screen.  If the right button is double-clicked, the mouse is 
  557. disabled until any keyboard key is pressed.  Pressing the <Ctrl> key 
  558. and the left button will set the global flag "done" which exits the 
  559. rest of the text demo and proceeds with the graphics demo.
  560.  
  561.     graphicdemo() works the same way as textdemo().  In addition to trying several cursors, it also tests different mickey-to-pixel ratios.  Notice that the ratio of 2 for the jet cursor will cause the cursor to locate on every fourth pixel as it moves across the screen.  graphicscreen() paints several background colors as well as black and white boxes in the center.  These boxes demonstrate the use of the cursor border created by the screen mask.  A graphical representation of a three-button mouse is again drawn to show the cursor position and button status.  nextgdemo() sets the graphics cursor and then processes mouse events, checking the position and button status.  
  562.  
  563.     The variables LBDN, CBDN, and RBDN are used to compare the cur-
  564. rent button status against the previous button status.  The color of 
  565. the screen buttons are then toggled if any button status has changed.  
  566. (This method is used to avoid screen paints in every pass through the 
  567. loop if the button status has not changed.  This is not necessary in 
  568. text mode because screen writes are much faster.)  Buttons are checked 
  569. for multi-clicks (up to four) and the color of the screen buttons will 
  570. reflect this.  Finally, we check for a left button release and see if 
  571. the cursor is in the [Next] box, a left button triple-click, and a 
  572. <Ctrl>-left button, and exit if so.
  573.  
  574. -----------------------------------------------------------------------
  575.  
  576. The Mouse++ Functions
  577.  
  578. -----------------------------------------------------------------------
  579. Mouse::Exists()
  580.  
  581. Syntax:     unsigned char Exists(void)
  582. Description:    Returns the value of an internal flag that is set by
  583.         the Mouse constructor.
  584. Return Value:    1 if a mouse was found, 0 otherwise.
  585.  
  586. -----------------------------------------------------------------------
  587. Mouse::Visible()
  588.  
  589. Syntax:     unsigned char Visible(void)
  590. Description:    Returns the status of the cursor visibility.
  591. Return Value:    1 if the cursor is visible, 0 otherwise.
  592.  
  593. -----------------------------------------------------------------------
  594. Mouse::Buttons()
  595.  
  596. Syntax:     unsigned char Buttons(void)
  597. Description:    Returns the number of buttons for the mouse
  598. Return Value:    2 for a 2-button mouse, 3 for a 3-button mouse.
  599.  
  600. -----------------------------------------------------------------------
  601. Mouse::Button()
  602.  
  603. Syntax:     unsigned char Button(void)
  604. Description:    Returns the status of the mouse buttons and shift keys 
  605.         that is stored internal to the Mouse class. Call 
  606.         Position() before using this function to insure an 
  607.         accurate value, or when using the event handler call 
  608.         GetEvent().
  609. Return Value:    A mask corresponding to the status of the mouse buttons
  610.         and the shift keys (down=1, up=0):
  611.         -------------------------------------------------------
  612.         0x01    Left button
  613.         0x02    Right button
  614.         0x04    Center button
  615.         0x08    Either shift key
  616.         0x10    Right shift key
  617.         0x20    Left shift key
  618.         0x40    Alt key
  619.         0x80    Ctrl key
  620.  
  621. -----------------------------------------------------------------------
  622. Mouse::Enable()
  623.  
  624. Syntax:     void Enable(void)
  625. Description:    Enables the mouse. This function must be called before 
  626.         the mouse can be used for the first time, or after a 
  627.         call to Disable(). A separate call to Show() is neces-
  628.         sary to display the cursor.
  629. Return Value:    None.
  630.  
  631. -----------------------------------------------------------------------
  632. Mouse::Disable()
  633.  
  634. Syntax:     void Disable(void)
  635. Description:    Disables the mouse and hides the cursor. If an event 
  636.         handler has been installed, it is disabled and the 
  637.         event buffer and multi-click buffer are cleared.
  638. Return Value:    None.
  639.  
  640. -----------------------------------------------------------------------
  641. Mouse::Show()
  642.  
  643. Syntax:     void Show(void)
  644. Description:    Turns on the mouse cursor.
  645. Return Value:    None. Sets the internal visible flag to 1.
  646.  
  647. -----------------------------------------------------------------------
  648. Mouse::Hide()
  649.  
  650. Syntax:     void Hide(void)
  651. Description:    Turns off the mouse cursor. All other mouse functions
  652.         will continue to operate. You should hide the cursor
  653.         prior to any screen writes to avoid having the mouse
  654.         restore an incorrect background.
  655. Return Value:    None. Sets the internal visible flag to 0.
  656.  
  657. -----------------------------------------------------------------------
  658. Mouse::Position()
  659.  
  660. Syntax:     void Position(void)
  661. Description:    Reads the cursor position and saves the coordinates
  662.         in internal variables. Use xPos() & yPos() to read
  663.         the internal variables. This function is not intended 
  664.         for use with the event handler.
  665. Return Value:    None. Sets internal class position variables and button 
  666.         status.
  667.  
  668. -----------------------------------------------------------------------
  669. Mouse::xPos()
  670.  
  671. Syntax:     int xPos(void)
  672. Description:    Returns the x-position of the mouse cursor that is
  673.         stored internal to the Mouse class. Call Position()
  674.         before using this function to insure an accurate
  675.         value, or when using the event handler call GetEvent().
  676. Return Value:    An integer that corresponds to the pixel location of
  677.         the cursor, even if the screen is in text mode.
  678.  
  679. -----------------------------------------------------------------------
  680. Mouse::yPos()
  681.  
  682. Syntax:     int yPos(void)
  683. Description:    Returns the y-position of the mouse cursor that is
  684.         stored internal to the Mouse class. Call Position()
  685.         before using this function to insure an accurate
  686.         value, or when using the event handler call GetEvent().
  687. Return Value:    An integer that corresponds to the pixel location of
  688.         the cursor, even if the screen is in text mode.
  689.  
  690. -----------------------------------------------------------------------
  691. Mouse::Motion()
  692.  
  693. Syntax:     void Motion(void)
  694. Description:    Reads the internal motion counters which give the dis-
  695.         tance (in mickeys) the mouse has moved since the last 
  696.         call to this function, and stores the values in class 
  697.         variables. Use xCount() & yCount() to read these vari-
  698.         ables. This function is not intended for use with the 
  699.         event handler.
  700. Return Value:    None.
  701.  
  702. -----------------------------------------------------------------------
  703. Mouse::xCount()
  704.  
  705. Syntax:     int xCount(void)
  706. Description:    Returns the distance the mouse has moved in the x-
  707.         direction. The distance is in mickeys, which may or may 
  708.         not be the same as pixels, depending on the mickey-to-
  709.         pixel ratio. This function is useful for seeing if the 
  710.         mouse has moved.
  711. Return Value:    An integer that corresponds to the x distance in mic-
  712.         keys, regardless of screen mode.
  713.  
  714. -----------------------------------------------------------------------
  715. Mouse::yCount()
  716.  
  717. Syntax:     int yCount(void)
  718. Description:    Returns the distance the mouse has moved in the y-
  719.         direction. The distance is in mickeys, which may or may 
  720.         not be the same as pixels, depending on the mickey-to-
  721.         pixel ratio. This function is useful for seeing if the 
  722.         mouse has moved.
  723. Return Value:    An integer that corresponds to the y distance in mic-
  724.         keys, regardless of screen mode.
  725.  
  726. -----------------------------------------------------------------------
  727. Mouse::Move()
  728.  
  729. Syntax:     void Move(int x, int y)
  730. Description:    Moves the cursor to a new position. x & y must be 
  731.         pixel coordinates even if the screen is in text mode.
  732. Return Value:    None.
  733.  
  734. -----------------------------------------------------------------------
  735. Mouse::Pressed()
  736.  
  737. Syntax:     int Pressed(int mbutton)
  738. Description:    In manual mode, this checks to see if mbutton has been 
  739.         pressed since the last call to this command. In event 
  740.         driven mode, this checks to see if the current event 
  741.         was triggered by mbutton pressed. mbutton can be 0 
  742.         (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  743. Return Value:    1 if mbutton has a pressed event, 0 otherwise.
  744.  
  745. -----------------------------------------------------------------------
  746. Mouse::Released()
  747.  
  748. Syntax:        int Released(int mbutton)
  749. Description:    In manual mode, this checks to see if mbutton has been 
  750.         released since the last call to this command. In event 
  751.         driven mode, this checks to see if the current event 
  752.         was triggered by mbutton released. mbutton can be 0 
  753.         (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  754. Return Value:    1 if mbutton has a released event, 0 otherwise.
  755.  
  756. -----------------------------------------------------------------------
  757. Mouse::LB_Dn()
  758.  
  759. Syntax:     unsigned char LB_Dn(void)
  760. Description:    Returns the status of the left button.
  761. Return Value:    1 if the left button is pressed, 0 otherwise.
  762.  
  763. -----------------------------------------------------------------------
  764. Mouse::RB_Dn()
  765.  
  766. Syntax:     unsigned char RB_Dn(void)
  767. Description:    Returns the status of the right button.
  768. Return Value:    1 if the right button is pressed, 0 otherwise.
  769.  
  770. -----------------------------------------------------------------------
  771. Mouse::CB_Dn()
  772.  
  773. Syntax:     unsigned char CB_Dn(void)
  774. Description:    Returns the status of the center button.
  775. Return Value:    1 if the center button is pressed, 0 otherwise.
  776.  
  777. -----------------------------------------------------------------------
  778. Mouse::xLimit()
  779.  
  780. Syntax:     void xLimit(int min, int max)
  781. Description:    Sets the limit that the cursor can move in the x-
  782.         direction. min & max must be pixel values even if the
  783.         screen is in text mode.
  784. Return Value:    None.
  785.  
  786. -----------------------------------------------------------------------
  787. Mouse::yLimit()
  788.  
  789. Syntax:     void yLimit(int min, int max)
  790. Description:    Sets the limit that the cursor can move in the y-
  791.         direction. min & max must be pixel values even if the
  792.         screen is in text mode.
  793. Return Value:    None.
  794.  
  795. -----------------------------------------------------------------------
  796. Mouse::SetTextCursor()
  797.  
  798. Syntax:     void SetTextCursor(TextCursor& cursor)
  799. Description:    Sets the text cursor as described by the TextCursor 
  800.         structure.
  801. Return Value:    None.
  802.  
  803. -----------------------------------------------------------------------
  804. Mouse::SetGraphicsCursor()
  805.  
  806. Syntax:     void SetGraphicsCursor(GraphicsCursor& cursor)
  807. Description:    Sets the graphics cursor as described by the 
  808.         GraphicsCursor structure.
  809. Return Value:    None.
  810.  
  811. -----------------------------------------------------------------------
  812. Mouse::MickToPix()
  813.  
  814. Syntax:     void MickToPix(int horiz, int vert)
  815. Description:    Sets the mickey-to-pixel ratio. A mickey is a motion 
  816.         signal sent by the mouse and occurs every 1/200th inch 
  817.         for most mice. horiz passes the number of mickeys re-
  818.         quired for an 8 pixel horizontal movement, and vert 
  819.         passes the number of mickeys required for an 8 pixel 
  820.         vertical movement. The constructor sets these to 8 and 
  821.         16, respectively.
  822. Return Value:    None.
  823.  
  824. -----------------------------------------------------------------------
  825. Mouse::SetSpeedThreshold()
  826.  
  827. Syntax:     void SetSpeedThreshold(unsigned speed)
  828. Description:    Sets the threshold at which the cursor speed doubles. 
  829.         speed is in mickeys-per-second and defaults to 64. 
  830.         Supposedly, this function is only available for Logi-
  831.         tech mice.
  832. Return Value:    None.
  833.  
  834. -----------------------------------------------------------------------
  835. Mouse::SetClickThreshold()
  836.  
  837. Syntax:     void SetClickThreshold(unsigned time)
  838. Description:    Sets the threshold at which sequential clicks are regi-
  839.         stered as multi-clicks. time is in milliseconds and de-
  840.         faults to 250.
  841. Return Value:    None.
  842.  
  843. -----------------------------------------------------------------------
  844. Mouse::MultiClick()
  845.  
  846. Syntax:     int MultiClick(int mbutton)
  847. Description:    Checks for multi-clicks of button mbutton. mbutton can 
  848.         be 0 (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  849. Return Value:    Current number of multi-clicks.
  850.  
  851. -----------------------------------------------------------------------
  852. Mouse::DoubleClick()
  853.  
  854. Syntax:     int DoubleClick(int mbutton)
  855. Description:    Checks for double-clicks of button mbutton. mbutton can 
  856.         be 0 (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  857. Return Value:    1 if mbutton has been double-clicked, 0 otherwise.
  858.  
  859. -----------------------------------------------------------------------
  860. Mouse::ClearClick()
  861.  
  862. Syntax:     void ClearClick(int mbutton)
  863. Description:    Resets the multi-click status of mbutton. mbutton can 
  864.         be 0 (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  865. Return Value:    None.
  866.  
  867. -----------------------------------------------------------------------
  868. Mouse::InBox()
  869.  
  870. Syntax:     int InBox(int left, int top, int right, int bottom)
  871. Description:    Checks if the mouse cursor is located within a rec-
  872.         tangle. Rectangle limits should be in pixels regardless 
  873.         of screen mode.
  874. Return Value:    1 if the cursor is in the rectangle, 0 otherwise.
  875.  
  876. -----------------------------------------------------------------------
  877. Mouse::Exclude()
  878.  
  879. Syntax:     void Exclude(int left, int top, int right, int bottom)
  880. Description:    Sets up an exclusion area in which the mouse cursor 
  881.         automatically turns itself off. This is not the same as 
  882.         the exclude function that is built into the mouse, and 
  883.         must be continuously called in a loop. Rectangle limits 
  884.         should be in pixels regardless of screen mode.
  885. Return Value:    None.
  886.  
  887. -----------------------------------------------------------------------
  888. Mouse::InstallHandler()
  889.  
  890. Syntax:     void InstallHandler(unsigned mask, 
  891.                     void interrupt (*fn)(void))
  892. Description:    Installs an interrupt handler function. This function 
  893.         is automatically run whenever an event occurs that is 
  894.         included in the mask. The mouse driver loads the CPU 
  895.         registers with mouse information before calling the 
  896.         function. Therefore, the first action should be to save 
  897.         this information to an event buffer, which can be accom-
  898.         plished by calling the Save() function. The remaining 
  899.         function code should be kept to a minimum, and the func-
  900.         tion MUST be terminated with the EventExit() macro. The 
  901.         mask bits are described in Table X. If a function poin-
  902.         ter is not passed in the parameter list, then the de-
  903.         fault handler MouseHandler() will be used.
  904. Return Value:    None.
  905.  
  906. -----------------------------------------------------------------------
  907. Mouse::Save()
  908.  
  909. Syntax:     void Save(int event, int button, int x, int y,
  910.               int xcount, int ycount)
  911. Description:    Stores the passed parameters in the event buffer. This 
  912.         should be the first function called from an event hand-
  913.         ler routine. See the default handler MouseHandler() for 
  914.         details.
  915. Return Value:    None.
  916.  
  917. -----------------------------------------------------------------------
  918. Mouse::GetEvent
  919.  
  920. Syntax:     void GetEvent(void)
  921. Description:    Gets the next event from the event buffer and loads the 
  922.         parameters into class variables.
  923. Return Value:    None.
  924.  
  925. -----------------------------------------------------------------------
  926. Mouse::ClearEvent
  927.  
  928. Syntax:     void ClearEvent(void)
  929. Description:    Clears the current event from the internal class varia-
  930.         bles.
  931. Return Value:    None.
  932.  
  933. -----------------------------------------------------------------------
  934. Mouse::ClearBuffer()
  935.  
  936. Syntax:     void ClearBuffer(void)
  937. Description:    Clears the event buffer.
  938. Return Value:    None.
  939.  
  940. -----------------------------------------------------------------------
  941.  
  942. References
  943. 1.  Kent Porter, "Mouse Mysteries, Part I: Text", Turbo 
  944.     Technix, Vol. 1, No. 4, pp. 52-67, May/June 1988.
  945. 2.  Kent Porter, "Mouse Mysteries, Part II: Graphics", Turbo 
  946.     Technix, Vol. 1, No. 5, pp. 42-53, July/August 1988.
  947. 3.  Terry Dettmann, DOS Programmers Reference, Part V: 
  948.     Reference, Mouse Functions, pp. 717-739, Que, 1989.
  949. 4.  Ralf Brown, Interrupt List, Release 90.3, July 15, 1990.  
  950.     This is available on the Public Domain as INTER390.
  951.