]> icculus.org git repositories - btb/d2x.git/blob - arch/win32/mouse.c
fix crash/hang when using -nojoystick in linux version (d1x r1.5)
[btb/d2x.git] / arch / win32 / mouse.c
1 /* $Id: mouse.c,v 1.3 2004-05-20 19:02:58 btb Exp $ */
2 /*
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.
13 */
14 /*
15  *
16  * Functions to access Mouse and Cyberman...
17  *
18  * Old Log:
19  * Revision 1.8  1996/02/21  13:57:36  allender
20  * cursor device manager stuff added here so as not to
21  * rely on InterfaceLib anymore
22  *
23  * Revision 1.7  1995/10/17  15:42:21  allender
24  * new mouse function to determine single button press
25  *
26  * Revision 1.6  1995/10/03  11:27:31  allender
27  * fixed up hotspot problems with the mouse on multiple monitors
28  *
29  * Revision 1.5  1995/07/13  11:27:08  allender
30  * trap button checks at MAX_MOUSE_BUTTONS
31  *
32  * Revision 1.4  1995/06/25  21:56:53  allender
33  * added events include
34  *
35  * Revision 1.3  1995/05/11  17:06:38  allender
36  * fixed up mouse routines
37  *
38  * Revision 1.2  1995/05/11  13:05:53  allender
39  * of mouse handler code
40  *
41  * Revision 1.1  1995/05/05  09:54:45  allender
42  * Initial revision
43  *
44  * Revision 1.9  1995/01/14  19:19:52  john
45  * Fixed signed short error cmp with -1 that caused mouse
46  * to break under Watcom 10.0
47  *
48  * Revision 1.8  1994/12/27  12:38:23  john
49  * Made mouse use temporary dos buffer instead of
50  *
51  * allocating its own.
52  *
53  * Revision 1.7  1994/12/05  23:54:53  john
54  * Fixed bug with mouse_get_delta only returning positive numbers..
55  *
56  * Revision 1.6  1994/11/18  23:18:18  john
57  * Changed some shorts to ints.
58  *
59  * Revision 1.5  1994/09/13  12:34:02  john
60  * Added functions to get down count and state.
61  *
62  * Revision 1.4  1994/08/29  20:52:19  john
63  * Added better cyberman support; also, joystick calibration
64  * value return funcctiionn,
65  *
66  * Revision 1.3  1994/08/24  18:54:32  john
67  * *** empty log message ***
68  *
69  * Revision 1.2  1994/08/24  18:53:46  john
70  * Made Cyberman read like normal mouse; added dpmi module; moved
71  * mouse from assembly to c. Made mouse buttons return time_down.
72  *
73  * Revision 1.1  1994/08/24  13:56:37  john
74  * Initial revision
75  *
76  *
77  */
78
79 #define WIN32_LEAN_AND_MEAN
80 #include <dinput.h>
81
82
83 #include <stdlib.h>
84 #include <stdio.h>
85 #include <string.h>
86
87 #include "error.h"
88 #include "fix.h"
89 #include "mouse.h"
90 #include "mono.h"
91 #include "timer.h"
92 #include "args.h"
93
94 // These are to kludge up a bit my slightly broken GCC directx port.
95 #ifndef E_FAIL
96 #define E_FAIL (HRESULT)0x80004005L
97 #endif
98 #ifndef SUCCEEDED
99 #define SUCCEEDED(a) ((HRESULT)(a) >= 0)
100 #endif
101 #ifndef S_OK
102 #define S_OK 0
103 #define S_FALSE 1
104 #endif
105 #ifndef SEVERITY_SUCCESS
106 #define SEVERITY_SUCCESS    0
107 #define SEVERITY_ERROR      1
108 #endif
109 #ifndef FACILITY_WIN32
110 #define FACILITY_WIN32                   7
111 #endif
112 #ifndef FIELD_OFFSET
113 #define FIELD_OFFSET(type, field)    ((LONG)&(((type *)0)->field))
114 #endif
115
116 #define ME_CURSOR_MOVED (1<<0)
117 #define ME_LB_P                 (1<<1)
118 #define ME_LB_R                 (1<<2)
119 #define ME_RB_P                 (1<<3)
120 #define ME_RB_R                 (1<<4)
121 #define ME_MB_P                 (1<<5)
122 #define ME_MB_R                 (1<<6)
123 #define ME_OB_P                 (1<<7)
124 #define ME_OB_R                 (1<<8)
125 #define ME_X_C                  (1<<9)
126 #define ME_Y_C                  (1<<10)
127 #define ME_Z_C                  (1<<11)
128 #define ME_P_C                  (1<<12)
129 #define ME_B_C                  (1<<13)
130 #define ME_H_C                  (1<<14)
131 #define ME_O_C                  (1<<15)
132
133 typedef struct event_info {
134         short x;
135         short y;
136         short z;
137         short pitch;
138         short bank;
139         short heading;
140         ushort button_status;
141         ushort device_dependant;
142 } event_info;
143
144 typedef struct mouse_info {
145         fix             ctime;
146         ubyte   cyberman;
147         int             num_buttons;
148         ubyte   pressed[MOUSE_MAX_BUTTONS];
149         fix             time_went_down[MOUSE_MAX_BUTTONS];
150         fix             time_held_down[MOUSE_MAX_BUTTONS];
151         uint    num_downs[MOUSE_MAX_BUTTONS];
152         uint    num_ups[MOUSE_MAX_BUTTONS];
153         //      ubyte   went_down; /* Not in PC version, not needed with 'num_downs' etc */
154         event_info *x_info;
155         ushort  button_status;
156 } mouse_info;
157
158 typedef struct cyberman_info {
159         ubyte device_type;
160         ubyte major_version;
161         ubyte minor_version;
162         ubyte x_descriptor;
163         ubyte y_descriptor;
164         ubyte z_descriptor;
165         ubyte pitch_descriptor;
166         ubyte roll_descriptor;
167         ubyte yaw_descriptor;
168         ubyte reserved;
169 } cyberman_info;
170
171 static mouse_info Mouse;
172
173 static int Mouse_installed = 0;
174
175 int WMMouse_Handler_Ready = 0;
176 int mouse_wparam, mouse_lparam, mouse_msg;
177
178
179 //GGI data:
180 //extern  ggi_visual_t          visual;
181 //extern  ggi_directbuffer_t            dbuf;   // GGI direct acces to screen memory
182 //extern  ggi_pixellinearbuffer *plb;
183
184 //Mouse globals
185 static double mouse_x, mouse_y;
186 static double mouse_saved_x, mouse_saved_y; //used when hiding/unhiding to reset the real (displayed) postion
187 double mouse_accel=1.0;
188
189 void DrawMouse(void);
190 void EraseMouse(void);
191 void MoveMouse(/*int button,*/ int x, int y);
192
193 #define WIN_WIDTH 640
194 #define WIN_HEIGHT 480
195 #define SCR_WIDTH 640
196 #define SCR_HEIGHT 480
197
198 LPDIRECTINPUT g_lpdi = NULL;
199 LPDIRECTINPUTDEVICE g_lpdidMouse = NULL;
200 extern HWND g_hWnd;
201
202
203 HRESULT ReadMouse (DIDEVICEOBJECTDATA *pdidod)
204 {
205         DWORD cElements = 1;
206         HRESULT hr;
207
208         if (g_lpdidMouse == NULL)
209                 return E_FAIL;
210
211         hr = IDirectInputDevice_GetDeviceData (
212                 g_lpdidMouse,
213                 sizeof (*pdidod),
214                 pdidod,
215                 &cElements,
216                 0);
217
218         if (hr == DIERR_INPUTLOST)
219         {
220                 hr = IDirectInputDevice_Acquire (g_lpdidMouse);
221                 if (SUCCEEDED (hr))
222                 {
223                         hr = IDirectInputDevice_GetDeviceData (
224                                 g_lpdidMouse,
225                                 sizeof (*pdidod),
226                                 pdidod,
227                                 &cElements,
228                                 0);
229                 }
230         }
231
232         if (SUCCEEDED (hr) && cElements != 1)
233                 hr = E_FAIL;
234
235         return hr;
236 }
237
238
239 void UpdateMouseState (DIDEVICEOBJECTDATA *pdidod)
240 {
241 //        fix timeNow = timer_get_fixed_seconds ();
242
243         ULONG iEvt = pdidod->dwOfs;
244         switch (iEvt)
245         {
246                 case DIMOFS_BUTTON0:
247                 case DIMOFS_BUTTON1:
248                 case DIMOFS_BUTTON2:
249                 case DIMOFS_BUTTON3:
250                 {
251                         BOOL bPressed = pdidod->dwData & 0x80;
252                         ULONG iButton = (iEvt - DIMOFS_BUTTON0) + MB_LEFT;
253                         if (bPressed)
254                         {
255                                 if (!Mouse.pressed [iButton])
256                                 {
257                                         Mouse.pressed [iButton] = 1;
258                                         Mouse.time_went_down [iButton] = Mouse.ctime;
259                                         Mouse.num_downs [iButton]++;
260                                         //                      Mouse.went_down = 1;
261                                 }
262                                 Mouse.num_downs [iButton] ++;
263                         }
264                         else
265                         {
266                                 if (Mouse.pressed [iButton])
267                                 {
268                                         Mouse.pressed [iButton] = 0;
269                                         Mouse.time_held_down [iButton] += Mouse.ctime - Mouse.time_went_down [iButton];
270                                         Mouse.num_ups [iButton]++;
271                                         //                      Mouse.went_down = 0;
272                                 }
273                         }
274                         break;
275                 }
276                 case DIMOFS_X:
277                         mouse_x += (double) ((LONG) pdidod->dwData);
278                         break;
279
280                 case DIMOFS_Y:
281                         mouse_y += (double) ((LONG) pdidod->dwData);
282                         break;
283                 case DIMOFS_Z:
284                         break;//hm, handle this?
285                 default:
286                         mprintf((0,"unknown mouse event %i\n",iEvt));
287 //                      exit (iEvt);//not happy.
288                         break;
289         }
290 }
291
292 void mouse_handler()
293 {
294         DIDEVICEOBJECTDATA didod;
295
296         Mouse.ctime = timer_get_fixed_seconds();
297
298         while (SUCCEEDED (ReadMouse (&didod)))
299         {
300                 UpdateMouseState (&didod);
301         }
302 }
303
304 void mouse_flush()
305 {
306         int i;
307         fix CurTime;
308         
309         if (!Mouse_installed)
310                 return;
311
312         mouse_handler();
313         //      _disable();
314         CurTime = timer_get_fixed_seconds();
315         for (i = 0; i < MOUSE_MAX_BUTTONS; i++) {
316                 Mouse.pressed[i] = 0;
317                 Mouse.time_went_down[i] = CurTime;
318                 Mouse.time_held_down[i] = 0;
319                 Mouse.num_downs[i] = 0;
320                 Mouse.num_ups[i] = 0;
321         }
322         //      Mouse.went_down = 0; /* mac only */
323         //      _enable();
324
325         {
326                 DWORD cElements = INFINITE;
327 //                HRESULT hr =
328                 IDirectInputDevice_GetDeviceData (
329                         g_lpdidMouse,
330                         sizeof (DIDEVICEOBJECTDATA),
331                         NULL,
332                         &cElements,
333                         0);
334         }
335 }
336
337
338 void mouse_close(void)
339 {
340         //      if (Mouse_installed)   // DPH: Unnecessary...
341         WMMouse_Handler_Ready=Mouse_installed = 0;
342
343         if (g_lpdidMouse != NULL)
344         {
345                 IDirectInputDevice_Unacquire (g_lpdidMouse);
346                 IDirectInputDevice_Release (g_lpdidMouse);
347                 g_lpdidMouse = NULL;
348         }
349         if (g_lpdi != NULL)
350         {
351                 IDirectInput_Release (g_lpdi);
352                 g_lpdi = NULL;
353         }
354 }
355
356
357
358 int mouse_init(int unused)
359 {
360         if (FindArg("-nomouse"))
361                 return 0;
362         if (Mouse_installed)
363                 return Mouse.num_buttons;
364         
365         {
366                 HRESULT hr;
367
368                 if (SUCCEEDED (hr = DirectInputCreate (GetModuleHandle (NULL), DIRECTINPUT_VERSION, &g_lpdi, NULL)))
369                 {
370                         if (SUCCEEDED (hr = IDirectInput_CreateDevice (g_lpdi,(void *) &GUID_SysMouse, &g_lpdidMouse, NULL)))
371                         {
372                                 DIPROPDWORD dipdw;
373                                 dipdw.diph.dwSize = sizeof (DIPROPDWORD);
374                                 dipdw.diph.dwHeaderSize = sizeof (DIPROPHEADER);
375                                 dipdw.diph.dwObj = 0;
376                                 dipdw.diph.dwHow = DIPH_DEVICE;
377                                 dipdw.dwData = 40;
378
379                                 if (SUCCEEDED (hr = IDirectInputDevice_SetDataFormat (g_lpdidMouse, &c_dfDIMouse)) &&
380                                         //changed on 9/4/99 by Victor Rachels NONEX -> Exclusive
381                                         SUCCEEDED (hr = IDirectInputDevice_SetCooperativeLevel (g_lpdidMouse, g_hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND)) &&
382                                         //end this section edit -VR
383                                         SUCCEEDED (hr = IDirectInputDevice_SetProperty (g_lpdidMouse, DIPROP_BUFFERSIZE, &dipdw.diph)) &&
384                                         SUCCEEDED (hr = IDirectInputDevice_Acquire (g_lpdidMouse)))
385                                 {
386                                 }
387                                 else
388                                 {
389                                         IDirectInputDevice_Release (g_lpdidMouse);
390                                         g_lpdidMouse = NULL;
391                                         return 0;
392                                 }
393                         }
394                 }
395         }
396         Mouse.num_buttons = 3;
397         
398         WMMouse_Handler_Ready=Mouse_installed = 1;
399         atexit(mouse_close);
400         mouse_flush();
401         //      mouse_set_center();
402         
403         return Mouse.num_buttons;
404 }
405
406 //WHS: added this
407 void mouse_center() {
408         mouse_x=mouse_saved_x=WIN_WIDTH/2;
409         mouse_y=mouse_saved_y=WIN_HEIGHT/2;
410 }
411
412 void mouse_get_pos( int *x, int *y)
413 {
414         mouse_handler(); //temp
415         
416         *x=(int) mouse_x;
417         *y=(int) mouse_y;
418 }
419
420 void mouse_get_delta( int *dx, int *dy )
421 {
422         if (!Mouse_installed) {
423                 *dx = *dy = 0;
424                 return;
425         }
426         mouse_handler(); //temp
427         
428         *dx = (int) mouse_x - WIN_WIDTH/2;
429         *dy = (int) mouse_y - WIN_HEIGHT/2;
430         
431         //Now reset the mouse position to the center of the screen
432         mouse_x = (double) WIN_WIDTH/2;
433         mouse_y = (double) WIN_HEIGHT/2;
434 }
435
436 void mouse_get_delta_no_reset( int *dx, int *dy )
437 {
438         if (!Mouse_installed) {
439                 *dx = *dy = 0;
440                 return;
441         }
442         mouse_handler(); //temp
443         
444         *dx = (int) mouse_x - WIN_WIDTH/2;
445         *dy = (int) mouse_y - WIN_HEIGHT/2;
446 }
447
448 int mouse_get_btns()
449 {
450         int  i;
451         uint flag=1;
452         int  status = 0;
453         
454         if (!Mouse_installed)
455                 return 0;
456
457         mouse_handler(); //temp
458         
459         for (i = 0; i < MOUSE_MAX_BUTTONS; i++) {
460                 if (Mouse.pressed[i])
461                         status |= flag;
462                 flag <<= 1;
463         }
464         return status;
465 }
466
467 /* This should be replaced with mouse_button_down_count(int button)     */
468 int mouse_went_down(int button)
469 {
470         int count;
471         
472         if (!Mouse_installed)
473                 return 0;
474
475         mouse_handler(); //temp
476         
477         if ((button < 0) || (button >= MOUSE_MAX_BUTTONS))
478                 return 0;
479         
480         //      _disable();             
481         count = Mouse.num_downs[button];
482         Mouse.num_downs[button] = 0;
483         
484         //      _enable();
485         return count;
486 }
487
488 // Returns how many times this button has went down since last call.
489 int mouse_button_down_count(int button) 
490 {
491         int count;
492         
493         if (!Mouse_installed)
494                 return 0;
495         
496         mouse_handler(); //temp
497         
498         if ((button < 0) || (button >= MOUSE_MAX_BUTTONS))
499                 return 0;
500         
501         //      _disable();
502         count = Mouse.num_downs[button];
503         Mouse.num_downs[button] = 0;
504         //      _enable();
505         return count;
506 }
507
508 // Returns 1 if this button is currently down
509 int mouse_button_state(int button)
510 {
511         int state;
512         
513         if (!Mouse_installed)
514                 return 0;
515         
516         mouse_handler(); //temp
517         
518         if ((button < 0) || (button >= MOUSE_MAX_BUTTONS))
519                 return 0;
520         
521         //      _disable();
522         state = Mouse.pressed[button];
523         //      _enable();
524         return state;
525 }
526
527 // Returns how long this button has been down since last call.
528 fix mouse_button_down_time(int button)  
529 {
530         fix time_down, time;
531         
532         if (!Mouse_installed)
533                 return 0;
534
535         mouse_handler(); //temp
536         
537         if ((button < 0) || (button >= MOUSE_MAX_BUTTONS))
538                 return 0;
539         
540         //      _disable();
541         if (!Mouse.pressed[button]) {
542                 time_down = Mouse.time_held_down[button];
543                 Mouse.time_held_down[button] = 0;
544         } else {
545                 time = timer_get_fixed_seconds();
546                 time_down = time - Mouse.time_held_down[button];
547                 Mouse.time_held_down[button] = 0;
548         }
549         //      _enable();
550         
551         return time_down;
552 }
553
554 void mouse_get_cyberman_pos( int *x, int *y )
555 {
556 }
557
558
559
560 //WHS: I made this :)
561 void hide_cursor()
562 {
563         ShowCursor(FALSE);
564 }
565
566 void show_cursor()
567 {
568         ShowCursor(TRUE);
569 }
570
571
572 /* New mouse pointer stuff for GGI/DGA */
573 //#include "cursor.h" /* cursor and mask */
574
575 typedef struct Sprite {
576         ushort width;
577         ushort height;
578         byte *pixels;
579         byte *mask;
580 } Sprite;
581
582 //Sprite mouse_sprite = { cursor_width, cursor_height, cursor_bits, cursor_mask_bits};
583
584 //byte *behind_mouse;
585 //byte behind_mouse[cursor_width*cursor_height];
586
587
588 void DrawMouse(void)
589 {
590 }
591
592
593 void EraseMouse(void)
594 {
595 }
596
597 //Should add a mode, relative, absolute
598 #define MOVE_REL 0
599 #define MOVE_ABS 1
600 //void MoveMouse(int mode, int x, int y) {
601
602 void MoveMouse(int x, int y)
603 {
604 }