1 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
\r
2 ³ Programming the Microsoft Mouse ³
\r
3 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r
5 Written for the PC-GPE by Mark Feldman
\r
6 e-mail address : u914097@student.canberra.edu.au
\r
7 myndale@cairo.anu.edu.au
\r
9 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
\r
10 ³ THIS FILE MAY NOT BE DISTRIBUTED ³
\r
11 ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³
\r
12 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r
15 ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
\r
19 I assume no responsibility whatsoever for any effect that this file, the
\r
20 information contained therein or the use thereof has on you, your sanity,
\r
21 computer, spouse, children, pets or anything else related to you or your
\r
22 existance. No warranty is provided nor implied with this information.
\r
24 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
\r
28 A complete list of mouse function calls can be found in the file GMOUSE.TXT,
\r
29 the file contains calls for both Microsoft (2 button) and Genius (3 button)
\r
32 Calling these functions from within a Pascal program is a fairly simple
\r
33 matter. This procedure would get the mouse position and button states:
\r
35 const MOUSEINTR = $33;
\r
37 procedure GetMousePos(var x, y : word; var button1, button2 : boolean);
\r
38 var regs : registers;
\r
41 Intr(MOUSEINTR, regs);
\r
44 button1 := (regs.bx and 1) <> 0;
\r
45 button2 := (regs.bx and 2) <> 0;
\r
49 The mouse position is returned in variables x and y, the button states are
\r
50 returned in variable button1 and button2 (true = button is pressed).
\r
53 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
\r
54 ³ Writing Custom Handlers ³
\r
55 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r
57 Most mouse drivers do not support SVGA modes, so you must write custom
\r
58 handlers if you want mouse support for these modes.
\r
60 Rather than writing an entire mouse driver, you can write a simple handler
\r
61 routine to take care of the graphics and tell the mouse driver to call it
\r
62 whenever the mouse does anything. This function is descibed in the GMOUSE.DOC
\r
63 file, but this demo Pascal program shows the general idea. It sets mode 13h,
\r
64 resets the mouse and waits for a key to be pressed. Whenever you do anything
\r
65 to the mouse (moving it or pressing a button) the handler will get called
\r
66 and it will draw a pixel on the screen. The color of the pixel depends on
\r
67 which buttons are being pressed.
\r
72 { called with bl = buttons, cx = x * 2, dx = y }
\r
73 procedure Handler; far; assembler;
\r
76 { This mouse "handler" just draws a pixel at the current mouse pos }
\r
96 { Set graphics mode 13h }
\r
100 { Initialize mouse driver }
\r
104 { Install custom handler }
\r
105 mov ax, SEG Handler
\r
107 mov dx, OFS Handler
\r
112 { Wait for a key press }
\r
116 { Back to text mode }
\r
125 Alternatively you may wish to write your own interrupt handler to process
\r
126 mouse events as they happen. When a mouse event occurs, 3 interrupts are
\r
127 generated and the bytes are availble via the COM port.
\r
129 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
\r
131 ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
\r
134 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r
136 The three bytes sent are formatted as follows:
\r
139 1st byte 2nd byte 3rd byte
\r
140 ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿
\r
141 ³-³1³?³?³Y³Y³X³X³³-³0³X³X³X³X³X³X³³-³0³Y³Y³Y³Y³Y³Y³
\r
142 ÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙ
\r
143 ³ ³ ÀÂÙ ÀÂÙ ÀÄÄÄÄÂÄÄÄÄÙ ÀÄÄÄÄÂÄÄÄÄÙ
\r
146 ³ ³ ÀÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ¿ ³
\r
147 ³ ³ ÚÁ¿ ÚÄÄÄÄÁÄÄÄÄ¿ ÚÁ¿ ÚÄÄÄÄÁÄÄÄÄ¿
\r
148 ³ ³ ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿
\r
149 ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³³ ³ ³ ³ ³ ³ ³ ³ ³
\r
150 Left Button ÄÄÙ ³ ÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙ
\r
151 Right Button ÄÄÄÄÙ X increment Y increment
\r
154 The X and Y increment values are in 2's compliment signed char format. (BTW
\r
155 thanks go to Adam Seychell for posting this info to comp.os.msdos.programmer).
\r
158 A simple Borland Pascal 7.0 mouse handler follows. First we declare a few
\r
162 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
\r
167 const COM1INTR = $0C;
\r
170 var bytenum : word;
\r
171 combytes : array[0..2] of byte;
\r
173 button1, button2 : boolean;
\r
174 MouseHandler : procedure;
\r
175 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r
177 The bytenum variable is used to keep track of which byte is expected next
\r
178 (ie 0, 1 or 2). The combytes variable is simply an array to keep track of
\r
179 bytes received so far. The mouse position will be stored in the x and y
\r
180 varaibles (note that this example will not perfrom any range checking).
\r
181 Button1 and button2 will be used to store the states of each of the buttons.
\r
182 MouseHandler will be used to store the normal mouse driver event handler.
\r
183 We'll need it to reset everything once we are finished.
\r
185 Here's the actual handler:
\r
187 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
\r
188 procedure MyMouseHandler; Interrupt;
\r
189 var dx, dy : integer;
\r
193 { Get the port byte }
\r
194 inbyte := Port[COM1PORT];
\r
196 { Make sure we are properly "synched" }
\r
197 if (inbyte and 64) = 64 then bytenum := 0;
\r
199 { Store the byte and adjust bytenum }
\r
200 combytes[bytenum] := inbyte;
\r
203 { Have we received all 3 bytes? }
\r
204 if bytenum = 3 then
\r
206 { Yes, so process them }
\r
207 dx := (combytes[0] and 3) shl 6 + combytes[1];
\r
208 dy := (combytes[0] and 12) shl 4 + combytes[2];
\r
209 if dx >= 128 then dx := dx - 256;
\r
210 if dy >= 128 then dy := dy - 256;
\r
213 button1 := (combytes[0] And 32) <> 0;
\r
214 button2 := (combytes[0] And 16) <> 0;
\r
216 { And start on first byte again }
\r
220 { Acknowledge the interrupt }
\r
223 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r
225 Once again pretty simple stuff. We just read the byte from the com1 port and
\r
226 figure out if it's time to do anything yet. If bit 6 is set to 1 then we
\r
227 know that it's meant to be the first byte of the 3, so we reset our
\r
228 bytenum variable to zero (in a perfect world bytes would always come in 3's
\r
229 and we would never need to check, but it never hurts to be careful).
\r
231 When 3 bytes have been received we simple decode them according to the
\r
232 diagram above and update the appropriate variables accordingly.
\r
234 The 'Port[$20] := $20;' command just lets the interrupt controller know we
\r
235 have processed the interrupt so it can send us the next one when it wants to.
\r
237 Note that the above "handler" does nothing more than keep track of the
\r
238 current mouse position and button states. If we were writing a proper mouse
\r
239 driver for an SVGA game we would also have to write custom cursor routines.
\r
240 I'll leave that bit to you!
\r
242 To actually install our mouse driver we'll have to set up all the variables,
\r
243 save the address of the current mouse handler and install our own. We'll
\r
244 also need call the existing mouse driver to set up the COM1 port to make
\r
245 sure it sends us the mouse bytes as it receives them. We could do this
\r
246 ourselves, but why make life harder than it already is?
\r
248 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
\r
249 procedure InitMyDriver;
\r
252 { Initialize the normal mouse handler }
\r
258 { Initialize some of the variables we'll be using }
\r
265 { Save the current mouse handler and set up our own }
\r
266 GetIntVec(COM1INTR, @MouseHandler);
\r
267 SetIntVec(COM1INTR, Addr(MyMouseHandler));
\r
269 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r
272 And finally when our program is finished it'll need to clean up after
\r
273 itself and return control back to the normal mouse driver:
\r
275 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
\r
276 procedure CleanUpMyDriver;
\r
278 SetIntVec(COM1INTR, @MouseHandler);
\r
280 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r
283 This little bit of source will test the above code. It does nothing more
\r
284 than repeatedly write the mouse position and button states to the screen
\r
285 until a keyboard key is pressed:
\r
287 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
\r
291 while not keypressed do
\r
292 WriteLn(x : 5, y : 5, button1 : 7, button2 : 7);
\r
295 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r