1 /* $Id: mouse.c,v 1.4 2004-05-21 00:48:14 btb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Functions to access Mouse and Cyberman...
20 * Revision 1.11 1995/02/10 18:52:17 john
21 * Fixed bug with mouse not getting closed.
23 * Revision 1.10 1995/02/02 11:10:33 john
24 * Changed a bunch of mouse stuff around to maybe get
25 * around PS/2 mouse hang.
27 * Revision 1.9 1995/01/14 19:19:52 john
28 * Fixed signed short error cmp with -1 that caused mouse
29 * to break under Watcom 10.0
31 * Revision 1.8 1994/12/27 12:38:23 john
32 * Made mouse use temporary dos buffer instead of
37 * Revision 1.7 1994/12/05 23:54:53 john
38 * Fixed bug with mouse_get_delta only returning positive numbers..
40 * Revision 1.6 1994/11/18 23:18:18 john
41 * Changed some shorts to ints.
43 * Revision 1.5 1994/09/13 12:34:02 john
44 * Added functions to get down count and state.
46 * Revision 1.4 1994/08/29 20:52:19 john
47 * Added better cyberman support; also, joystick calibration
48 * value return funcctiionn,
50 * Revision 1.3 1994/08/24 18:54:32 john
51 * *** empty log message ***
53 * Revision 1.2 1994/08/24 18:53:46 john
54 * Made Cyberman read like normal mouse; added dpmi module; moved
55 * mouse from assembly to c. Made mouse buttons return time_down.
57 * Revision 1.1 1994/08/24 13:56:37 john
69 #define _BORLAND_DOS_REGS 1
71 _go32_dpmi_registers handler_regs;
89 #define ME_CURSOR_MOVED (1<<0)
90 #define ME_LB_P (1<<1)
91 #define ME_LB_R (1<<2)
92 #define ME_RB_P (1<<3)
93 #define ME_RB_R (1<<4)
94 #define ME_MB_P (1<<5)
95 #define ME_MB_R (1<<6)
96 #define ME_OB_P (1<<7)
97 #define ME_OB_R (1<<8)
99 #define ME_Y_C (1<<10)
100 #define ME_Z_C (1<<11)
101 #define ME_P_C (1<<12)
102 #define ME_B_C (1<<13)
103 #define ME_H_C (1<<14)
104 #define ME_O_C (1<<15)
106 #define MOUSE_MAX_BUTTONS 11
108 typedef struct event_info {
115 ushort button_status;
116 ushort device_dependant;
119 typedef struct mouse_info {
123 ubyte pressed[MOUSE_MAX_BUTTONS];
124 fix time_went_down[MOUSE_MAX_BUTTONS];
125 fix time_held_down[MOUSE_MAX_BUTTONS];
126 uint num_downs[MOUSE_MAX_BUTTONS];
127 uint num_ups[MOUSE_MAX_BUTTONS];
129 ushort button_status;
132 typedef struct cyberman_info {
139 ubyte pitch_descriptor;
140 ubyte roll_descriptor;
141 ubyte yaw_descriptor;
145 static mouse_info Mouse;
147 static int Mouse_installed = 0;
150 #define m_ax r->d.eax
156 void mouse_handler (_go32_dpmi_registers *r)
159 #pragma off (check_stack)
160 void _loadds far mouse_handler (int m_ax, int mbx, int mcx, int mdx, int msi, int mdi)
162 #pragma aux mouse_handler parm [EAX] [EBX] [ECX] [EDX] [ESI] [EDI]
164 Mouse.ctime = timer_get_fixed_secondsX();
166 if (m_ax & ME_LB_P) { // left button pressed
167 if (!Mouse.pressed[MB_LEFT]) {
168 Mouse.pressed[MB_LEFT] = 1;
169 Mouse.time_went_down[MB_LEFT] = Mouse.ctime;
171 Mouse.num_downs[MB_LEFT]++;
172 } else if (m_ax & ME_LB_R ) { // left button released
173 if (Mouse.pressed[MB_LEFT]) {
174 Mouse.pressed[MB_LEFT] = 0;
175 Mouse.time_held_down[MB_LEFT] += Mouse.ctime-Mouse.time_went_down[MB_LEFT];
177 Mouse.num_ups[MB_LEFT]++;
180 if (m_ax & ME_RB_P ) { // right button pressed
181 if (!Mouse.pressed[MB_RIGHT]) {
182 Mouse.pressed[MB_RIGHT] = 1;
183 Mouse.time_went_down[MB_RIGHT] = Mouse.ctime;
185 Mouse.num_downs[MB_RIGHT]++;
186 } else if (m_ax & ME_RB_R ) {// right button released
187 if (Mouse.pressed[MB_RIGHT]) {
188 Mouse.pressed[MB_RIGHT] = 0;
189 Mouse.time_held_down[MB_RIGHT] += Mouse.ctime-Mouse.time_went_down[MB_RIGHT];
191 Mouse.num_ups[MB_RIGHT]++;
194 if (m_ax & ME_MB_P ) { // middle button pressed
195 if (!Mouse.pressed[MB_MIDDLE]) {
196 Mouse.pressed[MB_MIDDLE] = 1;
197 Mouse.time_went_down[MB_MIDDLE] = Mouse.ctime;
199 Mouse.num_downs[MB_MIDDLE]++;
200 } else if (m_ax & ME_MB_R ) { // middle button released
201 if (Mouse.pressed[MB_MIDDLE]) {
202 Mouse.pressed[MB_MIDDLE] = 0;
203 Mouse.time_held_down[MB_MIDDLE] += Mouse.ctime-Mouse.time_went_down[MB_MIDDLE];
205 Mouse.num_ups[MB_MIDDLE]++;
208 if (Mouse.cyberman && (m_ax & (ME_Z_C|ME_P_C|ME_B_C|ME_H_C))) {
209 Mouse.x_info = (event_info *)((msi & 0xFFFF) << 4);
211 if (m_ax & ME_Z_C ) { // z axis changed
212 if (Mouse.pressed[MB_Z_UP]) {
214 Mouse.pressed[MB_Z_UP] = 0;
215 Mouse.time_held_down[MB_Z_UP] += Mouse.ctime-Mouse.time_went_down[MB_Z_UP];
216 Mouse.num_ups[MB_Z_UP]++;
217 } else if ( Mouse.x_info->z>0 ) {
219 Mouse.pressed[MB_Z_UP] = 1;
220 Mouse.time_went_down[MB_Z_UP]=Mouse.ctime;
221 Mouse.num_downs[MB_Z_UP]++;
223 if (Mouse.pressed[MB_Z_DOWN]) {
225 Mouse.pressed[MB_Z_DOWN] = 0;
226 Mouse.time_held_down[MB_Z_DOWN] += Mouse.ctime-Mouse.time_went_down[MB_Z_DOWN];
227 Mouse.num_ups[MB_Z_DOWN]++;
228 } else if ( Mouse.x_info->z<0 ) {
230 Mouse.pressed[MB_Z_DOWN] = 1;
231 Mouse.time_went_down[MB_Z_DOWN]=Mouse.ctime;
232 Mouse.num_downs[MB_Z_DOWN]++;
235 if (m_ax & ME_P_C ) { // pitch changed
236 if (Mouse.pressed[MB_PITCH_BACKWARD]) {
237 // pitch backward released
238 Mouse.pressed[MB_PITCH_BACKWARD] = 0;
239 Mouse.time_held_down[MB_PITCH_BACKWARD] += Mouse.ctime-Mouse.time_went_down[MB_PITCH_BACKWARD];
240 Mouse.num_ups[MB_PITCH_BACKWARD]++;
241 } else if ( Mouse.x_info->pitch>0 ) {
242 // pitch backward pressed
243 Mouse.pressed[MB_PITCH_BACKWARD] = 1;
244 Mouse.time_went_down[MB_PITCH_BACKWARD]=Mouse.ctime;
245 Mouse.num_downs[MB_PITCH_BACKWARD]++;
247 if (Mouse.pressed[MB_PITCH_FORWARD]) {
248 // pitch forward released
249 Mouse.pressed[MB_PITCH_FORWARD] = 0;
250 Mouse.time_held_down[MB_PITCH_FORWARD] += Mouse.ctime-Mouse.time_went_down[MB_PITCH_FORWARD];
251 Mouse.num_ups[MB_PITCH_FORWARD]++;
252 } else if ( Mouse.x_info->pitch<0 ) {
253 // pitch forward pressed
254 Mouse.pressed[MB_PITCH_FORWARD] = 1;
255 Mouse.time_went_down[MB_PITCH_FORWARD]=Mouse.ctime;
256 Mouse.num_downs[MB_PITCH_FORWARD]++;
260 if (m_ax & ME_B_C ) { // bank changed
261 if (Mouse.pressed[MB_BANK_LEFT]) {
262 // bank left released
263 Mouse.pressed[MB_BANK_LEFT] = 0;
264 Mouse.time_held_down[MB_BANK_LEFT] += Mouse.ctime-Mouse.time_went_down[MB_BANK_LEFT];
265 Mouse.num_ups[MB_BANK_LEFT]++;
266 } else if ( Mouse.x_info->bank>0 ) {
268 Mouse.pressed[MB_BANK_LEFT] = 1;
269 Mouse.time_went_down[MB_BANK_LEFT]=Mouse.ctime;
270 Mouse.num_downs[MB_BANK_LEFT]++;
272 if (Mouse.pressed[MB_BANK_RIGHT]) {
273 // bank right released
274 Mouse.pressed[MB_BANK_RIGHT] = 0;
275 Mouse.time_held_down[MB_BANK_RIGHT] += Mouse.ctime-Mouse.time_went_down[MB_BANK_RIGHT];
276 Mouse.num_ups[MB_BANK_RIGHT]++;
277 } else if ( Mouse.x_info->bank<0 ) {
278 // bank right pressed
279 Mouse.pressed[MB_BANK_RIGHT] = 1;
280 Mouse.time_went_down[MB_BANK_RIGHT]=Mouse.ctime;
281 Mouse.num_downs[MB_BANK_RIGHT]++;
285 if (m_ax & ME_H_C ) { // heading changed
286 if (Mouse.pressed[MB_HEAD_LEFT]) {
287 // head left released
288 Mouse.pressed[MB_HEAD_LEFT] = 0;
289 Mouse.time_held_down[MB_HEAD_LEFT] += Mouse.ctime-Mouse.time_went_down[MB_HEAD_LEFT];
290 Mouse.num_ups[MB_HEAD_LEFT]++;
291 } else if ( Mouse.x_info->heading>0 ) {
293 Mouse.pressed[MB_HEAD_LEFT] = 1;
294 Mouse.time_went_down[MB_HEAD_LEFT]=Mouse.ctime;
295 Mouse.num_downs[MB_HEAD_LEFT]++;
297 if (Mouse.pressed[MB_HEAD_RIGHT]) {
298 // head right released
299 Mouse.pressed[MB_HEAD_RIGHT] = 0;
300 Mouse.time_held_down[MB_HEAD_RIGHT] += Mouse.ctime-Mouse.time_went_down[MB_HEAD_RIGHT];
301 Mouse.num_ups[MB_HEAD_RIGHT]++;
302 } else if ( Mouse.x_info->heading<0 ) {
303 // head right pressed
304 Mouse.pressed[MB_HEAD_RIGHT] = 1;
305 Mouse.time_went_down[MB_HEAD_RIGHT]=Mouse.ctime;
306 Mouse.num_downs[MB_HEAD_RIGHT]++;
316 void mouse_handler_end (void) // dummy functions
320 #pragma on (check_stack)
323 //--------------------------------------------------------
324 // returns 0 if no mouse
325 // else number of buttons
326 int mouse_init(int enable_cyberman)
333 union REGS inregs, outregs;
334 ubyte *Mouse_dos_mem;
337 return Mouse.num_buttons;
340 if (_farpeekl(_dos_ds, 0x33 * 4) == 0) {
342 if (_dos_getvect(0x33) == NULL) {
344 // added on 1/13/2000 by Victor Rachels for more info
345 con_printf(CON_NORMAL, "\nNo mouse driver found!\n");
346 // end this section addition - VR
347 // No mouse driver loaded
351 // Reset the mouse driver
352 memset( &inregs, 0, sizeof(inregs) );
354 int386(0x33, &inregs, &outregs);
355 if (outregs.w.ax != 0xffff)
357 // added on 1/13/2000 by Victor Rachels for more info
358 con_printf(CON_NORMAL, "\nUnable to reset mouse!\n");
359 // end this section edit - VR
364 Mouse.num_buttons = outregs.w.bx;
367 // Enable mouse driver
368 // added/edited on 1/15/2000 by Victor Rachels to make this optional - can usually be used w or w/o this reset
369 if(!FindArg("-ihaveabrokenmouse"))
371 memset(&inregs, 0, sizeof(inregs));
372 inregs.w.ax = 0x0020;
373 int386(0x33, &inregs, &outregs);
374 if (outregs.w.ax != 0xffff)
376 // added on 1/13/2000 by Victor Rachels for more info
377 con_printf(CON_NORMAL, "\nUnable to enable mouse! (%x)\n", outregs.w.ax);
378 // end this section edit - VR
382 // end this section edit/addition - VR
384 if ( enable_cyberman ) {
385 Mouse_dos_mem = dpmi_get_temp_low_buffer( 64 );
386 if (Mouse_dos_mem==NULL) {
387 printf( "Unable to allocate DOS buffer in mouse.c\n" );
389 // Check for Cyberman...
390 memset( &rr, 0, sizeof(dpmi_real_regs) );
391 rr.es = DPMI_real_segment(Mouse_dos_mem);
392 rr.edx = DPMI_real_offset(Mouse_dos_mem);
394 dpmi_real_int386x( 0x33, &rr );
396 // SWIFT functions supported
397 ci = (cyberman_info *)Mouse_dos_mem;
398 if (ci->device_type==1) { // Cyberman
400 //printf( "Cyberman mouse detected\n" );
401 Mouse.num_buttons = 11;
407 if (!dpmi_lock_region(&Mouse,sizeof(mouse_info))) {
408 printf( "Unable to lock mouse data region" );
411 if (!dpmi_lock_region((void near *)mouse_handler,(char *)mouse_handler_end - (char near *)mouse_handler)) {
412 printf( "Unable to lock mouse handler" );
416 // Install mouse handler
419 dpmi_real_regs rregs;
420 _go32_dpmi_seginfo info;
421 memset(&rregs, 0, sizeof(rregs));
422 info.pm_offset = (unsigned int)&mouse_handler;
423 if (_go32_dpmi_allocate_real_mode_callback_retf(&info, &handler_regs)) {
424 printf( "Unable allocate mouse handler callback" );
428 rregs.ecx = ME_LB_P|ME_LB_R|ME_RB_P|ME_RB_R|ME_MB_P|ME_MB_R; // watch all 3 button ups/downs
430 rregs.ecx |= ME_Z_C| ME_P_C| ME_B_C| ME_H_C; // if using a cyberman, also watch z, pitch, bank, heading.
431 rregs.edx = info.rm_offset;
432 rregs.es = info.rm_segment;
433 dpmi_real_int386x( 0x33, &rregs );
436 memset( &inregs, 0, sizeof(inregs));
437 memset( &sregs, 0, sizeof(sregs));
439 inregs.w.cx = ME_LB_P|ME_LB_R|ME_RB_P|ME_RB_R|ME_MB_P|ME_MB_R; // watch all 3 button ups/downs
441 inregs.w.cx |= ME_Z_C| ME_P_C| ME_B_C| ME_H_C; // if using a cyberman, also watch z, pitch, bank, heading.
442 inregs.x.edx = FP_OFF(mouse_handler);
443 sregs.es = FP_SEG(mouse_handler);
444 int386x(0x33, &inregs, &outregs, &sregs);
449 atexit( mouse_close );
453 return Mouse.num_buttons;
461 union REGS inregs, outregs;
463 if (Mouse_installed) {
465 // clear mouse handler by setting flags to 0.
466 memset( &inregs, 0, sizeof(inregs));
467 memset( &sregs, 0, sizeof(sregs));
469 inregs.w.cx = 0; // disable event handler by setting to zero.
472 int386x(0x33, &inregs, &outregs, &sregs);
477 void mouse_set_limits( int x1, int y1, int x2, int y2 )
479 union REGS inregs, outregs;
481 if (!Mouse_installed) return;
483 memset( &inregs, 0, sizeof(inregs));
484 inregs.w.ax = 0x7; // Set Horizontal Limits for Pointer
487 int386(0x33, &inregs, &outregs);
489 memset( &inregs, 0, sizeof(inregs));
490 inregs.w.ax = 0x8; // Set Vertical Limits for Pointer
493 int386(0x33, &inregs, &outregs);
496 void mouse_get_pos( int *x, int *y)
498 union REGS inregs, outregs;
500 if (!Mouse_installed) {
504 memset( &inregs, 0, sizeof(inregs));
505 inregs.w.ax = 0x3; // Get Mouse Position and Button Status
506 int386(0x33, &inregs, &outregs);
507 *x = (short)outregs.w.cx;
508 *y = (short)outregs.w.dx;
511 void mouse_get_delta( int *dx, int *dy )
513 union REGS inregs, outregs;
515 if (!Mouse_installed) {
520 memset( &inregs, 0, sizeof(inregs));
521 inregs.w.ax = 0xb; // Read Mouse motion counters
522 int386(0x33, &inregs, &outregs);
523 *dx = (short)outregs.w.cx;
524 *dy = (short)outregs.w.dx;
533 if (!Mouse_installed)
536 for (i=0; i<MOUSE_MAX_BUTTONS; i++ ) {
537 if (Mouse.pressed[i])
544 void mouse_set_pos( int x, int y)
546 union REGS inregs, outregs;
548 if (!Mouse_installed)
551 memset( &inregs, 0, sizeof(inregs));
552 inregs.w.ax = 0x4; // Set Mouse Pointer Position
555 int386(0x33, &inregs, &outregs);
564 if (!Mouse_installed)
569 //Clear the mouse data
570 CurTime =timer_get_fixed_secondsX();
571 for (i=0; i<MOUSE_MAX_BUTTONS; i++ ) {
572 Mouse.pressed[i] = 0;
573 Mouse.time_went_down[i] = CurTime;
574 Mouse.time_held_down[i] = 0;
575 Mouse.num_downs[i]=0;
582 // Returns how many times this button has went down since last call.
583 int mouse_button_down_count(int button)
587 if (!Mouse_installed)
592 count = Mouse.num_downs[button];
593 Mouse.num_downs[button]=0;
600 // Returns 1 if this button is currently down
601 int mouse_button_state(int button)
605 if (!Mouse_installed)
610 state = Mouse.pressed[button];
619 // Returns how long this button has been down since last call.
620 fix mouse_button_down_time(int button)
624 if (!Mouse_installed)
629 if ( !Mouse.pressed[button] ) {
630 time_down = Mouse.time_held_down[button];
631 Mouse.time_held_down[button] = 0;
633 time = timer_get_fixed_secondsX();
634 time_down = time - Mouse.time_went_down[button];
635 Mouse.time_went_down[button] = time;
643 void mouse_get_cyberman_pos( int *x, int *y )
647 ubyte *Mouse_dos_mem;
649 if ( (!Mouse_installed) || (!Mouse.cyberman) ) {
654 Mouse_dos_mem = dpmi_get_temp_low_buffer( 64 );
656 if ( !Mouse_dos_mem ) {
662 memset( &rr, 0, sizeof(dpmi_real_regs) );
663 rr.es = DPMI_real_segment(Mouse_dos_mem);
664 rr.edx = DPMI_real_offset(Mouse_dos_mem);
666 dpmi_real_int386x( 0x33, &rr );
668 ei = (event_info *)Mouse_dos_mem;
670 *x = (((ei->x+8128)*256)/(8064+8128+1)) - 127;
671 *y = (((ei->y+8128)*256)/(8064+8128+1)) - 127;