home *** CD-ROM | disk | FTP | other *** search
/ HomeWare 14 / HOMEWARE14.bin / prog / pcgpe10.arj / MOUSE.TXT < prev    next >
Text File  |  1994-05-10  |  10KB  |  296 lines

  1.                     ┌─────────────────────────────────┐
  2.                     │ Programming the Microsoft Mouse │
  3.                     └─────────────────────────────────┘
  4.  
  5.                  Written for the PC-GPE by Mark Feldman
  6.               e-mail address : u914097@student.canberra.edu.au
  7.                                myndale@cairo.anu.edu.au
  8.  
  9.               ┌───────────────────────────────────────────┐
  10.               │      THIS FILE MAY NOT BE DISTRIBUTED     │
  11.               │ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. │
  12.               └───────────────────────────────────────────┘
  13.  
  14.  
  15. ┌────────────┬───────────────────────────────────────────────────────────────
  16. │ Disclaimer │
  17. └────────────┘
  18.  
  19. I assume no responsibility whatsoever for any effect that this file, the
  20. information contained therein or the use thereof has on you, your sanity,
  21. computer, spouse, children, pets or anything else related to you or your
  22. existance. No warranty is provided nor implied with this information.
  23.  
  24. ┌──────────────┬─────────────────────────────────────────────────────────────
  25. │ Introduction │
  26. └──────────────┘
  27.  
  28. A complete list of mouse function calls can be found in the file GMOUSE.TXT,
  29. the file contains calls for both Microsoft (2 button) and Genius (3 button)
  30. modes.
  31.  
  32. Calling these functions from within a Pascal program is a fairly simple
  33. matter. This procedure would get the mouse position and button states:
  34.  
  35. const MOUSEINTR = $33;
  36.  
  37. procedure GetMousePos(var x, y : word; var button1, button2 : boolean);
  38. var regs : registers;
  39. begin
  40.   regs.ax := 3;
  41.   Intr(MOUSEINTR, regs);
  42.   x := regs.cx;
  43.   y := regs.dx;
  44.   button1 := (regs.bx and 1) <> 0;
  45.   button2 := (regs.bx and 2) <> 0;
  46. end;
  47.  
  48.  
  49. The mouse position is returned in variables x and y, the button states are
  50. returned in variable button1 and button2 (true = button is pressed).
  51.  
  52.  
  53. ┌─────────────────────────┬──────────────────────────────────────────────────
  54. │ Writing Custom Handlers │
  55. └─────────────────────────┘
  56.  
  57. Most mouse drivers do not support SVGA modes, so you must write custom
  58. handlers if you want mouse support for these modes.
  59.  
  60. Rather than writing an entire mouse driver, you can write a simple handler
  61. routine to take care of the graphics and tell the mouse driver to call it
  62. whenever the mouse does anything. This function is descibed in the GMOUSE.DOC
  63. file, but this demo Pascal program shows the general idea. It sets mode 13h,
  64. resets the mouse and waits for a key to be pressed. Whenever you do anything
  65. to the mouse (moving it or pressing a button) the handler will get called
  66. and it will draw a pixel on the screen. The color of the pixel depends on
  67. which buttons are being pressed.
  68.  
  69. Uses Crt, Dos;
  70.  
  71. {$F+}
  72. { called with bl = buttons, cx = x * 2, dx = y }
  73. procedure Handler; far; assembler;
  74. asm
  75.  
  76.   { This mouse "handler" just draws a pixel at the current mouse pos }
  77.   pusha
  78.   mov ax, $A000
  79.   mov es, ax
  80.   shr cx, 1
  81.   xchg dh, dl
  82.   mov di, dx
  83.   shr dx, 2
  84.   add di, dx
  85.   add di, cx
  86.   mov al, bl
  87.   inc al
  88.   stosb
  89.   popa
  90. end;
  91. {$F-}
  92.  
  93. begin
  94.   asm
  95.  
  96.     { Set graphics mode 13h }
  97.     mov ax, $13
  98.     int $10
  99.  
  100.     { Initialize mouse driver }
  101.     xor ax, ax
  102.     int $33
  103.  
  104.     { Install custom handler }
  105.     mov ax, SEG Handler
  106.     mov es, ax
  107.     mov dx, OFS Handler
  108.     mov ax, 12
  109.     mov cx, $1F
  110.     int $33
  111.  
  112.     { Wait for a key press }
  113.     xor ah, ah
  114.     int $16
  115.  
  116.     { Back to text mode }
  117.     mov ax, 3
  118.     int $10
  119.   end;
  120. end.
  121.  
  122.  
  123.  
  124.  
  125. Alternatively you may wish to write your own interrupt handler to process
  126. mouse events as they happen. When a mouse event occurs, 3 interrupts are
  127. generated and the bytes are availble via the COM port.
  128.  
  129.                   ┌──────────────────────────┐
  130.                   │        Interrupt    Port │
  131.                   ├──────────────────────────┤
  132.                   │ COM1      $0C       $3F8 │
  133.                   │ COM2      $0B       $3F8 │
  134.                   └──────────────────────────┘
  135.  
  136. The three bytes sent are formatted as follows:
  137.  
  138.  
  139.                1st byte        2nd byte         3rd byte
  140.           ┌─┬─┬─┬─┬─┬─┬─┬─┐┌─┬─┬─┬─┬─┬─┬─┬─┐┌─┬─┬─┬─┬─┬─┬─┬─┐
  141.           │-│1│?│?│X│X│Y│Y││-│0│X│X│X│X│X│X││-│0│Y│Y│Y│Y│Y│Y│
  142.           └─┴─┴─┴─┴─┴─┴─┴─┘└─┴─┴─┴─┴─┴─┴─┴─┘└─┴─┴─┴─┴─┴─┴─┴─┘
  143.                │ │ └┬┘ └┬┘      └────┬────┘      └────┬────┘
  144.                │ │  │   │            │                │
  145.                │ │  │   └────────────┼────────┐       │
  146.                │ │  └────────┐       │        │       │
  147.                │ │          ┌┴┐ ┌────┴────┐  ┌┴┐ ┌────┴────┐
  148.                │ │         ┌─┬─┬─┬─┬─┬─┬─┬─┐┌─┬─┬─┬─┬─┬─┬─┬─┐
  149.                │ │         │ │ │ │ │ │ │ │ ││ │ │ │ │ │ │ │ │
  150.  Left Button ──┘ │         └─┴─┴─┴─┴─┴─┴─┴─┘└─┴─┴─┴─┴─┴─┴─┴─┘
  151. Right Button ────┘            X increment      Y increment
  152.  
  153.  
  154. The X and Y increment values are in 2's compliment signed char format. (BTW
  155. thanks go to Adam Seychell for posting this info to comp.os.msdos.programmer).
  156.  
  157.  
  158. A simple Borland Pascal 7.0 mouse handler follows. First we declare a few
  159. things we'll need:
  160.  
  161.  
  162. ─────────────────────────────────────────────────────────────────────┐
  163. Uses Crt, Dos;
  164.  
  165. {$F+}
  166.  
  167. const COM1INTR = $0C;
  168.       COM1PORT = $3F8;
  169.  
  170. var bytenum : word;
  171.     combytes : array[0..2] of byte;
  172.     x, y : longint;
  173.     button1, button2 : boolean;
  174.     MouseHandler : procedure;
  175. ─────────────────────────────────────────────────────────────────────┘
  176.  
  177. The bytenum variable is used to keep track of which byte is expected next
  178. (ie 0, 1 or 2). The combytes variable is simply an array to keep track of
  179. bytes received so far. The mouse position will be stored in the x and y
  180. varaibles (note that this example will not perfrom any range checking).
  181. Button1 and button2 will be used to store the states of each of the buttons.
  182. MouseHandler will be used to store the normal mouse driver event handler.
  183. We'll need it to reset everything once we are finished.
  184.  
  185. Here's the actual handler:
  186.  
  187. ─────────────────────────────────────────────────────────────────────┐
  188. procedure MyMouseHandler; Interrupt;
  189. var dx, dy : integer;
  190. var inbyte : byte;
  191. begin
  192.  
  193.   { Get the port byte }
  194.   inbyte := Port[COM1PORT];
  195.  
  196.   { Make sure we are properly "synched" }
  197.   if (inbyte and 64) = 64 then bytenum := 0;
  198.  
  199.   { Store the byte and adjust bytenum }
  200.   combytes[bytenum] := inbyte;
  201.   inc(bytenum);
  202.  
  203.   { Have we received all 3 bytes? }
  204.   if bytenum = 3 then
  205.     begin
  206.       { Yes, so process them }
  207.       dx := (combytes[0] and 3) shl 6 + combytes[1];
  208.       dy := (combytes[0] and 12) shl 4 + combytes[2];
  209.       if dx >= 128 then dx := dx - 256;
  210.       if dy >= 128 then dy := dy - 256;
  211.       x := x + dx;
  212.       y := y + dy;
  213.       button1 := (combytes[0] And 32) <> 0;
  214.       button2 := (combytes[0] And 16) <> 0;
  215.  
  216.       { And start on first byte again }
  217.       bytenum := 0;
  218.     end;
  219.  
  220.   { Acknowledge the interrupt }
  221.   Port[$20] := $20;
  222. end;
  223. ─────────────────────────────────────────────────────────────────────┘
  224.  
  225. Once again pretty simple stuff. We just read the byte from the com1 port and
  226. figure out if it's time to do anything yet. If bit 6 is set to 1 then we
  227. know that it's meant to be the first byte of the 3, so we reset our
  228. bytenum variable to zero (in a perfect world bytes would always come in 3's
  229. and we would never need to check, but it never hurts to be careful).
  230.  
  231. When 3 bytes have been received we simple decode them according to the
  232. diagram above and update the appropriate variables accordingly.
  233.  
  234. The 'Port[$20] := $20;' command just lets the interrupt controller know we
  235. have processed the interrupt so it can send us the next one when it wants to.
  236.  
  237. Note that the above "handler" does nothing more than keep track of the
  238. current mouse position and button states. If we were writing a proper mouse
  239. driver for an SVGA game we would also have to write custom cursor routines.
  240. I'll leave that bit to you!
  241.  
  242. To actually install our mouse driver we'll have to set up all the variables,
  243. save the address of the current mouse handler and install our own. We'll
  244. also need call the existing mouse driver to set up the COM1 port to make
  245. sure it sends us the mouse bytes as it receives them. We could do this
  246. ourselves, but why make life harder than it already is?
  247.  
  248. ─────────────────────────────────────────────────────────────────────┐
  249. procedure InitMyDriver;
  250. begin
  251.  
  252.   { Initialize the normal mouse handler }
  253.   asm
  254.     mov ax, 0
  255.     int $33
  256.   end;
  257.  
  258.   { Initialize some of the variables we'll be using }
  259.   bytenum := 0;
  260.   x := 0;
  261.   y := 0;
  262.   button1 := false;
  263.   button2 := false;
  264.  
  265.   { Save the current mouse handler and set up our own }
  266.   GetIntVec(COM1INTR, @MouseHandler);
  267.   SetIntVec(COM1INTR, Addr(MyMouseHandler));
  268. end;
  269. ─────────────────────────────────────────────────────────────────────┘
  270.  
  271.  
  272. And finally when our program is finished it'll need to clean up after
  273. itself and return control back to the normal mouse driver:
  274.  
  275. ─────────────────────────────────────────────────────────────────────┐
  276. procedure CleanUpMyDriver;
  277. begin
  278.   SetIntVec(COM1INTR, @MouseHandler);
  279. end;
  280. ─────────────────────────────────────────────────────────────────────┘
  281.  
  282.  
  283. This little bit of source will test the above code. It does nothing more
  284. than repeatedly write the mouse position and button states to the screen
  285. until a keyboard key is pressed:
  286.  
  287. ─────────────────────────────────────────────────────────────────────┐
  288. begin
  289.   ClrScr;
  290.   InitMyDriver;
  291.   while not keypressed do
  292.     WriteLn(x : 5, y : 5, button1 : 7, button2 : 7);
  293.   CleanUpMyDriver;
  294. end.
  295. ─────────────────────────────────────────────────────────────────────┘
  296.