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