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