]> icculus.org git repositories - btb/d2x.git/blob - input/dos_mouse.c
moved old ChangeLog to NEWS
[btb/d2x.git] / input / dos_mouse.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 #include <conf.h>
15
16 #ifdef __ENV_DJGPP__
17
18 #ifdef __DJGPP__
19 #include <dpmi.h>
20 #define _BORLAND_DOS_REGS 1
21 #define near
22 _go32_dpmi_registers handler_regs;
23 #endif
24
25 #include <go32.h>
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 //#include <conio.h>
30 #include <dos.h>
31 //#include <i86.h>
32 #include <string.h>
33
34 #include "error.h"
35 #include "fix.h"
36 #include "u_dpmi.h"
37 #include "mouse.h"
38 #include "timer.h"
39
40 #define ME_CURSOR_MOVED (1<<0)
41 #define ME_LB_P                         (1<<1)
42 #define ME_LB_R                         (1<<2)
43 #define ME_RB_P                         (1<<3)
44 #define ME_RB_R                         (1<<4)
45 #define ME_MB_P                         (1<<5)
46 #define ME_MB_R                         (1<<6)
47 #define ME_OB_P                         (1<<7)
48 #define ME_OB_R                         (1<<8)
49 #define ME_X_C                  (1<<9)
50 #define ME_Y_C                  (1<<10)
51 #define ME_Z_C                  (1<<11)
52 #define ME_P_C                  (1<<12)
53 #define ME_B_C                  (1<<13)
54 #define ME_H_C                  (1<<14)
55 #define ME_O_C                  (1<<15)
56
57 #define MOUSE_MAX_BUTTONS       11
58
59 typedef struct event_info {
60         short x;
61         short y;
62         short z;
63         short pitch;
64         short bank;
65         short heading;
66         ushort button_status;
67         ushort device_dependant;
68 } event_info;
69
70 typedef struct mouse_info {
71         fix             ctime;
72         ubyte           cyberman;
73         int             num_buttons;
74         ubyte           pressed[MOUSE_MAX_BUTTONS];
75         fix             time_went_down[MOUSE_MAX_BUTTONS];
76         fix             time_held_down[MOUSE_MAX_BUTTONS];
77         uint            num_downs[MOUSE_MAX_BUTTONS];
78         uint            num_ups[MOUSE_MAX_BUTTONS];
79         event_info *x_info;
80         ushort  button_status;
81 } mouse_info;
82
83 typedef struct cyberman_info {
84         ubyte device_type;
85         ubyte major_version;
86         ubyte minor_version;
87         ubyte x_descriptor;
88         ubyte y_descriptor;
89         ubyte z_descriptor;
90         ubyte pitch_descriptor;
91         ubyte roll_descriptor;
92         ubyte yaw_descriptor;
93         ubyte reserved;
94 } cyberman_info;
95
96 static mouse_info Mouse;
97
98 static int Mouse_installed = 0;
99
100 #ifdef __DJGPP__
101 #define m_ax r->d.eax
102 #define mbx r->d.ebx
103 #define mcx r->d.ecx
104 #define mdx r->d.edx
105 #define msi r->d.esi
106 #define mdi r->d.edi
107 void mouse_handler (_go32_dpmi_registers *r)
108 {
109 #else
110 #pragma off (check_stack)
111 void _loadds far mouse_handler (int m_ax, int mbx, int mcx, int mdx, int msi, int mdi)
112 {
113 #pragma aux mouse_handler parm [EAX] [EBX] [ECX] [EDX] [ESI] [EDI]
114 #endif
115         Mouse.ctime = timer_get_fixed_secondsX();
116
117         if (m_ax & ME_LB_P)     {       // left button pressed
118                 if (!Mouse.pressed[MB_LEFT])    {
119                         Mouse.pressed[MB_LEFT] = 1;
120                         Mouse.time_went_down[MB_LEFT] = Mouse.ctime;
121                 }
122                 Mouse.num_downs[MB_LEFT]++;
123         } else if (m_ax & ME_LB_R )     {  // left button released
124                 if (Mouse.pressed[MB_LEFT])     {
125                         Mouse.pressed[MB_LEFT] = 0;
126                         Mouse.time_held_down[MB_LEFT] += Mouse.ctime-Mouse.time_went_down[MB_LEFT];
127                 }
128                 Mouse.num_ups[MB_LEFT]++;
129         }
130
131         if (m_ax & ME_RB_P ) {  // right button pressed
132                 if (!Mouse.pressed[MB_RIGHT])   {
133                         Mouse.pressed[MB_RIGHT] = 1;
134                         Mouse.time_went_down[MB_RIGHT] = Mouse.ctime;
135                 }
136                 Mouse.num_downs[MB_RIGHT]++;
137         } else if (m_ax & ME_RB_R )     {// right button released
138                 if (Mouse.pressed[MB_RIGHT])    {
139                         Mouse.pressed[MB_RIGHT] = 0;
140                         Mouse.time_held_down[MB_RIGHT] += Mouse.ctime-Mouse.time_went_down[MB_RIGHT];
141                 }
142                 Mouse.num_ups[MB_RIGHT]++;
143         }
144
145         if (m_ax & ME_MB_P )    { // middle button pressed
146                 if (!Mouse.pressed[MB_MIDDLE])  {
147                         Mouse.pressed[MB_MIDDLE] = 1;
148                         Mouse.time_went_down[MB_MIDDLE] = Mouse.ctime;
149                 }
150                 Mouse.num_downs[MB_MIDDLE]++;
151         } else if (m_ax & ME_MB_R )     { // middle button released
152                 if (Mouse.pressed[MB_MIDDLE])   {
153                         Mouse.pressed[MB_MIDDLE] = 0;
154                         Mouse.time_held_down[MB_MIDDLE] += Mouse.ctime-Mouse.time_went_down[MB_MIDDLE];
155                 }
156                 Mouse.num_ups[MB_MIDDLE]++;
157         }
158
159         if (Mouse.cyberman && (m_ax & (ME_Z_C|ME_P_C|ME_B_C|ME_H_C)))   {
160                 Mouse.x_info = (event_info *)((msi & 0xFFFF) << 4);
161
162                 if (m_ax & ME_Z_C )     { // z axis changed
163                         if (Mouse.pressed[MB_Z_UP])     {
164                                 // z up released
165                                 Mouse.pressed[MB_Z_UP] = 0;
166                                 Mouse.time_held_down[MB_Z_UP] += Mouse.ctime-Mouse.time_went_down[MB_Z_UP];
167                                 Mouse.num_ups[MB_Z_UP]++;
168                         }  else if ( Mouse.x_info->z>0 )        {
169                                 // z up pressed
170                                 Mouse.pressed[MB_Z_UP] = 1;
171                                 Mouse.time_went_down[MB_Z_UP]=Mouse.ctime;
172                                 Mouse.num_downs[MB_Z_UP]++;
173                         }
174                         if (Mouse.pressed[MB_Z_DOWN])   {
175                                 // z down released
176                                 Mouse.pressed[MB_Z_DOWN] = 0;
177                                 Mouse.time_held_down[MB_Z_DOWN] += Mouse.ctime-Mouse.time_went_down[MB_Z_DOWN];
178                                 Mouse.num_ups[MB_Z_DOWN]++;
179                         }  else if ( Mouse.x_info->z<0 )        {
180                                 // z down pressed
181                                 Mouse.pressed[MB_Z_DOWN] = 1;
182                                 Mouse.time_went_down[MB_Z_DOWN]=Mouse.ctime;
183                                 Mouse.num_downs[MB_Z_DOWN]++;
184                         }
185                 }
186                 if (m_ax & ME_P_C )     { // pitch changed
187                         if (Mouse.pressed[MB_PITCH_BACKWARD])   {
188                                 // pitch backward released
189                                 Mouse.pressed[MB_PITCH_BACKWARD] = 0;
190                                 Mouse.time_held_down[MB_PITCH_BACKWARD] += Mouse.ctime-Mouse.time_went_down[MB_PITCH_BACKWARD];
191                                 Mouse.num_ups[MB_PITCH_BACKWARD]++;
192                         }  else if ( Mouse.x_info->pitch>0 )    {
193                                 // pitch backward pressed
194                                 Mouse.pressed[MB_PITCH_BACKWARD] = 1;
195                                 Mouse.time_went_down[MB_PITCH_BACKWARD]=Mouse.ctime;
196                                 Mouse.num_downs[MB_PITCH_BACKWARD]++;
197                         }
198                         if (Mouse.pressed[MB_PITCH_FORWARD])    {
199                                 // pitch forward released
200                                 Mouse.pressed[MB_PITCH_FORWARD] = 0;
201                                 Mouse.time_held_down[MB_PITCH_FORWARD] += Mouse.ctime-Mouse.time_went_down[MB_PITCH_FORWARD];
202                                 Mouse.num_ups[MB_PITCH_FORWARD]++;
203                         }  else if ( Mouse.x_info->pitch<0 )    {
204                                 // pitch forward pressed
205                                 Mouse.pressed[MB_PITCH_FORWARD] = 1;
206                                 Mouse.time_went_down[MB_PITCH_FORWARD]=Mouse.ctime;
207                                 Mouse.num_downs[MB_PITCH_FORWARD]++;
208                         }
209                 }
210
211                 if (m_ax & ME_B_C )     { // bank changed
212                         if (Mouse.pressed[MB_BANK_LEFT])        {
213                                 // bank left released
214                                 Mouse.pressed[MB_BANK_LEFT] = 0;
215                                 Mouse.time_held_down[MB_BANK_LEFT] += Mouse.ctime-Mouse.time_went_down[MB_BANK_LEFT];
216                                 Mouse.num_ups[MB_BANK_LEFT]++;
217                         }  else if ( Mouse.x_info->bank>0 )     {
218                                 // bank left pressed
219                                 Mouse.pressed[MB_BANK_LEFT] = 1;
220                                 Mouse.time_went_down[MB_BANK_LEFT]=Mouse.ctime;
221                                 Mouse.num_downs[MB_BANK_LEFT]++;
222                         }
223                         if (Mouse.pressed[MB_BANK_RIGHT])       {
224                                 // bank right released
225                                 Mouse.pressed[MB_BANK_RIGHT] = 0;
226                                 Mouse.time_held_down[MB_BANK_RIGHT] += Mouse.ctime-Mouse.time_went_down[MB_BANK_RIGHT];
227                                 Mouse.num_ups[MB_BANK_RIGHT]++;
228                         }  else if ( Mouse.x_info->bank<0 )     {
229                                 // bank right pressed
230                                 Mouse.pressed[MB_BANK_RIGHT] = 1;
231                                 Mouse.time_went_down[MB_BANK_RIGHT]=Mouse.ctime;
232                                 Mouse.num_downs[MB_BANK_RIGHT]++;
233                         }
234                 }
235
236                 if (m_ax & ME_H_C )     { // heading changed
237                         if (Mouse.pressed[MB_HEAD_LEFT])        {
238                                 // head left released
239                                 Mouse.pressed[MB_HEAD_LEFT] = 0;
240                                 Mouse.time_held_down[MB_HEAD_LEFT] += Mouse.ctime-Mouse.time_went_down[MB_HEAD_LEFT];
241                                 Mouse.num_ups[MB_HEAD_LEFT]++;
242                         }  else if ( Mouse.x_info->heading>0 )  {
243                                 // head left pressed
244                                 Mouse.pressed[MB_HEAD_LEFT] = 1;
245                                 Mouse.time_went_down[MB_HEAD_LEFT]=Mouse.ctime;
246                                 Mouse.num_downs[MB_HEAD_LEFT]++;
247                         }
248                         if (Mouse.pressed[MB_HEAD_RIGHT])       {
249                                 // head right released
250                                 Mouse.pressed[MB_HEAD_RIGHT] = 0;
251                                 Mouse.time_held_down[MB_HEAD_RIGHT] += Mouse.ctime-Mouse.time_went_down[MB_HEAD_RIGHT];
252                                 Mouse.num_ups[MB_HEAD_RIGHT]++;
253                         }  else if ( Mouse.x_info->heading<0 )  {
254                                 // head right pressed
255                                 Mouse.pressed[MB_HEAD_RIGHT] = 1;
256                                 Mouse.time_went_down[MB_HEAD_RIGHT]=Mouse.ctime;
257                                 Mouse.num_downs[MB_HEAD_RIGHT]++;
258                         }
259                 }
260         }
261         
262 }
263
264
265
266
267 void mouse_handler_end (void)  // dummy functions
268 {
269 }
270 #pragma on (check_stack)
271
272 //--------------------------------------------------------
273 // returns 0 if no mouse
274 //           else number of buttons
275 int mouse_init(int enable_cyberman)
276 {
277         dpmi_real_regs rr;
278         cyberman_info *ci;
279 #ifndef __DJGPP__
280         struct SREGS sregs;
281 #endif
282         union REGS inregs, outregs;
283         ubyte *Mouse_dos_mem;
284
285         if (Mouse_installed)
286                 return Mouse.num_buttons;
287
288 #ifdef __DJGPP__
289        if (_farpeekl(_dos_ds, 0x33 * 4) == 0) {
290 #else
291        if (_dos_getvect(0x33) == NULL) {
292 #endif
293                 // No mouse driver loaded
294                 return 0;
295        }
296
297         // Reset the mouse driver
298         memset( &inregs, 0, sizeof(inregs) );
299         inregs.w.ax = 0;
300         int386(0x33, &inregs, &outregs);
301         if (outregs.w.ax != 0xffff)
302                 return 0;
303
304         Mouse.num_buttons = outregs.w.bx;
305         Mouse.cyberman = 0;
306
307         // Enable mouse driver
308         memset( &inregs, 0, sizeof(inregs) );
309         inregs.w.ax = 0x0020;
310         int386(0x33, &inregs, &outregs);
311         if (outregs.w.ax != 0xffff )
312                 return 0;
313
314         if ( enable_cyberman )  {
315                 Mouse_dos_mem = dpmi_get_temp_low_buffer( 64 );
316                 if (Mouse_dos_mem==NULL)        {
317                         printf( "Unable to allocate DOS buffer in mouse.c\n" );
318                 } else {
319                         // Check for Cyberman...        
320                         memset( &rr, 0, sizeof(dpmi_real_regs) );
321                         rr.es = DPMI_real_segment(Mouse_dos_mem);
322                         rr.edx = DPMI_real_offset(Mouse_dos_mem);
323                         rr.eax = 0x53c1;
324                         dpmi_real_int386x( 0x33, &rr );
325                         if (rr.eax==1)  {
326                                 // SWIFT functions supported
327                                 ci      = (cyberman_info *)Mouse_dos_mem;
328                                 if (ci->device_type==1) {       // Cyberman     
329                                         Mouse.cyberman = 1;
330                                         //printf( "Cyberman mouse detected\n" );
331                                         Mouse.num_buttons = 11;
332                                 }
333                         }
334                 }
335         }
336
337         if (!dpmi_lock_region(&Mouse,sizeof(mouse_info)))       {
338                 printf( "Unable to lock mouse data region" );
339                 exit(1);
340         }
341         if (!dpmi_lock_region((void near *)mouse_handler,(char *)mouse_handler_end - (char near *)mouse_handler))       {
342                 printf( "Unable to lock mouse handler" );
343                 exit(1);
344         }
345
346         // Install mouse handler
347 #ifdef __DJGPP__
348         {
349          dpmi_real_regs rregs;
350          _go32_dpmi_seginfo info;
351          memset(&rregs, 0, sizeof(rregs));
352          info.pm_offset = (unsigned int)&mouse_handler;
353          if (_go32_dpmi_allocate_real_mode_callback_retf(&info, &handler_regs)) {
354                 printf( "Unable allocate mouse handler callback" );
355                 exit(1);
356          }
357          rregs.eax     = 0xC;
358          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
359          if (Mouse.cyberman)
360                 rregs.ecx     |= ME_Z_C| ME_P_C| ME_B_C| ME_H_C;      // if using a cyberman, also watch z, pitch, bank, heading.
361          rregs.edx       = info.rm_offset;
362          rregs.es        = info.rm_segment;
363          dpmi_real_int386x( 0x33, &rregs );
364         }
365 #else
366         memset( &inregs, 0, sizeof(inregs));
367         memset( &sregs, 0, sizeof(sregs));
368         inregs.w.ax     = 0xC;
369         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
370         if (Mouse.cyberman)
371                 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.
372         inregs.x.edx    = FP_OFF(mouse_handler);
373         sregs.es                = FP_SEG(mouse_handler);
374         int386x(0x33, &inregs, &outregs, &sregs);
375 #endif
376
377         Mouse_installed = 1;
378
379         atexit( mouse_close );
380
381         mouse_flush();
382
383         return Mouse.num_buttons;
384 }
385
386
387
388 void mouse_close()
389 {
390         struct SREGS sregs;
391         union REGS inregs, outregs;
392
393         if (Mouse_installed)    {
394                 Mouse_installed = 0;
395                 // clear mouse handler by setting flags to 0.
396                 memset( &inregs, 0, sizeof(inregs));
397                 memset( &sregs, 0, sizeof(sregs));
398                 inregs.w.ax     = 0xC;
399                 inregs.w.cx             = 0;            // disable event handler by setting to zero.
400                 inregs.x.edx    = 0;    
401                 sregs.es       = 0;
402                 int386x(0x33, &inregs, &outregs, &sregs);
403         }
404 }
405
406
407 void mouse_set_limits( int x1, int y1, int x2, int y2 )
408 {
409         union REGS inregs, outregs;
410
411         if (!Mouse_installed) return;
412
413         memset( &inregs, 0, sizeof(inregs));
414         inregs.w.ax = 0x7;      // Set Horizontal Limits for Pointer
415         inregs.w.cx = x1;
416         inregs.w.dx = x2;
417         int386(0x33, &inregs, &outregs);
418
419         memset( &inregs, 0, sizeof(inregs));
420         inregs.w.ax = 0x8;      // Set Vertical Limits for Pointer
421         inregs.w.cx = y1;
422         inregs.w.dx = y2;
423         int386(0x33, &inregs, &outregs);
424 }
425
426 void mouse_get_pos( int *x, int *y)
427 {
428         union REGS inregs, outregs;
429
430         if (!Mouse_installed) {
431                 *x = *y = 0;
432                 return;
433         }
434         memset( &inregs, 0, sizeof(inregs));
435         inregs.w.ax = 0x3;      // Get Mouse Position and Button Status
436         int386(0x33, &inregs, &outregs);
437         *x = (short)outregs.w.cx; 
438         *y = (short)outregs.w.dx; 
439 }
440
441 void mouse_get_delta( int *dx, int *dy )
442 {
443         union REGS inregs, outregs;
444
445         if (!Mouse_installed) {
446                 *dx = *dy = 0;
447                 return;
448         }
449
450         memset( &inregs, 0, sizeof(inregs));
451         inregs.w.ax = 0xb;      // Read Mouse motion counters
452         int386(0x33, &inregs, &outregs);
453         *dx = (short)outregs.w.cx; 
454         *dy = (short)outregs.w.dx; 
455 }
456
457 int mouse_get_btns()
458 {
459         int i;
460         uint flag=1;
461         int status = 0;
462
463         if (!Mouse_installed) 
464                 return 0;
465
466         for (i=0; i<MOUSE_MAX_BUTTONS; i++ )    {
467                 if (Mouse.pressed[i])
468                         status |= flag;
469                 flag <<= 1;
470         }
471         return status;
472 }
473
474 void mouse_set_pos( int x, int y)
475 {
476         union REGS inregs, outregs;
477
478         if (!Mouse_installed) 
479                 return;
480
481         memset( &inregs, 0, sizeof(inregs));
482         inregs.w.ax = 0x4;      // Set Mouse Pointer Position
483         inregs.w.cx = x;
484         inregs.w.dx = y;
485         int386(0x33, &inregs, &outregs);
486
487 }
488
489 void mouse_flush()
490 {
491         int i;
492         fix CurTime;
493
494         if (!Mouse_installed) 
495                 return;
496
497         _disable();
498
499         //Clear the mouse data
500         CurTime =timer_get_fixed_secondsX();
501         for (i=0; i<MOUSE_MAX_BUTTONS; i++ )    {
502                 Mouse.pressed[i] = 0;
503                 Mouse.time_went_down[i] = CurTime;
504                 Mouse.time_held_down[i] = 0;
505                 Mouse.num_downs[i]=0;
506                 Mouse.num_ups[i]=0;
507         }
508         _enable();
509 }
510
511
512 // Returns how many times this button has went down since last call.
513 int mouse_button_down_count(int button) 
514 {
515         int count;
516
517         if (!Mouse_installed) 
518                 return 0;
519
520         _disable();
521
522         count = Mouse.num_downs[button];
523         Mouse.num_downs[button]=0;
524
525         _enable();
526
527         return count;
528 }
529
530 // Returns 1 if this button is currently down
531 int mouse_button_state(int button)      
532 {
533         int state;
534
535         if (!Mouse_installed) 
536                 return 0;
537
538         _disable();
539
540         state = Mouse.pressed[button];
541
542         _enable();
543
544         return state;
545 }
546
547
548
549 // Returns how long this button has been down since last call.
550 fix mouse_button_down_time(int button)  
551 {
552         fix time_down, time;
553
554         if (!Mouse_installed) 
555                 return 0;
556
557         _disable();
558
559         if ( !Mouse.pressed[button] )   {
560                 time_down = Mouse.time_held_down[button];
561                 Mouse.time_held_down[button] = 0;
562         } else  {
563                 time = timer_get_fixed_secondsX();
564                 time_down =  time - Mouse.time_went_down[button];
565                 Mouse.time_went_down[button] = time;
566         }
567
568         _enable();
569
570         return time_down;
571 }
572
573 void mouse_get_cyberman_pos( int *x, int *y )
574 {
575         dpmi_real_regs rr;
576         event_info * ei;
577         ubyte *Mouse_dos_mem;
578
579         if ( (!Mouse_installed) || (!Mouse.cyberman) ) {
580                 *x = *y = 0;
581                 return;
582         }
583
584         Mouse_dos_mem = dpmi_get_temp_low_buffer( 64 );
585
586         if ( !Mouse_dos_mem )   {
587                 *x = *y = 0;
588                 return;
589         }
590
591
592         memset( &rr, 0, sizeof(dpmi_real_regs) );
593         rr.es = DPMI_real_segment(Mouse_dos_mem);
594         rr.edx = DPMI_real_offset(Mouse_dos_mem);
595         rr.eax = 0x5301;
596         dpmi_real_int386x( 0x33, &rr );
597
598         ei = (event_info *)Mouse_dos_mem;
599
600         *x = (((ei->x+8128)*256)/(8064+8128+1)) - 127;
601         *y = (((ei->y+8128)*256)/(8064+8128+1)) - 127;
602 }
603
604 #endif // __ENV_DJGPP__