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