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