]> icculus.org git repositories - taylor/freespace2.git/blob - src/io/mouse.cpp
Keyboard partially fixed
[taylor/freespace2.git] / src / io / mouse.cpp
1 /*
2  * $Logfile: /Freespace2/code/Io/Mouse.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Routines to read the mouse.
8  *
9  * $Log$
10  * Revision 1.3  2002/05/29 06:25:13  theoddone33
11  * Keyboard input, mouse tracking now work
12  *
13  * Revision 1.2  2002/05/07 03:16:46  theoddone33
14  * The Great Newline Fix
15  *
16  * Revision 1.1.1.1  2002/05/03 03:28:09  root
17  * Initial import.
18  *
19  * 
20  * 4     7/15/99 9:20a Andsager
21  * FS2_DEMO initial checkin
22  * 
23  * 3     6/02/99 6:18p Dave
24  * Fixed TNT lockup problems! Wheeeee!
25  * 
26  * 2     10/07/98 10:53a Dave
27  * Initial checkin.
28  * 
29  * 1     10/07/98 10:49a Dave
30  * 
31  * 29    6/10/98 2:52p Hoffoss
32  * Made mouse code use DI by default, but fall back on normal code if that
33  * fails.
34  * 
35  * 28    5/24/98 1:35p Hoffoss
36  * Fixed bug where  mouse cursor is always recentering with a
37  * mouse_flush() call in debug version.
38  * 
39  * 27    5/22/98 4:50p Hoffoss
40  * Trying to fix mouse acceleration problem..
41  * 
42  * 26    5/21/98 12:26p Lawrance
43  * Fixed mouse jerk at mission start while in debug build only.
44  * 
45  * 25    5/15/98 2:41p Hoffoss
46  * Made mouse default to off (for flying ship) and fixed some new pilot
47  * init bugs.
48  * 
49  * 24    5/08/98 4:13p Hoffoss
50  * Fixed problem with mouse pointer centering causing lost keypresses.
51  * 
52  * 23    5/07/98 6:58p Hoffoss
53  * Made changes to mouse code to fix a number of problems.
54  * 
55  * 22    5/05/98 8:38p Hoffoss
56  * Added sensitivity adjustment to options menu and made it save to pilot
57  * file.
58  * 
59  * 21    5/05/98 1:03p Hoffoss
60  * Fixed initialization bug.
61  * 
62  * 20    5/01/98 5:45p Hoffoss
63  * Made further improvements to the mouse code.
64  * 
65  * 19    5/01/98 3:35p Hoffoss
66  * Made changes to release version of mouse code.
67  * 
68  * 18    5/01/98 1:14p Hoffoss
69  * Changed mouse usage so directInput is only used for release version.
70  * 
71  * 17    4/30/98 5:40p Hoffoss
72  * Added mouse as a supported control to fly the ship.
73  * 
74  * 16    4/29/98 12:13a Lawrance
75  * Add function to check down count of mouse button without reseting the
76  * internal count.  Added hook to reset demo trailer timer when a button
77  * is pressed.
78  * 
79  * 15    4/02/98 5:26p John
80  * 
81  * 14    1/19/98 6:15p John
82  * Fixed all my Optimized Build compiler warnings
83  * 
84  * 13    12/04/97 3:47p John
85  * Made joystick move mouse cursor
86  * 
87  * 12    11/20/97 5:36p Dave
88  * Hooked in a bunch of main hall changes (including sound). Made it
89  * possible to reposition (rewind/ffwd) 
90  * sound buffer pointers. Fixed animation direction change framerate
91  * problem.
92  * 
93  * 11    5/12/97 11:41a John
94  * Added range checking to mouse position
95  * 
96  * 10    4/22/97 5:55p Lawrance
97  * let mouse.cpp decide if mouse has moved
98  * 
99  * 9     4/22/97 12:29p John
100  * Changed mouse code so that you have to call mouse_init for the mouse
101  * stuff to work.
102  * 
103  * 8     4/22/97 10:56a John
104  * fixed some resource leaks.
105  * 
106  * 7     3/26/97 10:52a Lawrance
107  * mouse always on in menus, disappears in gameplay after 1 second
108  * 
109  * 6     3/11/97 1:37p Lawrance
110  * added mouse_up_count(), changed mouse_mark() to mouse_mark_button() &
111  * mouse_mark_move()
112  * 
113  * 5     12/09/96 1:29p Lawrance
114  * adding 3 button support
115  * 
116  * 4     12/03/96 4:19p John
117  * Added some code so that holding down the mouse buttons between menus
118  * doesn't select the next menu.
119  *
120  * $NoKeywords: $
121  */
122
123 #ifndef PLAT_UNIX
124 #include <windows.h>
125 #include <windowsx.h>
126 #endif
127
128 #include "mouse.h"
129 #include "2d.h"
130 #include "osapi.h"
131
132 #define MOUSE_MODE_DI   0
133 #define MOUSE_MODE_WIN  1
134
135 #ifdef NDEBUG
136 LOCAL int Mouse_mode = MOUSE_MODE_DI;
137 #else
138 LOCAL int Mouse_mode = MOUSE_MODE_WIN;
139 #endif
140
141 LOCAL int mouse_inited = 0;
142 LOCAL int Di_mouse_inited = 0;
143 LOCAL int Mouse_x;
144 LOCAL int Mouse_y;
145
146 CRITICAL_SECTION mouse_lock;
147
148 // #define USE_DIRECTINPUT
149
150 int mouse_flags;
151 int mouse_left_pressed = 0;
152 int mouse_right_pressed = 0;
153 int mouse_middle_pressed = 0;
154 int mouse_left_up = 0;
155 int mouse_right_up = 0;
156 int mouse_middle_up = 0;
157 int Mouse_dx = 0;
158 int Mouse_dy = 0;
159 int Mouse_dz = 0;
160
161 int Mouse_sensitivity = 4;
162 int Use_mouse_to_fly = 0;
163 int Mouse_hidden = 0;
164 int Keep_mouse_centered = 0;;
165
166 int di_init();
167 void di_cleanup();
168 void mouse_force_pos(int x, int y);
169 void mouse_eval_deltas_di();
170
171 int mouse_is_visible()
172 {
173         return !Mouse_hidden;
174 }
175
176 void mouse_close()
177 {
178         if (!mouse_inited)
179                 return;
180
181 #ifdef USE_DIRECTINPUT
182         di_cleanup();
183 #endif
184         mouse_inited = 0;
185 #ifdef PLAT_UNIX
186         STUB_FUNCTION;
187 #else
188         DeleteCriticalSection( &mouse_lock );
189 #endif
190 }
191
192 void mouse_init()
193 {
194         // Initialize queue
195         if ( mouse_inited ) return;
196         mouse_inited = 1;
197
198 #ifdef PLAT_UNIX
199         STUB_FUNCTION;
200 #else
201         InitializeCriticalSection( &mouse_lock );
202 #endif
203
204         ENTER_CRITICAL_SECTION(&mouse_lock);
205
206         mouse_flags = 0;
207         Mouse_x = gr_screen.max_w / 2;
208         Mouse_y = gr_screen.max_h / 2;
209
210 #ifdef USE_DIRECTINPUT
211         if (!di_init())
212                 Mouse_mode = MOUSE_MODE_WIN;
213 #else
214         Mouse_mode = MOUSE_MODE_WIN;
215 #endif
216
217         LEAVE_CRITICAL_SECTION(&mouse_lock);    
218
219         atexit( mouse_close );
220 }
221
222
223 // ----------------------------------------------------------------------------
224 // mouse_mark_button() is called asynchronously by the OS when a mouse button
225 // goes up or down.  The mouse button that is affected is passed via the 
226 // flags parameter.  
227 //
228 // parameters:   flags ==> mouse button pressed/released
229 //               set   ==> 1 - button is pressed
230 //                         0 - button is released
231
232 void mouse_mark_button( uint flags, int set)
233 {
234         if ( !mouse_inited ) return;
235
236         ENTER_CRITICAL_SECTION(&mouse_lock);
237
238         if ( !(mouse_flags & MOUSE_LEFT_BUTTON) )       {
239
240                 if ( (flags & MOUSE_LEFT_BUTTON) && (set == 1) ) {
241                         mouse_left_pressed++;
242
243 ////////////////////////////
244 /// SOMETHING TERRIBLE IS ABOUT TO HAPPEN.  I FEEL THIS IS NECESSARY FOR THE DEMO, SINCE
245 /// I DON'T WANT TO CALL CRITICAL SECTION CODE EACH FRAME TO CHECK THE LEFT MOUSE BUTTON.
246 /// PLEASE SEE ALAN FOR MORE INFORMATION.
247 ////////////////////////////
248 #ifdef FS2_DEMO
249                                         {
250                                         extern void demo_reset_trailer_timer();
251                                         demo_reset_trailer_timer();
252                                         }
253 #endif
254 ////////////////////////////
255 /// IT'S OVER.  SEE, IT WASN'T SO BAD RIGHT?  IT'S IS VERY UGLY LOOKING, I KNOW.
256 ////////////////////////////
257
258                 }
259         }
260         else {
261                 if ( (flags & MOUSE_LEFT_BUTTON) && (set == 0) ){
262                         mouse_left_up++;
263                 }
264         }
265
266         if ( !(mouse_flags & MOUSE_RIGHT_BUTTON) )      {
267
268                 if ( (flags & MOUSE_RIGHT_BUTTON) && (set == 1) ){
269                         mouse_right_pressed++;
270                 }
271         }
272         else {
273                 if ( (flags & MOUSE_RIGHT_BUTTON) && (set == 0) ){
274                         mouse_right_up++;
275                 }
276         }
277
278         if ( !(mouse_flags & MOUSE_MIDDLE_BUTTON) )     {
279
280                 if ( (flags & MOUSE_MIDDLE_BUTTON) && (set == 1) ){
281                         mouse_middle_pressed++;
282                 }
283         }
284         else {
285                 if ( (flags & MOUSE_MIDDLE_BUTTON) && (set == 0) ){
286                         mouse_middle_up++;
287                 }
288         }
289
290         if ( set ){
291                 mouse_flags |= flags;
292         } else {
293                 mouse_flags &= ~flags;
294         }
295
296         LEAVE_CRITICAL_SECTION(&mouse_lock);    
297 }
298
299 void mouse_flush()
300 {
301         if (!mouse_inited)
302                 return;
303
304         mouse_eval_deltas();
305         Mouse_dx = Mouse_dy = Mouse_dz = 0;
306         ENTER_CRITICAL_SECTION(&mouse_lock);
307         mouse_left_pressed = 0;
308         mouse_right_pressed = 0;
309         mouse_middle_pressed = 0;
310         mouse_flags = 0;
311         LEAVE_CRITICAL_SECTION(&mouse_lock);    
312 }
313
314 int mouse_down_count(int n, int reset_count)
315 {
316         int tmp = 0;
317         if ( !mouse_inited ) return 0;
318
319         if ( (n < LOWEST_MOUSE_BUTTON) || (n > HIGHEST_MOUSE_BUTTON)) return 0;
320
321         ENTER_CRITICAL_SECTION(&mouse_lock);
322
323         switch (n) {
324                 case MOUSE_LEFT_BUTTON:
325                         tmp = mouse_left_pressed;
326                         if ( reset_count ) {
327                                 mouse_left_pressed = 0;
328                         }
329                         break;
330
331                 case MOUSE_RIGHT_BUTTON:
332                         tmp = mouse_right_pressed;
333                         if ( reset_count ) {
334                                 mouse_right_pressed = 0;
335                         }
336                         break;
337
338                 case MOUSE_MIDDLE_BUTTON:
339                         tmp = mouse_middle_pressed;
340                         if ( reset_count ) {
341                                 mouse_middle_pressed = 0;
342                         }
343                         break;
344         } // end switch
345
346         LEAVE_CRITICAL_SECTION(&mouse_lock);    
347
348         return tmp;
349 }
350
351 // mouse_up_count() returns the number of times button n has gone from down to up
352 // since the last call
353 //
354 // parameters:  n - button of mouse (see #define's in mouse.h)
355 //
356 int mouse_up_count(int n)
357 {
358         int tmp = 0;
359         if ( !mouse_inited ) return 0;
360
361         if ( (n < LOWEST_MOUSE_BUTTON) || (n > HIGHEST_MOUSE_BUTTON)) return 0;
362
363         ENTER_CRITICAL_SECTION(&mouse_lock);
364
365         switch (n) {
366                 case MOUSE_LEFT_BUTTON:
367                         tmp = mouse_left_up;
368                         mouse_left_up = 0;
369                         break;
370
371                 case MOUSE_RIGHT_BUTTON:
372                         tmp = mouse_right_up;
373                         mouse_right_up = 0;
374                         break;
375
376                 case MOUSE_MIDDLE_BUTTON:
377                         tmp = mouse_middle_up;
378                         mouse_middle_up = 0;
379                         break;
380
381                 default:
382                         Assert(0);      // can't happen
383                         break;
384         } // end switch
385
386         LEAVE_CRITICAL_SECTION(&mouse_lock);    
387
388         return tmp;
389 }
390
391 // returns 1 if mouse button btn is down, 0 otherwise
392
393 int mouse_down(int btn)
394 {
395         int tmp;
396         if ( !mouse_inited ) return 0;
397
398         if ( (btn < LOWEST_MOUSE_BUTTON) || (btn > HIGHEST_MOUSE_BUTTON)) return 0;
399
400
401         ENTER_CRITICAL_SECTION(&mouse_lock);
402
403
404         if ( mouse_flags & btn )
405                 tmp = 1;
406         else
407                 tmp = 0;
408
409         LEAVE_CRITICAL_SECTION(&mouse_lock);    
410
411         return tmp;
412 }
413
414 // returns the fraction of time btn has been down since last call 
415 // (currently returns 1 if buttons is down, 0 otherwise)
416 //
417 float mouse_down_time(int btn)
418 {
419         float tmp;
420         if ( !mouse_inited ) return 0.0f;
421
422         if ( (btn < LOWEST_MOUSE_BUTTON) || (btn > HIGHEST_MOUSE_BUTTON)) return 0.0f;
423
424         ENTER_CRITICAL_SECTION(&mouse_lock);
425
426         if ( mouse_flags & btn )
427                 tmp = 1.0f;
428         else
429                 tmp = 0.0f;
430
431         LEAVE_CRITICAL_SECTION(&mouse_lock);
432
433         return tmp;
434 }
435
436 void mouse_get_delta(int *dx, int *dy, int *dz)
437 {
438         if (dx)
439                 *dx = Mouse_dx;
440         if (dy)
441                 *dy = Mouse_dy;
442         if (dz)
443                 *dz = Mouse_dz;
444 }
445
446 // Forces the actual windows cursor to be at (x,y).  This may be independent of our tracked (x,y) mouse pos.
447 void mouse_force_pos(int x, int y)
448 {
449         if (os_foreground()) {  // only mess with windows's mouse if we are in control of it
450 #ifdef PLAT_UNIX
451                 STUB_FUNCTION;
452 #else
453                 POINT pnt;
454
455                 pnt.x = x;
456                 pnt.y = y;
457                 ClientToScreen((HWND) os_get_window(), &pnt);
458                 SetCursorPos(pnt.x, pnt.y);
459 #endif
460         }
461 }
462
463 #include "gamesequence.h"
464
465 // change in mouse position since last call
466 void mouse_eval_deltas()
467 {
468         static int old_x = 0;
469         static int old_y = 0;
470         int tmp_x, tmp_y, cx, cy;
471
472         Mouse_dx = Mouse_dy = Mouse_dz = 0;
473         if (!mouse_inited)
474                 return;
475
476         if (Mouse_mode == MOUSE_MODE_DI) {
477                 mouse_eval_deltas_di();
478                 return;
479         }
480
481         cx = gr_screen.max_w / 2;
482         cy = gr_screen.max_h / 2;
483
484         ENTER_CRITICAL_SECTION(&mouse_lock);
485
486 #ifdef PLAT_UNIX
487         STUB_FUNCTION;
488 #else
489         POINT pnt;
490         GetCursorPos(&pnt);
491         ScreenToClient((HWND)os_get_window(), &pnt);
492         tmp_x = pnt.x;
493         tmp_y = pnt.y;
494 #endif
495
496         Mouse_dx = tmp_x - old_x;
497         Mouse_dy = tmp_y - old_y;
498         Mouse_dz = 0;
499
500         if (Keep_mouse_centered && Mouse_hidden) {
501                 if (Mouse_dx || Mouse_dy)
502                         mouse_force_pos(cx, cy);
503
504                 old_x = cx;
505                 old_y = cy;
506
507         } else {
508                 old_x = tmp_x;
509                 old_y = tmp_y;
510         }
511
512         LEAVE_CRITICAL_SECTION(&mouse_lock);
513 }
514
515 #ifndef PLAT_UNIX
516 #include "vdinput.h"
517
518 static LPDIRECTINPUT                    Di_mouse_obj = NULL;
519 static LPDIRECTINPUTDEVICE      Di_mouse = NULL;
520 #endif
521
522 void mouse_eval_deltas_di()
523 {
524 #ifdef PLAT_UNIX
525         STUB_FUNCTION;
526 #else
527         int repeat = 1;
528         HRESULT hr = 0;
529         DIMOUSESTATE mouse_state;
530
531         Mouse_dx = Mouse_dy = Mouse_dz = 0;
532         if (!Di_mouse_inited)
533                 return;
534
535         repeat = 1;
536         memset(&mouse_state, 0, sizeof(mouse_state));
537         while (repeat) {
538                 repeat = 0;
539
540                 hr = Di_mouse->GetDeviceState(sizeof(mouse_state), &mouse_state);
541                 if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) {
542                         // DirectInput is telling us that the input stream has
543                         // been interrupted.  We aren't tracking any state
544                         // between polls, so we don't have any special reset
545                         // that needs to be done.  We just re-acquire and
546                         // try again.
547                         Sleep(500);             // Pause a half second...
548                         hr = Di_mouse->Acquire();
549                         if (SUCCEEDED(hr))
550                                 repeat = 1;
551                 }
552         }
553
554         if (SUCCEEDED(hr)) {
555                 Mouse_dx = (int) mouse_state.lX;
556                 Mouse_dy = (int) mouse_state.lY;
557                 Mouse_dz = (int) mouse_state.lZ;
558
559         } else {
560                 Mouse_dx = Mouse_dy = Mouse_dz = 0;
561         }
562
563         Mouse_x += Mouse_dx;
564         Mouse_y += Mouse_dy;
565
566         if (Mouse_x < 0)
567                 Mouse_x = 0;
568
569         if (Mouse_y < 0)
570                 Mouse_y = 0;
571
572         if (Mouse_x >= gr_screen.max_w)
573                 Mouse_x = gr_screen.max_w - 1;
574
575         if (Mouse_y >= gr_screen.max_h)
576                 Mouse_y = gr_screen.max_h - 1;
577
578         // keep the mouse inside our window so we don't switch applications or anything (debug bug people reported?)
579         // JH: Dang!  This makes the mouse readings in DirectInput act screwy!
580 //      mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
581 #endif
582 }
583
584 int mouse_get_pos(int *xpos, int *ypos)
585 {
586         int flags;
587
588         if (Mouse_mode == MOUSE_MODE_DI) {
589                 if (xpos)
590                         *xpos = Mouse_x;
591
592                 if (ypos)
593                         *ypos = Mouse_y;
594
595                 return mouse_flags;
596         }
597
598         if (!mouse_inited) {
599                 *xpos = *ypos = 0;
600                 return 0;
601         }
602
603 #ifdef PLAT_UNIX
604         flags = SDL_GetMouseState (&Mouse_x, &Mouse_y);
605         // DDOI - FIXME?
606 #else
607         POINT pnt;
608         GetCursorPos(&pnt);
609         ScreenToClient((HWND)os_get_window(), &pnt);
610
611 //      EnterCriticalSection(&mouse_lock);
612
613         flags = mouse_flags;
614         Mouse_x = pnt.x;
615         Mouse_y = pnt.y;
616 #endif
617
618 //      LeaveCriticalSection(&mouse_lock);
619
620         if (Mouse_x < 0){
621                 Mouse_x = 0;
622         }
623
624         if (Mouse_y < 0){
625                 Mouse_y = 0;
626         }
627
628         if (Mouse_x >= gr_screen.max_w){
629                 Mouse_x = gr_screen.max_w - 1;
630         }
631
632         if (Mouse_y >= gr_screen.max_h){
633                 Mouse_y = gr_screen.max_h - 1;
634         }
635         
636         if (xpos){
637                 *xpos = Mouse_x;
638         }
639
640         if (ypos){
641                 *ypos = Mouse_y;
642         }
643
644         return flags;
645 }
646
647 void mouse_get_real_pos(int *mx, int *my)
648 {
649         if (Mouse_mode == MOUSE_MODE_DI) {
650                 *mx = Mouse_x;
651                 *my = Mouse_y;
652                 return;
653         }
654
655 #ifdef PLAT_UNIX
656         SDL_GetMouseState (mx, my);
657 #else
658         POINT pnt;
659         GetCursorPos(&pnt);
660         ScreenToClient((HWND)os_get_window(), &pnt);
661         
662         *mx = pnt.x;
663         *my = pnt.y;
664 #endif
665 }
666
667 void mouse_set_pos(int xpos, int ypos)
668 {
669         if (Mouse_mode == MOUSE_MODE_DI) {
670                 Mouse_x = xpos;
671                 Mouse_y = ypos;
672                 return;
673         }
674
675         if ((xpos != Mouse_x) || (ypos != Mouse_y)){
676                 mouse_force_pos(xpos, ypos);
677         }
678 }
679
680 int di_init()
681 {
682 #ifdef PLAT_UNIX
683         STUB_FUNCTION;
684         return 0;
685 #else
686         HRESULT hr;
687
688         if (Mouse_mode == MOUSE_MODE_WIN){
689                 return 0;
690         }
691
692         Di_mouse_inited = 0;
693         hr = DirectInputCreate(GetModuleHandle(NULL), DIRECTINPUT_VERSION, &Di_mouse_obj, NULL);
694         if (FAILED(hr)) {
695                 hr = DirectInputCreate(GetModuleHandle(NULL), 0x300, &Di_mouse_obj, NULL);
696                 if (FAILED(hr)) {
697                         mprintf(( "DirectInputCreate() failed!\n" ));
698                         return FALSE;
699                 }
700         }
701
702         hr = Di_mouse_obj->CreateDevice(GUID_SysMouse, &Di_mouse, NULL);
703         if (FAILED(hr)) {
704                 mprintf(( "CreateDevice() failed!\n" ));
705                 return FALSE;
706         }
707
708         hr = Di_mouse->SetDataFormat(&c_dfDIMouse);
709         if (FAILED(hr)) {
710                 mprintf(( "SetDataFormat() failed!\n" ));
711                 return FALSE;
712         }
713
714         hr = Di_mouse->SetCooperativeLevel((HWND)os_get_window(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
715         if (FAILED(hr)) {
716                 mprintf(( "SetCooperativeLevel() failed!\n" ));
717                 return FALSE;
718         }
719 /*
720         DIPROPDWORD hdr;
721
722         // Turn on buffering
723         hdr.diph.dwSize = sizeof(DIPROPDWORD); 
724         hdr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
725         hdr.diph.dwObj = 0;             
726         hdr.diph.dwHow = DIPH_DEVICE;   // Apply to entire device
727         hdr.dwData = 16;        //MAX_BUFFERED_KEYBOARD_EVENTS;
728
729         hr = Di_mouse->SetProperty( DIPROP_BUFFERSIZE, &hdr.diph );
730         if (FAILED(hr)) {
731                 mprintf(( "SetProperty DIPROP_BUFFERSIZE failed\n" ));
732                 return FALSE;
733         }
734
735         Di_event = CreateEvent( NULL, FALSE, FALSE, NULL );
736         Assert(Di_event != NULL);
737
738         hr = Di_mouse->SetEventNotification(Di_event);
739         if (FAILED(hr)) {
740                 mprintf(( "SetEventNotification failed\n" ));
741                 return FALSE;
742         }
743 */
744         Di_mouse->Acquire();
745
746         Di_mouse_inited = 1;
747         return TRUE;
748 #endif
749 }
750
751 void di_cleanup()
752 {
753 #ifdef PLAT_UNIX
754         STUB_FUNCTION;
755 #else
756         // Destroy any lingering IDirectInputDevice object.
757         if (Di_mouse) {
758                 // Unacquire the device one last time just in case we got really confused
759                 // and tried to exit while the device is still acquired.
760                 Di_mouse->Unacquire();
761
762                 Di_mouse->Release();
763                 Di_mouse = NULL;
764         }
765
766         // Destroy any lingering IDirectInput object.
767         if (Di_mouse_obj) {
768                 Di_mouse_obj->Release();
769                 Di_mouse_obj = NULL;
770         }
771
772         Di_mouse_inited = 0;
773 #endif
774 }
775