OSDN Git Service

modified: Project 16.bfproject
[proj16/16.git] / 16 / PCGPE10 / MOUSE.TXT
1                     ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
2                     ³ Programming the Microsoft Mouse ³\r
3                     ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
4 \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
8 \r
9               ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
10               ³      THIS FILE MAY NOT BE DISTRIBUTED     ³\r
11               ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³\r
12               ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
13 \r
14 \r
15 ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\r
16 ³ Disclaimer ³\r
17 ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
18 \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
23 \r
24 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\r
25 ³ Introduction ³\r
26 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
27 \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
30 modes.\r
31 \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
34 \r
35 const MOUSEINTR = $33;\r
36 \r
37 procedure GetMousePos(var x, y : word; var button1, button2 : boolean);\r
38 var regs : registers;\r
39 begin\r
40   regs.ax := 3;\r
41   Intr(MOUSEINTR, regs);\r
42   x := regs.cx;\r
43   y := regs.dx;\r
44   button1 := (regs.bx and 1) <> 0;\r
45   button2 := (regs.bx and 2) <> 0;\r
46 end;\r
47 \r
48 \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
51 \r
52 \r
53 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\r
54 ³ Writing Custom Handlers ³\r
55 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
56 \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
59 \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
68 \r
69 Uses Crt, Dos;\r
70 \r
71 {$F+}\r
72 { called with bl = buttons, cx = x * 2, dx = y }\r
73 procedure Handler; far; assembler;\r
74 asm\r
75 \r
76   { This mouse "handler" just draws a pixel at the current mouse pos }\r
77   pusha\r
78   mov ax, $A000\r
79   mov es, ax\r
80   shr cx, 1\r
81   xchg dh, dl\r
82   mov di, dx\r
83   shr dx, 2\r
84   add di, dx\r
85   add di, cx\r
86   mov al, bl\r
87   inc al\r
88   stosb\r
89   popa\r
90 end;\r
91 {$F-}\r
92 \r
93 begin\r
94   asm\r
95 \r
96     { Set graphics mode 13h }\r
97     mov ax, $13\r
98     int $10\r
99 \r
100     { Initialize mouse driver }\r
101     xor ax, ax\r
102     int $33\r
103 \r
104     { Install custom handler }\r
105     mov ax, SEG Handler\r
106     mov es, ax\r
107     mov dx, OFS Handler\r
108     mov ax, 12\r
109     mov cx, $1F\r
110     int $33\r
111 \r
112     { Wait for a key press }\r
113     xor ah, ah\r
114     int $16\r
115 \r
116     { Back to text mode }\r
117     mov ax, 3\r
118     int $10\r
119   end;\r
120 end.\r
121 \r
122 \r
123 \r
124 \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
128 \r
129                   ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
130                   ³        Interrupt    Port ³\r
131                   ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\r
132                   ³ COM1      $0C       $3F8 ³\r
133                   ³ COM2      $0B       $3F8 ³\r
134                   ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
135 \r
136 The three bytes sent are formatted as follows:\r
137 \r
138 \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
144                ³ ³  ³   ³            ³                ³\r
145                ³ ³  ³   ÀÄÄÄÄ¿       ³                ³\r
146                ³ ³  ÀÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ¿       ³\r
147                ³ ³          ÚÁ¿ ÚÄÄÄÄÁÄÄÄÄ¿  ÚÁ¿ ÚÄÄÄÄÁÄÄÄÄ¿\r
148                ³ ³         ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿\r
149                ³ ³         ³ ³ ³ ³ ³ ³ ³ ³ ³³ ³ ³ ³ ³ ³ ³ ³ ³\r
150  Left Button ÄÄÙ ³         ÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙ\r
151 Right Button ÄÄÄÄÙ            X increment      Y increment\r
152 \r
153 \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
156 \r
157 \r
158 A simple Borland Pascal 7.0 mouse handler follows. First we declare a few\r
159 things we'll need:\r
160 \r
161 \r
162 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
163 Uses Crt, Dos;\r
164 \r
165 {$F+}\r
166 \r
167 const COM1INTR = $0C;\r
168       COM1PORT = $3F8;\r
169 \r
170 var bytenum : word;\r
171     combytes : array[0..2] of byte;\r
172     x, y : longint;\r
173     button1, button2 : boolean;\r
174     MouseHandler : procedure;\r
175 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
176 \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
184 \r
185 Here's the actual handler:\r
186 \r
187 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
188 procedure MyMouseHandler; Interrupt;\r
189 var dx, dy : integer;\r
190 var inbyte : byte;\r
191 begin\r
192 \r
193   { Get the port byte }\r
194   inbyte := Port[COM1PORT];\r
195 \r
196   { Make sure we are properly "synched" }\r
197   if (inbyte and 64) = 64 then bytenum := 0;\r
198 \r
199   { Store the byte and adjust bytenum }\r
200   combytes[bytenum] := inbyte;\r
201   inc(bytenum);\r
202 \r
203   { Have we received all 3 bytes? }\r
204   if bytenum = 3 then\r
205     begin\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
211       x := x + dx;\r
212       y := y + dy;\r
213       button1 := (combytes[0] And 32) <> 0;\r
214       button2 := (combytes[0] And 16) <> 0;\r
215 \r
216       { And start on first byte again }\r
217       bytenum := 0;\r
218     end;\r
219 \r
220   { Acknowledge the interrupt }\r
221   Port[$20] := $20;\r
222 end;\r
223 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
224 \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
230 \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
233 \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
236 \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
241 \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
247 \r
248 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
249 procedure InitMyDriver;\r
250 begin\r
251 \r
252   { Initialize the normal mouse handler }\r
253   asm\r
254     mov ax, 0\r
255     int $33\r
256   end;\r
257 \r
258   { Initialize some of the variables we'll be using }\r
259   bytenum := 0;\r
260   x := 0;\r
261   y := 0;\r
262   button1 := false;\r
263   button2 := false;\r
264 \r
265   { Save the current mouse handler and set up our own }\r
266   GetIntVec(COM1INTR, @MouseHandler);\r
267   SetIntVec(COM1INTR, Addr(MyMouseHandler));\r
268 end;\r
269 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
270 \r
271 \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
274 \r
275 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
276 procedure CleanUpMyDriver;\r
277 begin\r
278   SetIntVec(COM1INTR, @MouseHandler);\r
279 end;\r
280 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
281 \r
282 \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
286 \r
287 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
288 begin\r
289   ClrScr;\r
290   InitMyDriver;\r
291   while not keypressed do\r
292     WriteLn(x : 5, y : 5, button1 : 7, button2 : 7);\r
293   CleanUpMyDriver;\r
294 end.\r
295 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r