]> icculus.org git repositories - taylor/freespace2.git/blob - src/io/joy.cpp
do not swap German z and y keys if they are already swapped
[taylor/freespace2.git] / src / io / joy.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Io/Joy.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Code to read the joystick
16  *
17  * $Log$
18  * Revision 1.3  2002/06/09 04:41:21  relnev
19  * added copyright header
20  *
21  * Revision 1.2  2002/05/07 03:16:46  theoddone33
22  * The Great Newline Fix
23  *
24  * Revision 1.1.1.1  2002/05/03 03:28:09  root
25  * Initial import.
26  *
27  * 
28  * 5     7/15/99 9:20a Andsager
29  * FS2_DEMO initial checkin
30  * 
31  * 4     6/02/99 6:18p Dave
32  * Fixed TNT lockup problems! Wheeeee!
33  * 
34  * 3     10/09/98 2:57p Dave
35  * Starting splitting up OS stuff.
36  * 
37  * 2     10/07/98 10:53a Dave
38  * Initial checkin.
39  * 
40  * 1     10/07/98 10:49a Dave
41  * 
42  * 61    5/24/98 12:56a Mike
43  * Put in debug code, but comment out, to check joystick sensitivity.
44  * 
45  * 60    5/19/98 6:54p Lawrance
46  * Set default joystick sensitivity to max
47  * 
48  * 59    5/13/98 7:14p Hoffoss
49  * Made invalid axis return center position value.
50  * 
51  * 58    5/13/98 1:17a Hoffoss
52  * Added joystick axes configurability.
53  * 
54  * 57    5/07/98 3:15p Hoffoss
55  * Fixed typo.
56  * 
57  * 56    5/07/98 12:41p Hoffoss
58  * Changed code to make joystick sensitivity default to center of range.
59  * 
60  * 55    5/06/98 12:02a Hoffoss
61  * Fixed throttle problems with joysticks.
62  * 
63  * 54    5/05/98 8:38p Hoffoss
64  * Added sensitivity adjustment to options menu and made it save to pilot
65  * file.
66  * 
67  * 53    5/04/98 11:08p Hoffoss
68  * Expanded on Force Feedback code, and moved it all into Joy_ff.cpp.
69  * Updated references everywhere to it.
70  * 
71  * 52    5/03/98 6:02p Hoffoss
72  * Added DirectInput support for joystick (only works with v5.0, so only
73  * Win95).
74  * 
75  * 51    5/01/98 5:59p Hoffoss
76  * Checking in code so I can switch back to NT to work on this instead
77  * (Win95, bah!)
78  * 
79  * 50    4/30/98 12:12p Hoffoss
80  * Changed code to explicitly use calibrated values from Windows for
81  * joystick axis.
82  * 
83  * 49    4/29/98 12:13a Lawrance
84  * Add function for reading down count without resetting internal count.
85  * Add hook to reset demo trailer timer.
86  * 
87  * 48    4/25/98 12:02p Lawrance
88  * take out crit sec code around joystick read in joy_process
89  * 
90  * 47    4/22/98 9:03p John
91  * Put critical section around all the joygetposex functions.   Had to set
92  * up events to signal the polling thread to end at the end of the
93  * program.
94  * 
95  * 46    4/17/98 3:07p Jim
96  * added debug code to test joystick
97  * 
98  * 45    4/13/98 10:16a John
99  * Switched gettime back to timer_get_milliseconds, which is now thread
100  * safe.
101  * 
102  * 44    4/12/98 11:08p Lawrance
103  * switch back to using gettime() in separate threads
104  * 
105  * 43    4/12/98 5:31p Lawrance
106  * use timer_get_milliseconds() instead of gettime()
107  * 
108  * 42    3/21/98 11:29a John
109  * Made joy_flush work when a button is held down
110  * 
111  * 41    3/12/98 10:44a Hoffoss
112  * Whoops, should probably use the actual define rather than 0.
113  * 
114  * 40    3/12/98 10:38a Hoffoss
115  * Changed joystick default to first slot in never set up in FSLaunch
116  * 
117  * 39    3/11/98 5:27p Hoffoss
118  * Added to FreeSpace usage of joystick specified through FSLaunch.
119  * 
120  * 38    3/09/98 4:44p Sandeep
121  * 
122  * 37    3/07/98 5:23p Sandeep
123  * 
124  * 35    3/06/98 11:12a Hoffoss
125  * Fixed joystick deadzone bug.
126  * 
127  * 33    3/06/98 10:02a Hoffoss
128  * Made dead zone adjustable, and defaulted it to 10% instead of 5%.
129  * 
130  * 36    3/07/98 4:50p John
131  * Added code to allow toggling force feedback on/off in setup
132  * 
133  * 35    3/06/98 11:12a Hoffoss
134  * Fixed joystick deadzone bug.
135  * 
136  * 33    3/06/98 10:02a Hoffoss
137  * Made dead zone adjustable, and defaulted it to 10% instead of 5%.
138  * 
139  * 32    2/11/98 9:56p Jim
140  * allender: from sandeep on Jim's machine -- some force feedback stuff
141  * 
142  * 31    1/29/98 11:04a Sandeep
143  * 
144  * 30    1/27/98 8:40p Sandeep
145  * 
146  * 29    1/19/98 6:15p John
147  * Fixed all my Optimized Build compiler warnings
148  * 
149  * 28    1/08/98 6:35p Hoffoss
150  * Fixed joystick undefined detection.
151  * 
152  * 27    1/08/98 3:48p Dan
153  * Fixed bug with joystick axis reading thinking it's undefined at
154  * extremes.
155  * 
156  * 26    10/16/97 5:37p Lawrance
157  * change thread priority from THREAD_PRIORITY_TIME_CRITICAL to 
158  * THREAD_PRIORITY_HIGHEST
159  * 
160  * 25    10/09/97 10:15a Johnson
161  * try to init several times if joystick init fails
162  * 
163  * 24    10/07/97 10:42a Johnson
164  * zero out JOYINFOEX struct before setting dwSize
165  * 
166  * 23    10/06/97 5:54p Johnson
167  * ALAN: fix nasty bug where dwSize member of JOYINFOEX was not being set,
168  * resulting in random failure
169  * 
170  * 22    9/15/97 11:42p Lawrance
171  * change button_info to joy_button_info to avoid name conflict
172  * 
173  * 21    8/07/97 11:26p Lawrance
174  * add support for 4th axis (rudder)
175  * 
176  * 20    7/29/97 5:30p Lawrance
177  * move gettime() from keyboard module to timer module
178  * 
179  * 19    7/11/97 11:43a Lawrance
180  * fix bug with joy_up_count
181  * 
182  * 18    7/10/97 12:29a Lawrance
183  * fix problem with NT not recognizing an axis that was set under 95
184  * 
185  * 17    7/09/97 11:41p Lawrance
186  * added throttle and hat support
187  * 
188  * 16    6/19/97 9:50a John
189  * fixed bug where joy_close getting called out of order doesn't matter.
190  * 
191  * 15    5/18/97 2:40p Lawrance
192  * added joy_get_caps()
193  * 
194  * 14    4/22/97 10:56a John
195  * fixed some resource leaks.
196  * 
197  * 13    2/27/97 2:23p Lawrance
198  * took out debug stmts
199  * 
200  * 12    2/27/97 10:04a Lawrance
201  * fixed bug that was causing all joy buttons but 0 to be read incorrectly
202  * 
203  * 11    2/17/97 5:18p John
204  * Added a bunch of RCS headers to a bunch of old files that don't have
205  * them.
206  *
207  * $NoKeywords: $
208  */
209
210 #include <windows.h>
211 #include <windowsx.h>
212
213 #include "pstypes.h"
214 #include "joy.h"
215 #include "fix.h"
216 #include "key.h"
217 #include "timer.h"
218 #include "osregistry.h"
219 #include "joy_ff.h"
220 #include "vdinput.h"
221 #include "osapi.h"
222
223 #define PRECALIBRATED 1
224
225 static int Joy_inited = 0;
226 int joy_num_sticks = 0;
227 int Dead_zone_size = 10;
228 int Cur_joystick = -1;  // joystick used for input or -1
229 int Joy_sensitivity = 9;
230
231 CRITICAL_SECTION joy_lock;
232
233 HANDLE joy_thread = NULL;
234 DWORD joy_thread_id;
235 int joy_pollrate = 1000 / 18;  // poll at 18Hz
236
237 HANDLE Joy_tell_thread_to_end_event = NULL;
238 HANDLE Joy_thread_says_its_done_event = NULL;
239
240 static int Joy_last_x_reading = 0;
241 static int Joy_last_y_reading = 0;
242
243 int Joy_di_inited = 0;
244 static LPDIRECTINPUT                            Di_joystick_obj = NULL;
245 static LPDIRECTINPUTDEVICE2     Di_joystick = NULL;
246
247 typedef struct joy_button_info {
248         int     actual_state;           // Set if the button is physically down
249         int     state;                          // Set when the button goes from up to down, cleared on down to up.  Different than actual_state after a flush.
250         int     down_count;
251         int     up_count;
252         int     down_time;
253         uint    last_down_check;        // timestamp in milliseconds of last 
254 } joy_button_info;
255
256 Joy_info joystick;
257
258 joy_button_info joy_buttons[JOY_TOTAL_BUTTONS];
259
260 int joy_di_init();
261 int joy_di_shutdown();
262 int joystick_read_raw_axis_di(int num_axes, int *axis);
263
264 // --------------------------------------------------------------
265 //      joy_flush()
266 //
267 // Clear the state of the joystick.
268 //
269 void joy_flush()
270 {
271         int                     i;
272         joy_button_info *bi;
273
274         if ( joy_num_sticks < 1 ) return;
275
276         EnterCriticalSection(&joy_lock);
277         for ( i = 0; i < JOY_TOTAL_BUTTONS; i++) {
278                 bi = &joy_buttons[i];
279                 bi->state               = 0;
280                 bi->down_count  = 0;
281                 bi->up_count    = 0;
282                 bi->down_time   = 0;
283                 bi->last_down_check = timer_get_milliseconds();
284         }
285         
286         LeaveCriticalSection(&joy_lock);
287 }
288
289 // --------------------------------------------------------------
290 //      joy_process()
291 //
292 // Runs as a separate thread, and updates the state of the joystick
293 //
294 DWORD joy_process(DWORD lparam)
295 {
296         MMRESULT                rs;
297         JOYINFOEX       ji;
298         int                     i,state;
299         joy_button_info *bi;    
300
301         for ( i = 0; i < JOY_TOTAL_BUTTONS; i++) {
302                 bi = &joy_buttons[i];
303                 bi->actual_state = 0;           // Don't set in flush code!
304                 bi->state               = 0;
305                 bi->down_count  = 0;
306                 bi->up_count    = 0;
307                 bi->down_time   = 0;
308                 bi->last_down_check = timer_get_milliseconds();
309         }
310
311         while (1) {
312                 // Wait for the thread to be signaled to end or 1/18th of a second to pass...
313                 if ( WaitForSingleObject( Joy_tell_thread_to_end_event, joy_pollrate )==WAIT_OBJECT_0)  {
314                         break;
315                 }
316
317                 memset(&ji, 0, sizeof(ji));
318                 ji.dwSize = sizeof(ji);
319 //              ji.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNRAWDATA;
320                 ji.dwFlags = JOY_RETURNALL;
321
322                 EnterCriticalSection(&joy_lock);
323
324                 uint joy_state = 0;
325                 if (Cur_joystick >= 0) {
326                         rs = joyGetPosEx(Cur_joystick, &ji);
327                         // If there's an error, assume all buttons down.
328                         if (rs == JOYERR_NOERROR) {
329                                 joy_state = ji.dwButtons;
330                         }
331                 }
332
333                 // Process ji.dwButtons
334                 for (i=0; i<JOY_TOTAL_BUTTONS; i++) {
335                         state = 0;
336                         if (i < JOY_NUM_BUTTONS) {
337                                 state = joy_state & (1<<i);
338
339                         } else {
340                                 // check for hat presses, which act like buttons
341                                 switch (i) {
342                                         case JOY_HATBACK:
343                                                 if (ji.dwPOV == JOY_POVBACKWARD)
344                                                         state = 1;
345                                                 break;
346
347                                         case JOY_HATFORWARD:
348                                                 if (ji.dwPOV == JOY_POVFORWARD)
349                                                         state = 1;
350                                                 break;
351
352                                         case JOY_HATLEFT:
353                                                 if (ji.dwPOV == JOY_POVLEFT)
354                                                         state = 1;
355                                                 break;
356
357                                         case JOY_HATRIGHT:
358                                                 if (ji.dwPOV == JOY_POVRIGHT)
359                                                         state = 1;
360                                                 break;
361
362                                         default:
363                                                 Int3(); // should never happen
364                                                 break;
365
366                                 }       // end switch
367                         }       // end if
368
369
370                         if (state != joy_buttons[i].actual_state) {
371                                 // Button position physically changed.
372                                 joy_buttons[i].actual_state = state;
373
374                                 if ( state )    {
375                                         // went from up to down
376                                         joy_buttons[i].down_count++;
377                                         joy_buttons[i].down_time = 0;
378
379                                         joy_buttons[i].state = 1;
380
381 ////////////////////////////
382 /// SOMETHING TERRIBLE IS ABOUT TO HAPPEN.  I FEEL THIS IS NECESSARY FOR THE DEMO, SINCE
383 /// I DON'T WANT TO CALL CRITICAL SECTION CODE EACH FRAME TO CHECK ALL THE JOYSTICK BUTTONS.
384 /// PLEASE SEE ALAN FOR MORE INFORMATION.
385 ////////////////////////////
386 #ifdef FS2_DEMO
387                                         {
388                                         extern void demo_reset_trailer_timer();
389                                         demo_reset_trailer_timer();
390                                         }
391 #endif
392 ////////////////////////////
393 /// IT'S OVER.  SEE, IT WASN'T SO BAD RIGHT?  IT'S IS VERY UGLY LOOKING, I KNOW.
394 ////////////////////////////
395
396
397                                 } else {
398                                         // went from down to up
399                                         if ( joy_buttons[i].state )     {
400                                                 joy_buttons[i].up_count++;
401                                         }
402                                         joy_buttons[i].state = 0;
403                                 }
404
405                         } else {
406                                 // Didn't move... increment time down if down.
407                                 if (joy_buttons[i].state) {
408                                         joy_buttons[i].down_time += joy_pollrate;
409                                 }
410                         }
411
412                 }  // end for
413
414                 LeaveCriticalSection(&joy_lock);
415         }
416
417         SetEvent(Joy_thread_says_its_done_event);       
418
419         return 0;
420 }
421
422 // --------------------------------------------------------------
423 //      joy_close()
424 //
425 // Close the joystick system.  Should be called at game exit.
426 //
427 void joy_close()
428 {
429         if (!Joy_inited)
430                 return;
431
432         // joy_di_shutdown();
433
434         Joy_inited = 0;
435         joy_num_sticks = 0;
436
437         // Tell joystick polling thread to end
438         SetEvent(Joy_tell_thread_to_end_event);
439
440         // Wait for it to end
441         if ( WaitForSingleObject( Joy_thread_says_its_done_event, 5000 )==WAIT_TIMEOUT) {                       //INFINITE );
442                 mprintf(( "Joy end thread wait timeout!\n" ));
443         }
444         CloseHandle(Joy_tell_thread_to_end_event);
445         CloseHandle(Joy_thread_says_its_done_event);
446
447         // It is now safe to release any resources use by the polling thread.
448         DeleteCriticalSection( &joy_lock );
449         if (joy_thread) {
450                 CloseHandle(joy_thread);
451                 joy_thread = NULL;
452         }
453
454         joy_ff_shutdown();
455 }
456
457 // --------------------------------------------------------------
458 //      joy_get_caps()
459 //
460 // Determine the capabilities of the attached joysticks.
461 //
462 void joy_get_caps(int max)
463 {
464         JOYCAPS JoyCaps;
465         int j;
466
467         for (j=0; j<JOY_NUM_AXES; j++)
468                 joystick.axis_valid[j] = 0;
469
470         for (j=JOYSTICKID1; j<JOYSTICKID1+max; j++) {
471                 if (JOYERR_NOERROR == joyGetDevCaps (j, &JoyCaps, sizeof(JoyCaps))) {
472                         nprintf(("JOYSTICK", "Joystick #%d: %s\n", j - JOYSTICKID1 + 1, JoyCaps.szPname));
473
474                         if (j == Cur_joystick) {
475                                 joystick.axis_valid[0] = joystick.axis_valid[1] = 1;
476                                 if (JoyCaps.wCaps & JOYCAPS_HASZ)
477                                         joystick.axis_valid[2] = 1;
478                                 if (JoyCaps.wCaps & JOYCAPS_HASR)
479                                         joystick.axis_valid[3] = 1;
480                                 if (JoyCaps.wCaps & JOYCAPS_HASU)
481                                         joystick.axis_valid[4] = 1;
482                                 if (JoyCaps.wCaps & JOYCAPS_HASV)
483                                         joystick.axis_valid[5] = 1;
484                         }
485                 }
486         }
487 }
488
489 int joy_get_scaled_reading(int raw, int axn);
490 int joy_get_unscaled_reading(int raw, int axn);
491
492 DCF(joytest, "Test joystick")
493 {
494         if (Dc_command) {
495                 while (!keyd_pressed[KEY_ESC]) {
496                         int x, y, axis[JOY_NUM_AXES];
497
498                         if (joy_num_sticks < 1)
499                                 return;
500
501                         joystick_read_raw_axis(JOY_NUM_AXES, axis);
502
503                         x = joy_get_scaled_reading(axis[0], 0);
504                         y = joy_get_scaled_reading(axis[1], 1);
505
506                         mprintf(("X=%5d Y=%5d  Calibrated X=%6d Y=%6d\n", axis[0], axis[1], x, y));
507                         Sleep(100);
508                 }
509         }
510 }
511
512 DCF(joytest2, "Test joystick (extended)")
513 {
514         if (Dc_command) {
515                 while (!keyd_pressed[KEY_ESC]) {
516                         int x, y, z, r, axis[JOY_NUM_AXES];
517
518                         if (joy_num_sticks < 1)
519                                 return;
520
521                         joystick_read_raw_axis(JOY_NUM_AXES, axis);
522
523                         x = joy_get_scaled_reading(axis[0], 0);
524                         y = joy_get_scaled_reading(axis[1], 1);
525                         z = joy_get_unscaled_reading(axis[2], 2);
526                         r = joy_get_scaled_reading(axis[3], 3);
527
528                         mprintf(("X=%5d Y=%5d Z=%5d Rx=%5d Ry=%5d Rz=%5d Cal X=%6d Y=%6d Z=%6d R=%6d\n", axis[0], axis[1], axis[2], axis[3], axis[4], axis[5], x, y, z, r));
529                         Sleep(100);
530                 }
531         }
532 }
533
534 // --------------------------------------------------------------
535 //      joy_init()
536 //
537 // Initialize the joystick system.  This is called once at game startup.
538 //
539
540 int joy_init()
541 {
542         int i, n, count;
543         MMRESULT rs;
544         JOYINFOEX ji;
545
546         if (Joy_inited)
547                 return 0;
548
549         Joy_inited = 1;
550         n = joyGetNumDevs();
551         Cur_joystick = os_config_read_uint(NULL, "CurrentJoystick", JOYSTICKID1);
552
553         joy_get_caps(n);
554
555         if (n < 1) {
556                 mprintf(("No joystick driver detected\n"));
557                 return 0;
558         }
559
560         InitializeCriticalSection(&joy_lock);
561         atexit(joy_close);
562
563         joy_flush();
564
565         joy_num_sticks = 0;
566         memset(&ji, 0, sizeof(ji));
567         ji.dwSize = sizeof(ji);
568         ji.dwFlags = JOY_RETURNALL;
569
570         if (Cur_joystick >= 0) {
571                 // AL: test code to try and find out why this call fails the first time
572                 rs = 0;
573                 for (count=0; count<20; count++) {
574                         rs = joyGetPosEx(Cur_joystick, &ji);
575                         if (rs == JOYERR_NOERROR)
576                                 break;
577                 }
578                         
579                 if (rs == JOYERR_NOERROR) {
580                         joy_num_sticks++;
581
582                         Joy_tell_thread_to_end_event = CreateEvent( NULL, FALSE, FALSE, NULL );
583                         Joy_thread_says_its_done_event = CreateEvent( NULL, FALSE, FALSE, NULL );
584
585                         joy_thread = CreateThread(NULL, 
586                                                                                         1024 * 32,
587                                                                                         (LPTHREAD_START_ROUTINE) joy_process,
588                                                                                         NULL,
589                                                                                         0,
590                                                                                         &joy_thread_id);
591
592                 //              SetThreadPriority(joy_thread, THREAD_PRIORITY_TIME_CRITICAL - 1);
593                         SetThreadPriority(joy_thread, THREAD_PRIORITY_HIGHEST);
594                 }
595         }
596
597         mprintf(("Windoze reported %d joysticks, we found %d\n", n, joy_num_sticks));
598
599 #ifdef PRECALIBRATED
600         // Fake a calibration
601         if (joy_num_sticks > 0) {
602                 for (i=0; i<4; i++) {
603                         joystick.axis_min[i] = 0;
604                         joystick.axis_center[i] = 32768;
605                         joystick.axis_max[i] = 65536;
606                 }
607         }
608 #else
609         // Fake a calibration
610         if (joy_num_sticks > 0) {
611                 joy_set_cen();
612                 for (i=0; i<4; i++) {
613                         joystick.axis_min[i] = 0;
614                         joystick.axis_max[i] = joystick.axis_center[i]*2;
615                 }
616         }
617 #endif
618
619         joy_ff_init();
620         // joy_di_init();
621
622         return joy_num_sticks;
623 }
624
625 // --------------------------------------------------------------
626 //      joy_cheap_cal()
627 //
628 //      Manual calibrate joystick routine
629 //
630 void joy_cheap_cal()
631 {
632         if ( joy_num_sticks < 1 ) return;
633
634         while(1)        {
635                 Sleep(50);
636                 if ( key_inkey()) break;
637                 if (joy_down_count(0)) break;
638                 mprintf(( "Move stick to upper-left and hit button\n" ));
639         }
640         joy_set_ul();
641
642         while(1)        {
643                 Sleep(50);
644                 if ( key_inkey()) break;
645                 if (joy_down_count(0)) break;
646                 mprintf(( "Move stick to lower-right and hit button\n" ));
647         }
648         joy_set_lr();
649
650         while(1)        {
651                 Sleep(50);
652                 if ( key_inkey()) break;
653                 if (joy_down_count(0)) break;
654                 mprintf(( "Move stick to center and hit button\n" ));
655         }
656         joy_set_cen();
657 }
658
659 // --------------------------------------------------------------
660 //      joy_get_pos_old()
661 //
662 //      Get the position of the joystick axes
663 //
664 int joy_get_pos_old(int * x, int * y )
665 {
666         MMRESULT rs;
667         JOYINFOEX ji;
668
669         if ( joy_num_sticks < 1 ) {
670                 if (x) *x = 0;
671                 if (y) *y = 0;
672                 return 0;
673         }
674
675         memset(&ji, 0, sizeof(ji));
676         ji.dwSize = sizeof(ji);
677
678 #ifdef PRECALIBRATED
679 //JOY_USEDEADZONE|
680 //JOY_RETURNCENTERED|
681 //JOY_RETURNX|JOY_RETURNY|JOY_RETURNRAWDATA;
682         ji.dwFlags = JOY_RETURNALL;
683 #else
684         ji.dwFlags = JOY_CAL_READXYONLY;
685 #endif
686
687         if (Cur_joystick >= 0) {
688                 EnterCriticalSection(&joy_lock);
689                 rs = joyGetPosEx(Cur_joystick, &ji);
690                 LeaveCriticalSection(&joy_lock);
691
692                 if (rs == JOYERR_NOERROR) {
693 #if 1
694                         if (x)
695                                 *x = ji.dwXpos;
696                         if (y)
697                                 *y = ji.dwYpos;
698 #else
699                         if (x) {        
700                                 *x = (ji.dwXpos - 32768) * 2;
701                                 if (*x < -65536)
702                                         *x = -65536;
703                                 else if (*x > 65536)
704                                         *x = 65536;
705                         }
706
707                         if (y) {
708                                 *y = (ji.dwYpos - 32768) * 2;
709                                 if (*y < -65536)
710                                         *y = -65536;
711                                 else if (*y > 65536)
712                                         *y = 65536;
713                         }
714 #endif
715                         return 1;
716                 }
717         }
718
719         if (x)
720                 *x = 0;
721         if (y)
722                 *y = 0;
723
724         return 0;
725 }
726
727
728 // --------------------------------------------------------------
729 //      joy_down_count()
730 //
731 //      Return the number of times the joystick button has gone down since
732 // joy_down_count() was last called
733 //
734 //      input:          btn                     =>              button number to check
735 //                                      reset_count     =>              (default 1): if true reset down_count
736 //
737 //      returns:                number of times button 'btn' has gone down since last call
738 //
739 int joy_down_count(int btn, int reset_count)
740 {
741         int tmp;
742
743         if ( joy_num_sticks < 1 ) return 0;
744         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0;
745
746         EnterCriticalSection(&joy_lock);
747         tmp = joy_buttons[btn].down_count;
748         if ( reset_count ) {
749                 joy_buttons[btn].down_count = 0;
750         }
751         LeaveCriticalSection(&joy_lock);
752
753         return tmp;
754 }
755
756
757 // --------------------------------------------------------------
758 //      joy_down()
759 //
760 //      Return the state of button number 'btn'
761 //
762 //      input:          btn     =>              button number to check
763 //
764 //      returns:                0               =>              not pressed
765 //                                      1               =>              pressed
766 //
767 int joy_down(int btn)
768 {
769         int tmp;
770
771         if ( joy_num_sticks < 1 ) return 0;
772         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS )) return 0;
773
774         EnterCriticalSection(&joy_lock);
775         tmp = joy_buttons[btn].state;
776         LeaveCriticalSection(&joy_lock);
777
778         return tmp;
779 }
780
781 // --------------------------------------------------------------
782 //      joy_up_count()
783 //
784 //      Return the number of times the joystick button has gone up since
785 // joy_up_count() was last called
786 //
787 //      input:          btn     =>              button number to check
788 //
789 //      returns:                number of times button 'btn' has gone up since last call
790 //
791 int joy_up_count(int btn)
792 {
793         int tmp;
794
795         if ( joy_num_sticks < 1 ) return 0;
796         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0;
797
798         EnterCriticalSection(&joy_lock);
799         tmp = joy_buttons[btn].up_count;
800         joy_buttons[btn].up_count = 0;
801         LeaveCriticalSection(&joy_lock);
802
803         return tmp;
804 }
805
806 // --------------------------------------------------------------
807 //      joy_down_time()
808 //
809 //      Return a number between 0 and 1.  This number represents the percentage
810 // time that the joystick button has been down since it was last checked
811 //
812 //      input:          btn     =>              button number to check
813 //      returns:                value between 0 and 1
814 //
815 float joy_down_time(int btn)
816 {
817         float                           rval;
818         unsigned int    now;
819         joy_button_info         *bi;
820
821         if ( joy_num_sticks < 1 ) return 0.0f;
822         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0.0f;
823         bi = &joy_buttons[btn];
824         EnterCriticalSection(&joy_lock);
825         
826         now = timer_get_milliseconds();
827
828         if ( bi->down_time == 0 && joy_down(btn) ) {
829                 bi->down_time += joy_pollrate;
830         }
831
832         if ( (now - bi->last_down_check) > 0)
833                 rval = i2fl(bi->down_time) / (now - bi->last_down_check);
834         else
835                 rval = 0.0f;
836
837         bi->down_time = 0;
838         bi->last_down_check = now;
839         
840         LeaveCriticalSection(&joy_lock);
841
842         if (rval < 0)
843                 rval = 0.0f;
844         if (rval > 1)
845                 rval = 1.0f;
846
847         return rval;
848 }
849
850 // --------------------------------------------------------------
851 //      joy_get_cal_vals()
852 //
853 //      Get the calibrated min, center, and max for all axes
854 //
855 //      input:  axis_min                =>              OUTPUT PARAMETER:       array of at least 4 ints to hold min axis values
856 //                              axis_center     =>              OUTPUT PARAMETER:       array of at least 4 ints to hold center axis values
857 //                              axis_min                =>              OUTPUT PARAMETER:       array of at least 4 ints to hold max axis values
858 //
859 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
860 {
861         int i;
862
863         for ( i = 0; i < 4; i++)                {
864                 axis_min[i] = joystick.axis_min[i];
865                 axis_center[i] = joystick.axis_center[i];
866                 axis_max[i] = joystick.axis_max[i];
867         }
868 }
869
870 // --------------------------------------------------------------
871 //      joy_set_cal_vals()
872 //
873 //      Get the calibrated min, center, and max for all axes
874 //
875 //      input:  axis_min                =>              array of at 4 ints that hold min axis values
876 //                              axis_center     =>              array of at 4 ints that hold center axis values
877 //                              axis_min                =>              array of at 4 ints that hold max axis values
878 //
879 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
880 {
881         int i;
882
883         for (i=0; i<4; i++)             {
884                 joystick.axis_min[i] = axis_min[i];
885                 joystick.axis_center[i] = axis_center[i];
886                 joystick.axis_max[i] = axis_max[i];
887         }
888 }
889
890 // --------------------------------------------------------------
891 //      joystick_read_raw_axis()
892 //
893 //      Read the raw axis information for a specified number of axes.
894 //
895 //      input:  num_axes        =>              number of axes to read.  Note the axes go in the following order:
896 //                                                                      dwXpos
897 //                                                                      dwYpos 
898 //                                                                      dwZpos (throttle)
899 //                                                                      dwRpos (rudder)
900 //                                                                      dwUpos (5th axis)
901 //                                                                      dwVpos (6th axis) 
902 //
903 //                              axis            =>              an array of at least 4 ints to hold axis data
904 //
905 int joystick_read_raw_axis(int num_axes, int *axis)
906 {
907         MMRESULT                rs;
908         JOYINFOEX       ji;
909         int                     i;
910
911         Assert(num_axes <= JOY_NUM_AXES);
912         for (i=0; i<num_axes; i++)
913                 axis[i] = 32768;
914
915         // first, try reading with DirectInput, if we can
916         if (Joy_di_inited)
917                 return joystick_read_raw_axis_di(num_axes, axis);
918
919         // No DirectInput joystick, fall back on older stuff
920         if (joy_num_sticks < 1)
921                 return 0;
922
923         memset(&ji, 0, sizeof(ji));
924         ji.dwSize = sizeof(ji);
925
926 #ifdef PRECALIBRATED
927         ji.dwFlags = JOY_RETURNALL;
928 #else
929         ji.dwFlags = JOY_RETURNRAWDATA;
930 #endif
931
932         switch (num_axes) {
933                 case    6:
934                         ji.dwFlags |= JOY_RETURNV;
935                 case    5:
936                         ji.dwFlags |= JOY_RETURNU;
937                 case    4:
938                         ji.dwFlags |= JOY_RETURNR;
939                 case    3:
940                         ji.dwFlags |= JOY_RETURNZ;
941                 case    2:
942                         ji.dwFlags |= JOY_RETURNY;
943                 case    1:
944                         ji.dwFlags |= JOY_RETURNX;
945                         break;
946
947                 default:
948                         Int3();
949                         break;
950         }
951
952         if (Cur_joystick >= 0) {
953                 EnterCriticalSection(&joy_lock);
954                 rs = joyGetPosEx(Cur_joystick, &ji);
955                 LeaveCriticalSection(&joy_lock);
956
957         } else
958                 return 0;
959
960         if (rs != JOYERR_NOERROR)
961                 return 0;
962
963         switch (num_axes) {
964                 case 6:
965                         if (joystick.axis_valid[5])
966                                 axis[5] = ji.dwVpos;
967
968                 case 5:
969                         if (joystick.axis_valid[4])
970                                 axis[4] = ji.dwUpos;
971
972                 case 4:
973                         if (joystick.axis_valid[3])
974                                 axis[3] = ji.dwRpos;
975
976                 case 3:
977                         if (joystick.axis_valid[2])
978                                 axis[2] = ji.dwZpos;
979
980                 case 2:
981                         if (joystick.axis_valid[1])
982                                 axis[1] = ji.dwYpos;
983
984                 case 1:
985                         if (joystick.axis_valid[0])
986                                 axis[0] = ji.dwXpos;
987
988                         break;
989
990                 default:
991                         Int3();
992                         break;
993         }
994
995         return 1;
996 }
997
998 // --------------------------------------------------------------
999 //      joy_set_ul()
1000 //
1001 //      Get the minimum axis information (namely, joystick in upper left).
1002 // This is called by a manual calibration routine.
1003 //
1004 //      NOTE:   sets the values in joystick.axis_min[]
1005 //
1006 void joy_set_ul()       
1007 {
1008         joystick_read_raw_axis( 2, joystick.axis_min );
1009 }
1010
1011 // --------------------------------------------------------------
1012 //      joy_set_lr()
1013 //
1014 //      Get the maximum axis information (namely, joystick in lower right).
1015 // This is called by a manual calibration routine.
1016 //
1017 //      NOTE:   sets the values in joystick.axis_max[]
1018 //
1019 void joy_set_lr()       
1020 {
1021         joystick_read_raw_axis( 2, joystick.axis_max );
1022 }
1023
1024 // --------------------------------------------------------------
1025 //      joy_set_cen()
1026 //
1027 //      Get the center axis information (namely, joystick in dead zone).
1028 // This is called by a manual calibration routine.
1029 //
1030 //      NOTE:   sets the values in joystick.axis_center[]
1031 //
1032 void joy_set_cen() 
1033 {
1034         joystick_read_raw_axis( 2, joystick.axis_center );
1035 }
1036
1037 int joy_get_unscaled_reading(int raw, int axn)
1038 {
1039         int rng;
1040
1041         // Make sure it's calibrated properly.
1042         if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5)
1043                 return 0;
1044
1045         if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5)
1046                 return 0;
1047
1048         rng = joystick.axis_max[axn] - joystick.axis_min[axn];
1049         raw -= joystick.axis_min[axn];  // adjust for linear range starting at 0
1050         
1051         // cap at limits
1052         if (raw < 0)
1053                 raw = 0;
1054         if (raw > rng)
1055                 raw = rng;
1056
1057         return (int) ((unsigned int) raw * (unsigned int) F1_0 / (unsigned int) rng);  // convert to 0 - F1_0 range.
1058 }
1059
1060 // --------------------------------------------------------------
1061 //      joy_get_scaled_reading()
1062 //
1063 //      input:  raw     =>      the raw value for an axis position
1064 //                              axn     =>      axis number, numbered starting at 0
1065 //
1066 // return:      joy_get_scaled_reading will return a value that represents
1067 //                              the joystick pos from -1 to +1 for the specified axis number 'axn', and
1068 //                              the raw value 'raw'
1069 //
1070 int joy_get_scaled_reading(int raw, int axn)
1071 {
1072         int x, d, dead_zone, rng;
1073         float percent, sensitivity_percent, non_sensitivity_percent;
1074
1075         // Make sure it's calibrated properly.
1076         if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5)
1077                 return 0;
1078
1079         if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5)
1080                 return 0;
1081
1082         raw -= joystick.axis_center[axn];
1083
1084         dead_zone = (joystick.axis_max[axn] - joystick.axis_min[axn]) * Dead_zone_size / 100;
1085
1086         if (raw < -dead_zone) {
1087                 rng = joystick.axis_center[axn] - joystick.axis_min[axn] - dead_zone;
1088                 d = -raw - dead_zone;
1089
1090         } else if (raw > dead_zone) {
1091                 rng = joystick.axis_max[axn] - joystick.axis_center[axn] - dead_zone;
1092                 d = raw - dead_zone;
1093
1094         } else
1095                 return 0;
1096
1097         if (d > rng)
1098                 d = rng;
1099
1100         Assert(Joy_sensitivity >= 0 && Joy_sensitivity <= 9);
1101
1102         // compute percentages as a range between 0 and 1
1103         sensitivity_percent = (float) Joy_sensitivity / 9.0f;
1104         non_sensitivity_percent = (float) (9 - Joy_sensitivity) / 9.0f;
1105
1106         // find percent of max axis is at
1107         percent = (float) d / (float) rng;
1108
1109         // work sensitivity on axis value
1110         percent = (percent * sensitivity_percent + percent * percent * percent * percent * percent * non_sensitivity_percent);
1111
1112         x = (int) ((float) F1_0 * percent);
1113
1114         //nprintf(("AI", "d=%6i, sens=%3i, percent=%6.3f, val=%6i, ratio=%6.3f\n", d, Joy_sensitivity, percent, (raw<0) ? -x : x, (float) d/x));
1115
1116         if (raw < 0)
1117                 return -x;
1118
1119         return x;
1120 }
1121
1122 // --------------------------------------------------------------
1123 //      joy_get_pos()
1124 //
1125 //      input:  x               =>              OUTPUT PARAMETER: x-axis position of stick (-1 to 1)
1126 //                              y               =>              OUTPUT PARAMETER: y-axis position of stick (-1 to 1)
1127 //                              z               =>              OUTPUT PARAMETER: z-axis (throttle) position of stick (-1 to 1)
1128 //                              r               =>              OUTPUT PARAMETER: rudder position of stick (-1 to 1)
1129 //
1130 //      return: success => 1
1131 //                              failure => 0
1132 //
1133 int joy_get_pos(int *x, int *y, int *z, int *rx)
1134 {
1135         int axis[JOY_NUM_AXES];
1136
1137         if (x) *x = 0;
1138         if (y) *y = 0;
1139         if (z) *z = 0;
1140         if (rx) *rx = 0;
1141
1142         if (joy_num_sticks < 1) return 0;
1143
1144         joystick_read_raw_axis( 6, axis );
1145
1146         //      joy_get_scaled_reading will return a value represents the joystick pos from -1 to +1
1147         if (x && joystick.axis_valid[0])
1148                 *x = joy_get_scaled_reading(axis[0], 0);
1149         if (y && joystick.axis_valid[1]) 
1150                 *y = joy_get_scaled_reading(axis[1], 1);
1151         if (z && joystick.axis_valid[2])
1152                 *z = joy_get_unscaled_reading(axis[2], 2);
1153         if (rx && joystick.axis_valid[3])
1154                 *rx = joy_get_scaled_reading(axis[3], 3);
1155
1156         if (x)
1157                 Joy_last_x_reading = *x;
1158
1159         if (y)
1160                 Joy_last_x_reading = *y;
1161
1162         return 1;
1163 }
1164
1165 // change in joy position since last call
1166 void joy_get_delta(int *dx, int *dy)
1167 {
1168         static int old_joy_x = 0;
1169         static int old_joy_y = 0;
1170
1171         if ( !Joy_inited ) {
1172                 *dx = *dy = 0;
1173                 return;
1174         }
1175
1176         *dx = Joy_last_x_reading - old_joy_x;
1177         *dy = Joy_last_y_reading - old_joy_y;
1178
1179         old_joy_x = Joy_last_x_reading;
1180         old_joy_y = Joy_last_y_reading;
1181 }
1182
1183 ////  This is the DirectInput joystick stuff
1184
1185 GUID Di_joy_guid;
1186 int Di_joy_guid_valid = 0;
1187
1188 BOOL CALLBACK joy_di_enum(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
1189 {
1190         char buf[64];   
1191
1192         nprintf(("Joystick", "Joystick detected: %s (%s)\n", lpddi->tszInstanceName, lpddi->tszProductName));
1193         sprintf(buf, "Joystick %d", Cur_joystick + 1);
1194         if (!stricmp(buf, lpddi->tszInstanceName)) {
1195                 Di_joy_guid = lpddi->guidInstance;
1196                 Di_joy_guid_valid = 1;
1197                 nprintf(("Joystick", "   (Selected joystick)\n"));
1198         }
1199
1200         return DIENUM_CONTINUE;
1201 }
1202 /*
1203 BOOL FAR PASCAL InitJoystickInput(LPCDIDEVICEINSTANCE pdinst, LPVOID pvRef)
1204 {
1205    LPDIRECTINPUT pdi = pvRef;
1206    LPDIRECTINPUTDEVICE pdev;
1207    DIPROPRANGE diprg;
1208
1209    // create the DirectInput joystick device
1210    if(pdi->lpVtbl->CreateDevice(pdi, &pdinst->guidInstance, &pdev, NULL) != DI_OK)
1211    {
1212       OutputDebugString("IDirectInput::CreateDevice FAILED\n");
1213       return DIENUM_CONTINUE;
1214    }
1215
1216    // set joystick data format
1217    if (pdev->lpVtbl->SetDataFormat(pdev, &c_dfDIJoystick) != DI_OK)
1218    {
1219       OutputDebugString("IDirectInputDevice::SetDataFormat FAILED\n");
1220       pdev->lpVtbl->Release(pdev);
1221       return DIENUM_CONTINUE;
1222    }
1223
1224    // set the cooperative level
1225    if (pdev->lpVtbl->SetCooperativeLevel(pdev, hWndMain,
1226       DISCL_NONEXCLUSIVE | DISCL_FOREGROUND) != DI_OK)
1227    {
1228       OutputDebugString("IDirectInputDevice::SetCooperativeLevel FAILED\n");
1229       pdev->lpVtbl->Release(pdev);
1230       return DIENUM_CONTINUE;
1231    }
1232
1233    // set X-axis range to (-1000 ... +1000)
1234    // This lets us test against 0 to see which way the stick is pointed.
1235
1236    diprg.diph.dwSize       = sizeof(diprg);
1237    diprg.diph.dwHeaderSize = sizeof(diprg.diph);
1238    diprg.diph.dwObj        = DIJOFS_X;
1239    diprg.diph.dwHow        = DIPH_BYOFFSET;
1240    diprg.lMin              = -1000;
1241    diprg.lMax              = +1000;
1242
1243    if (pdev->lpVtbl->SetProperty(pdev, DIPROP_RANGE, &diprg.diph) != DI_OK)
1244    {
1245       OutputDebugString("IDirectInputDevice::SetProperty(DIPH_RANGE) FAILED\n");
1246       pdev->lpVtbl->Release(pdev);
1247       return FALSE;
1248    }
1249
1250    //
1251    // And again for Y-axis range
1252    //
1253    diprg.diph.dwObj        = DIJOFS_Y;
1254
1255    if (pdev->lpVtbl->SetProperty(pdev, DIPROP_RANGE, &diprg.diph) != DI_OK)
1256    {
1257       OutputDebugString("IDirectInputDevice::SetProperty(DIPH_RANGE) FAILED\n");
1258       pdev->lpVtbl->Release(pdev);
1259       return FALSE;
1260    }
1261
1262    // set X axis dead zone to 50% (to avoid accidental turning)
1263    // Units are ten thousandths, so 50% = 5000/10000.
1264    if (SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_X, DIPH_BYOFFSET, 5000) != DI_OK)
1265    {
1266       OutputDebugString("IDirectInputDevice::SetProperty(DIPH_DEADZONE) FAILED\n");
1267       pdev->lpVtbl->Release(pdev);
1268       return FALSE;
1269    }
1270
1271
1272    // set Y axis dead zone to 50% (to avoid accidental thrust)
1273    // Units are ten thousandths, so 50% = 5000/10000.
1274    if (SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_Y, DIPH_BYOFFSET, 5000) != DI_OK)
1275    {
1276       OutputDebugString("IDirectInputDevice::SetProperty(DIPH_DEADZONE) FAILED\n");
1277       pdev->lpVtbl->Release(pdev);
1278       return FALSE;
1279    }
1280
1281
1282    // Add it to our list of devices.  If AddInputDevice succeeds,
1283    // he will do an AddRef.
1284    AddInputDevice(pdev, pdinst);
1285         hRes = pdev->lpVtbl->QueryInterface(
1286                     pdev, &IID_IDirectInputDevice2,
1287                     (LPVOID *)&g_rgpdevFound[g_cpdevFound]);
1288
1289    pdev->lpVtbl->Release(pdev);
1290
1291    return DIENUM_CONTINUE;
1292 }
1293 */
1294 int joy_di_init()
1295 {
1296         HRESULT hr;
1297    LPDIRECTINPUTDEVICE pdev;
1298
1299         Joy_di_inited = 0;
1300         hr = DirectInputCreate(GetModuleHandle(NULL), 0x500, &Di_joystick_obj, NULL);
1301         if (FAILED(hr)) {
1302                 mprintf(( "DirectInputCreate() failed!\n" ));
1303                 return -1;
1304         }
1305
1306         Di_joy_guid_valid = 0;
1307         hr = Di_joystick_obj->EnumDevices(DIDEVTYPE_JOYSTICK, joy_di_enum, Di_joystick_obj, DIEDFL_ATTACHEDONLY);
1308         if (FAILED(hr)) {
1309                 mprintf(( "EnumDevice() failed!\n" ));
1310                 return -1;
1311         }
1312
1313         if (!Di_joy_guid_valid) {
1314                 mprintf(( "Correct joystick not found.\n" ));
1315                 return -1;
1316         }
1317
1318         hr = Di_joystick_obj->CreateDevice(Di_joy_guid, &pdev, NULL);
1319         if (FAILED(hr)) {
1320                 mprintf(( "CreateDevice() failed!\n" ));
1321                 return -1;
1322         }
1323
1324         hr = pdev->SetDataFormat(&c_dfDIJoystick);
1325         if (FAILED(hr)) {
1326                 mprintf(( "SetDataFormat() failed!\n" ));
1327                 if (hr == DIERR_ACQUIRED)
1328                         mprintf(( "   (reason: DIERR_ACQUIRED)\n" ));
1329
1330                 if (hr == DIERR_INVALIDPARAM)
1331                         mprintf(( "   (reason: DIERR_INVALIDPARAM)\n" ));
1332
1333                 if (hr == DIERR_NOTINITIALIZED)
1334                         mprintf(( "   (reason: DIERR_NOTINITIALIZED)\n" ));
1335
1336                 pdev->Release();
1337                 return -1;
1338         }
1339
1340         hr = pdev->SetCooperativeLevel((HWND) os_get_window(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
1341         if (FAILED(hr)) {
1342                 mprintf(( "SetCooperativeLevel() failed!\n" ));
1343                 if (hr == DIERR_ACQUIRED)
1344                         mprintf(( "   (reason: DIERR_ACQUIRED)\n" ));
1345
1346                 if (hr == DIERR_INVALIDPARAM)
1347                         mprintf(( "   (reason: DIERR_INVALIDPARAM)\n" ));
1348
1349                 if (hr == DIERR_NOTINITIALIZED)
1350                         mprintf(( "   (reason: DIERR_NOTINITIALIZED)\n" ));
1351
1352                 pdev->Release();
1353                 return -1;
1354         }
1355
1356         hr = pdev->QueryInterface(IID_IDirectInputDevice2, (LPVOID *) &Di_joystick);
1357         if (FAILED(hr)) {
1358                 pdev->Release();
1359                 return -1;
1360         }
1361
1362         Di_joystick->Acquire();
1363
1364         pdev->Release();
1365         Joy_di_inited = 1;
1366         nprintf(("Joystick", "DirectInput initialization of joystick succeeded\n"));
1367         return 0;
1368 }
1369
1370 int joy_di_shutdown()
1371 {
1372         // Destroy any lingering IDirectInputDevice object.
1373         if (Di_joystick) {
1374                 // Unacquire the device one last time just in case we got really confused
1375                 // and tried to exit while the device is still acquired.
1376                 Di_joystick->Unacquire();
1377
1378                 Di_joystick->Release();
1379                 Di_joystick = NULL;
1380         }
1381
1382         // Destroy any lingering IDirectInput object.
1383         if (Di_joystick_obj) {
1384                 Di_joystick_obj->Release();
1385                 Di_joystick_obj = NULL;
1386         }
1387
1388         Joy_di_inited = 0;
1389         return 0;
1390 }
1391
1392 int joystick_read_raw_axis_di(int num_axes, int *axis)
1393 {
1394         int repeat = 1;
1395         HRESULT hr = 0;
1396         DIJOYSTATE joy_state;
1397
1398         if (!Joy_di_inited)
1399                 return 0;
1400
1401         repeat = 1;
1402         while (repeat) {
1403                 repeat = 0;
1404
1405            hr = Di_joystick->Poll();
1406                 if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) {
1407                         // DirectInput is telling us that the input stream has
1408                         // been interrupted.  We aren't tracking any state
1409                         // between polls, so we don't have any special reset
1410                         // that needs to be done.  We just re-acquire and
1411                         // try again.
1412                         Sleep(1000);            // Pause a second...
1413                         hr = Di_joystick->Acquire();
1414                         if (SUCCEEDED(hr))
1415                                 repeat = 1;
1416                 }
1417         }
1418
1419         repeat = 1;
1420         memset(&joy_state, 0, sizeof(joy_state));
1421         while (repeat) {
1422                 repeat = 0;
1423
1424                 hr = Di_joystick->GetDeviceState(sizeof(joy_state), &joy_state);
1425                 if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) {
1426                         // DirectInput is telling us that the input stream has
1427                         // been interrupted.  We aren't tracking any state
1428                         // between polls, so we don't have any special reset
1429                         // that needs to be done.  We just re-acquire and
1430                         // try again.
1431                         Sleep(1000);            // Pause a second...
1432                         hr = Di_joystick->Acquire();
1433                         if (SUCCEEDED(hr))
1434                                 repeat = 1;
1435                 }
1436         }
1437
1438         if (SUCCEEDED(hr)) {
1439                 switch (num_axes) {
1440                         case 6:
1441                                 if (joystick.axis_valid[5])
1442                                         axis[5] = joy_state.lRy;
1443
1444                         case 5:
1445                                 if (joystick.axis_valid[4])
1446                                         axis[4] = joy_state.lRx;
1447
1448                         case 4:
1449                                 if (joystick.axis_valid[3])
1450                                         axis[3] = joy_state.lRz;
1451
1452                         case 3:
1453                                 if (joystick.axis_valid[2])
1454                                         axis[2] = joy_state.lZ;
1455
1456                         case 2:
1457                                 if (joystick.axis_valid[1])
1458                                         axis[1] = joy_state.lY;
1459
1460                         case 1:
1461                                 if (joystick.axis_valid[0])
1462                                         axis[0] = joy_state.lX;
1463
1464                                 break;
1465                 }
1466         }
1467
1468         return 1;
1469 }
1470