FS2_Open
Open source remastering of the Freespace 2 engine
joy.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 #include <windows.h>
13 #include <windowsx.h>
14 
15 #include "globalincs/pstypes.h"
16 #include "io/joy.h"
17 #include "math/fix.h"
18 #include "io/key.h"
19 #include "io/timer.h"
20 #include "osapi/osregistry.h"
21 #include "io/joy_ff.h"
22 #include "directx/vdinput.h"
23 #include "osapi/osapi.h"
24 #include "debugconsole/console.h"
25 
26 
27 #define PRECALIBRATED 1
28 
29 static int Joy_inited = 0;
31 int Dead_zone_size = 10;
32 int Cur_joystick = -1; // joystick used for input or -1
34 
36 
39 int joy_pollrate = 1000 / 18; // poll at 18Hz
40 
43 
44 static int Joy_last_x_reading = 0;
45 static int Joy_last_y_reading = 0;
46 
47 int Joy_di_inited = 0;
48 static LPDIRECTINPUT Di_joystick_obj = NULL;
49 static LPDIRECTINPUTDEVICE2 Di_joystick = NULL;
50 
51 typedef struct joy_button_info {
52  int actual_state; // Set if the button is physically down
53  int state; // Set when the button goes from up to down, cleared on down to up. Different than actual_state after a flush.
54  int down_count;
55  int up_count;
56  int down_time;
57  uint last_down_check; // timestamp in milliseconds of last
59 
61 
63 
64 int joy_di_init();
65 int joy_di_shutdown();
66 int joystick_read_raw_axis_di(int num_axes, int *axis);
67 
68 // --------------------------------------------------------------
69 // joy_flush()
70 //
71 // Clear the state of the joystick.
72 //
73 void joy_flush()
74 {
75  int i;
76  joy_button_info *bi;
77 
78  if ( joy_num_sticks < 1 ) return;
79 
80  EnterCriticalSection(&joy_lock);
81  for ( i = 0; i < JOY_TOTAL_BUTTONS; i++) {
82  bi = &joy_buttons[i];
83  bi->state = 0;
84  bi->down_count = 0;
85  bi->up_count = 0;
86  bi->down_time = 0;
88  }
89 
90  LeaveCriticalSection(&joy_lock);
91 }
92 
93 // --------------------------------------------------------------
94 // joy_process()
95 //
96 // Runs as a separate thread, and updates the state of the joystick
97 //
99 {
100  MMRESULT rs;
101  JOYINFOEX ji;
102  int i,state;
103  joy_button_info *bi;
104  EXECUTION_STATE last_exectution_state = 0;
105  uint last_ssav_time = 0;
106 
107 
108  // power management stuff, we need to handle this manually for joysticks
109  {
110  // give notification that we need both display and system (for multi) resources to remain available
111  // NOTE: we'll have to restore the previous execution state before exiting this thread
112  last_exectution_state = SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED);
113 
114  // turn of screen saver, but save the current timeout so that we can restore it later
115  SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &last_ssav_time, 0);
116  SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
117  }
118 
119 
120  for ( i = 0; i < JOY_TOTAL_BUTTONS; i++) {
121  bi = &joy_buttons[i];
122  bi->actual_state = 0; // Don't set in flush code!
123  bi->state = 0;
124  bi->down_count = 0;
125  bi->up_count = 0;
126  bi->down_time = 0;
128  }
129 
130  while (1) {
131  // Wait for the thread to be signaled to end or 1/18th of a second to pass...
132  if ( WaitForSingleObject( Joy_tell_thread_to_end_event, joy_pollrate )==WAIT_OBJECT_0) {
133  break;
134  }
135 
136  memset(&ji, 0, sizeof(ji));
137  ji.dwSize = sizeof(ji);
138 // ji.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNRAWDATA;
139  ji.dwFlags = JOY_RETURNALL;
140 
141  EnterCriticalSection(&joy_lock);
142 
143  uint joy_state = 0;
144  if (Cur_joystick >= 0) {
145  rs = joyGetPosEx(Cur_joystick, &ji);
146  // If there's an error, assume all buttons down.
147  if (rs == JOYERR_NOERROR) {
148  joy_state = ji.dwButtons;
149  }
150  }
151 
152  // Process ji.dwButtons
153  for (i=0; i<JOY_TOTAL_BUTTONS; i++) {
154  state = 0;
155  if (i < JOY_NUM_BUTTONS) {
156  state = joy_state & (1<<i);
157 
158  } else {
159  // check for hat presses, which act like buttons
160  switch (i) {
161  case JOY_HATBACK:
162  if (ji.dwPOV == JOY_POVBACKWARD)
163  state = 1;
164  break;
165 
166  case JOY_HATFORWARD:
167  if (ji.dwPOV == JOY_POVFORWARD)
168  state = 1;
169  break;
170 
171  case JOY_HATLEFT:
172  if (ji.dwPOV == JOY_POVLEFT)
173  state = 1;
174  break;
175 
176  case JOY_HATRIGHT:
177  if (ji.dwPOV == JOY_POVRIGHT)
178  state = 1;
179  break;
180 
181  default:
182  Int3(); // should never happen
183  break;
184 
185  } // end switch
186  } // end if
187 
188 
189  if (state != joy_buttons[i].actual_state) {
190  // Button position physically changed.
191  joy_buttons[i].actual_state = state;
192 
193  if ( state ) {
194  // went from up to down
195  joy_buttons[i].down_count++;
196  joy_buttons[i].down_time = 0;
197 
198  joy_buttons[i].state = 1;
199  } else {
200  // went from down to up
201  if ( joy_buttons[i].state ) {
202  joy_buttons[i].up_count++;
203  }
204  joy_buttons[i].state = 0;
205  }
206 
207  } else {
208  // Didn't move... increment time down if down.
209  if (joy_buttons[i].state) {
210  joy_buttons[i].down_time += joy_pollrate;
211  }
212  }
213 
214  } // end for
215 
216  LeaveCriticalSection(&joy_lock);
217  }
218 
219  // power management stuff, we need to handle this manually for joysticks
220  {
221  // restore the original execution state
222  last_exectution_state = SetThreadExecutionState(last_exectution_state);
223 
224  // restore the original screensaver timeout value
225  SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, last_ssav_time, NULL, 0);
226  }
227 
229 
230  return 0;
231 }
232 
233 // --------------------------------------------------------------
234 // joy_close()
235 //
236 // Close the joystick system. Should be called at game exit.
237 //
238 void joy_close()
239 {
240  if (!Joy_inited)
241  return;
242 
243  // joy_di_shutdown();
244 
245  Joy_inited = 0;
246  joy_num_sticks = 0;
247 
248  // Tell joystick polling thread to end
250 
251  // Wait for it to end
252  if ( WaitForSingleObject( Joy_thread_says_its_done_event, 5000 )==WAIT_TIMEOUT) { //INFINITE );
253  mprintf(( "Joy end thread wait timeout!\n" ));
254  }
255  CloseHandle(Joy_tell_thread_to_end_event);
256  CloseHandle(Joy_thread_says_its_done_event);
257 
258  // It is now safe to release any resources use by the polling thread.
259  DeleteCriticalSection( &joy_lock );
260  if (joy_thread) {
261  CloseHandle(joy_thread);
262  joy_thread = NULL;
263  }
264 
265  joy_ff_shutdown();
266 }
267 
268 // --------------------------------------------------------------
269 // joy_get_caps()
270 //
271 // Determine the capabilities of the attached joysticks.
272 //
273 void joy_get_caps(int max)
274 {
275  JOYCAPS JoyCaps;
276  int j;
277 
278  for (j=0; j<JOY_NUM_AXES; j++)
279  joystick.axis_valid[j] = 0;
280 
281  for (j=JOYSTICKID1; j<JOYSTICKID1+max; j++) {
282  if (JOYERR_NOERROR == joyGetDevCaps (j, &JoyCaps, sizeof(JoyCaps))) {
283  nprintf(("JOYSTICK", "Joystick #%d: %s\n", j - JOYSTICKID1 + 1, JoyCaps.szPname));
284 
285  if (j == Cur_joystick) {
286  joystick.axis_valid[0] = joystick.axis_valid[1] = 1;
287  if (JoyCaps.wCaps & JOYCAPS_HASZ)
288  joystick.axis_valid[2] = 1;
289  if (JoyCaps.wCaps & JOYCAPS_HASR)
290  joystick.axis_valid[3] = 1;
291  if (JoyCaps.wCaps & JOYCAPS_HASU)
292  joystick.axis_valid[4] = 1;
293  if (JoyCaps.wCaps & JOYCAPS_HASV)
294  joystick.axis_valid[5] = 1;
295  }
296  }
297  }
298 }
299 
300 int joy_get_scaled_reading(int raw, int axn);
301 int joy_get_unscaled_reading(int raw, int axn);
302 
303 DCF(joytest, "Test joystick")
304 {
305  if (dc_optional_string_either("help", "?") || dc_optional_string_either("--help", "--?"))
306  {
307  dc_printf("Real-time test of the joystick's X and Y axes. Readings are taken from the joystick and directly");
308  dc_printf("spewed to a popup window. Press ESC to abort the test.\n");
309 
310  dc_printf("First pair of readings are the raw values as reported by the OS's input library. Second pair of");
311  dc_printf("readings are what the engine uses for controls\n");
312  return;
313  }
314 
315  while (!keyd_pressed[KEY_ESC]) {
316  int x, y, axis[JOY_NUM_AXES];
317 
318  if (joy_num_sticks < 1)
319  return;
320 
322 
323  x = joy_get_scaled_reading(axis[0], 0);
324  y = joy_get_scaled_reading(axis[1], 1);
325 
326  mprintf(("X=%5d Y=%5d Calibrated X=%6d Y=%6d\n", axis[0], axis[1], x, y));
327  Sleep(100);
328  }
329 
330 }
331 
332 DCF(joytest2, "Test joystick (extended)")
333 {
334  if (dc_optional_string_either("help", "?") || dc_optional_string_either("--help", "--?"))
335  {
336  dc_printf("Real-time test of the joystick's X, Y, Z, Rx, Ry, and Rz axes. Readings are taken from the joystick");
337  dc_printf("and directly spewed to a popup window. Press ESC to abort the test.");
338 
339  dc_printf("First set of readings are the raw values as reported by the OS's input library. Second set of");
340  dc_printf("readings are what the engine uses for controls\n");
341  return;
342  }
343 
344  while (!keyd_pressed[KEY_ESC]) {
345  int x, y, z, r, axis[JOY_NUM_AXES];
346 
347  if (joy_num_sticks < 1)
348  return;
349 
351 
352  x = joy_get_scaled_reading(axis[0], 0);
353  y = joy_get_scaled_reading(axis[1], 1);
354  z = joy_get_unscaled_reading(axis[2], 2);
355  r = joy_get_scaled_reading(axis[3], 3);
356 
357  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));
358  Sleep(100);
359  }
360 }
361 
362 // --------------------------------------------------------------
363 // joy_init()
364 //
365 // Initialize the joystick system. This is called once at game startup.
366 //
367 
368 int joy_init()
369 {
370  int i, n, count;
371  MMRESULT rs;
372  JOYINFOEX ji;
373 
374  if (Joy_inited)
375  return 0;
376 
377  Joy_inited = 1;
378  n = joyGetNumDevs();
379  Cur_joystick = os_config_read_uint(NULL, "CurrentJoystick", JOYSTICKID1);
380 
381  joy_get_caps(n);
382 
383  if (n < 1) {
384  mprintf(("No joystick driver detected\n"));
385  return 0;
386  }
387 
388  InitializeCriticalSection(&joy_lock);
389  atexit(joy_close);
390 
391  joy_flush();
392 
393  joy_num_sticks = 0;
394  memset(&ji, 0, sizeof(ji));
395  ji.dwSize = sizeof(ji);
396  ji.dwFlags = JOY_RETURNALL;
397 
398  if (Cur_joystick >= 0) {
399  // AL: test code to try and find out why this call fails the first time
400  rs = 0;
401  for (count=0; count<20; count++) {
402  rs = joyGetPosEx(Cur_joystick, &ji);
403  if (rs == JOYERR_NOERROR)
404  break;
405  }
406 
407  if (rs == JOYERR_NOERROR) {
408  joy_num_sticks++;
409 
410  Joy_tell_thread_to_end_event = CreateEvent( NULL, FALSE, FALSE, NULL );
411  Joy_thread_says_its_done_event = CreateEvent( NULL, FALSE, FALSE, NULL );
412 
413  joy_thread = CreateThread(NULL,
414  1024 * 32,
415  (LPTHREAD_START_ROUTINE) joy_process,
416  NULL,
417  0,
418  &joy_thread_id);
419 
420  // SetThreadPriority(joy_thread, THREAD_PRIORITY_TIME_CRITICAL - 1);
421  SetThreadPriority(joy_thread, THREAD_PRIORITY_HIGHEST);
422  }
423  }
424 
425  mprintf(("Windows reported %d joysticks, we found %d\n", n, joy_num_sticks));
426 
427 #ifdef PRECALIBRATED
428  // Fake a calibration
429  if (joy_num_sticks > 0) {
430  for (i=0; i<4; i++) {
431  joystick.axis_min[i] = 0;
432  joystick.axis_center[i] = 32768;
433  joystick.axis_max[i] = 65536;
434  }
435  }
436 #else
437  // Fake a calibration
438  if (joy_num_sticks > 0) {
439  joy_set_cen();
440  for (i=0; i<4; i++) {
441  joystick.axis_min[i] = 0;
442  joystick.axis_max[i] = joystick.axis_center[i]*2;
443  }
444  }
445 #endif
446 
447  joy_ff_init();
448  // joy_di_init();
449 
450  return joy_num_sticks;
451 }
452 
453 // --------------------------------------------------------------
454 // joy_cheap_cal()
455 //
456 // Manual calibrate joystick routine
457 //
458 void joy_cheap_cal()
459 {
460  if ( joy_num_sticks < 1 ) return;
461 
462  while(1) {
463  Sleep(50);
464  if ( key_inkey()) break;
465  if (joy_down_count(0)) break;
466  mprintf(( "Move stick to upper-left and hit button\n" ));
467  }
468  joy_set_ul();
469 
470  while(1) {
471  Sleep(50);
472  if ( key_inkey()) break;
473  if (joy_down_count(0)) break;
474  mprintf(( "Move stick to lower-right and hit button\n" ));
475  }
476  joy_set_lr();
477 
478  while(1) {
479  Sleep(50);
480  if ( key_inkey()) break;
481  if (joy_down_count(0)) break;
482  mprintf(( "Move stick to center and hit button\n" ));
483  }
484  joy_set_cen();
485 }
486 
487 // --------------------------------------------------------------
488 // joy_get_pos_old()
489 //
490 // Get the position of the joystick axes
491 //
492 int joy_get_pos_old(int * x, int * y )
493 {
494  MMRESULT rs;
495  JOYINFOEX ji;
496 
497  if ( joy_num_sticks < 1 ) {
498  if (x) *x = 0;
499  if (y) *y = 0;
500  return 0;
501  }
502 
503  memset(&ji, 0, sizeof(ji));
504  ji.dwSize = sizeof(ji);
505 
506 #ifdef PRECALIBRATED
507 //JOY_USEDEADZONE|
508 //JOY_RETURNCENTERED|
509 //JOY_RETURNX|JOY_RETURNY|JOY_RETURNRAWDATA;
510  ji.dwFlags = JOY_RETURNALL;
511 #else
512  ji.dwFlags = JOY_CAL_READXYONLY;
513 #endif
514 
515  if (Cur_joystick >= 0) {
516  EnterCriticalSection(&joy_lock);
517  rs = joyGetPosEx(Cur_joystick, &ji);
518  LeaveCriticalSection(&joy_lock);
519 
520  if (rs == JOYERR_NOERROR) {
521 #if 1
522  if (x)
523  *x = ji.dwXpos;
524  if (y)
525  *y = ji.dwYpos;
526 #else
527  if (x) {
528  *x = (ji.dwXpos - 32768) * 2;
529  if (*x < -65536)
530  *x = -65536;
531  else if (*x > 65536)
532  *x = 65536;
533  }
534 
535  if (y) {
536  *y = (ji.dwYpos - 32768) * 2;
537  if (*y < -65536)
538  *y = -65536;
539  else if (*y > 65536)
540  *y = 65536;
541  }
542 #endif
543  return 1;
544  }
545  }
546 
547  if (x)
548  *x = 0;
549  if (y)
550  *y = 0;
551 
552  return 0;
553 }
554 
555 
556 // --------------------------------------------------------------
557 // joy_down_count()
558 //
559 // Return the number of times the joystick button has gone down since
560 // joy_down_count() was last called
561 //
562 // input: btn => button number to check
563 // reset_count => (default 1): if true reset down_count
564 //
565 // returns: number of times button 'btn' has gone down since last call
566 //
567 int joy_down_count(int btn, int reset_count)
568 {
569  int tmp;
570 
571  if ( joy_num_sticks < 1 ) return 0;
572  if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0;
573 
574  EnterCriticalSection(&joy_lock);
575  tmp = joy_buttons[btn].down_count;
576  if ( reset_count ) {
577  joy_buttons[btn].down_count = 0;
578  }
579  LeaveCriticalSection(&joy_lock);
580 
581  return tmp;
582 }
583 
584 
585 // --------------------------------------------------------------
586 // joy_down()
587 //
588 // Return the state of button number 'btn'
589 //
590 // input: btn => button number to check
591 //
592 // returns: 0 => not pressed
593 // 1 => pressed
594 //
595 int joy_down(int btn)
596 {
597  int tmp;
598 
599  if ( joy_num_sticks < 1 ) return 0;
600  if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS )) return 0;
601 
602  EnterCriticalSection(&joy_lock);
603  tmp = joy_buttons[btn].state;
604  LeaveCriticalSection(&joy_lock);
605 
606  return tmp;
607 }
608 
609 // --------------------------------------------------------------
610 // joy_up_count()
611 //
612 // Return the number of times the joystick button has gone up since
613 // joy_up_count() was last called
614 //
615 // input: btn => button number to check
616 //
617 // returns: number of times button 'btn' has gone up since last call
618 //
619 int joy_up_count(int btn)
620 {
621  int tmp;
622 
623  if ( joy_num_sticks < 1 ) return 0;
624  if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0;
625 
626  EnterCriticalSection(&joy_lock);
627  tmp = joy_buttons[btn].up_count;
628  joy_buttons[btn].up_count = 0;
629  LeaveCriticalSection(&joy_lock);
630 
631  return tmp;
632 }
633 
634 // --------------------------------------------------------------
635 // joy_down_time()
636 //
637 // Return a number between 0 and 1. This number represents the percentage
638 // time that the joystick button has been down since it was last checked
639 //
640 // input: btn => button number to check
641 // returns: value between 0 and 1
642 //
643 float joy_down_time(int btn)
644 {
645  float rval;
646  unsigned int now;
647  joy_button_info *bi;
648 
649  if ( joy_num_sticks < 1 ) return 0.0f;
650  if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0.0f;
651  bi = &joy_buttons[btn];
652  EnterCriticalSection(&joy_lock);
653 
654  now = timer_get_milliseconds();
655 
656  if ( bi->down_time == 0 && joy_down(btn) ) {
657  bi->down_time += joy_pollrate;
658  }
659 
660  if (now > bi->last_down_check)
661  rval = i2fl(bi->down_time) / (now - bi->last_down_check);
662  else
663  rval = 0.0f;
664 
665  bi->down_time = 0;
666  bi->last_down_check = now;
667 
668  LeaveCriticalSection(&joy_lock);
669 
670  if (rval < 0)
671  rval = 0.0f;
672  if (rval > 1)
673  rval = 1.0f;
674 
675  return rval;
676 }
677 
678 // --------------------------------------------------------------
679 // joy_get_cal_vals()
680 //
681 // Get the calibrated min, center, and max for all axes
682 //
683 // input: axis_min => OUTPUT PARAMETER: array of at least 4 ints to hold min axis values
684 // axis_center => OUTPUT PARAMETER: array of at least 4 ints to hold center axis values
685 // axis_min => OUTPUT PARAMETER: array of at least 4 ints to hold max axis values
686 //
687 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
688 {
689  int i;
690 
691  for ( i = 0; i < 4; i++) {
692  axis_min[i] = joystick.axis_min[i];
693  axis_center[i] = joystick.axis_center[i];
694  axis_max[i] = joystick.axis_max[i];
695  }
696 }
697 
698 // --------------------------------------------------------------
699 // joy_set_cal_vals()
700 //
701 // Get the calibrated min, center, and max for all axes
702 //
703 // input: axis_min => array of at 4 ints that hold min axis values
704 // axis_center => array of at 4 ints that hold center axis values
705 // axis_min => array of at 4 ints that hold max axis values
706 //
707 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
708 {
709  int i;
710 
711  for (i=0; i<4; i++) {
712  joystick.axis_min[i] = axis_min[i];
713  joystick.axis_center[i] = axis_center[i];
714  joystick.axis_max[i] = axis_max[i];
715  }
716 }
717 
718 // --------------------------------------------------------------
719 // joystick_read_raw_axis()
720 //
721 // Read the raw axis information for a specified number of axes.
722 //
723 // input: num_axes => number of axes to read. Note the axes go in the following order:
724 // dwXpos
725 // dwYpos
726 // dwZpos (throttle)
727 // dwRpos (rudder)
728 // dwUpos (5th axis)
729 // dwVpos (6th axis)
730 //
731 // axis => an array of at least 4 ints to hold axis data
732 //
733 int joystick_read_raw_axis(int num_axes, int *axis)
734 {
735  MMRESULT rs;
736  JOYINFOEX ji;
737  int i;
738 
739  Assert(num_axes <= JOY_NUM_AXES);
740  for (i=0; i<num_axes; i++)
741  axis[i] = 32768;
742 
743  // first, try reading with DirectInput, if we can
744  if (Joy_di_inited)
745  return joystick_read_raw_axis_di(num_axes, axis);
746 
747  // No DirectInput joystick, fall back on older stuff
748  if (joy_num_sticks < 1)
749  return 0;
750 
751  memset(&ji, 0, sizeof(ji));
752  ji.dwSize = sizeof(ji);
753 
754 #ifdef PRECALIBRATED
755  ji.dwFlags = JOY_RETURNALL;
756 #else
757  ji.dwFlags = JOY_RETURNRAWDATA;
758 #endif
759 
760  switch (num_axes) {
761  case 6:
762  ji.dwFlags |= JOY_RETURNV;
763  case 5:
764  ji.dwFlags |= JOY_RETURNU;
765  case 4:
766  ji.dwFlags |= JOY_RETURNR;
767  case 3:
768  ji.dwFlags |= JOY_RETURNZ;
769  case 2:
770  ji.dwFlags |= JOY_RETURNY;
771  case 1:
772  ji.dwFlags |= JOY_RETURNX;
773  break;
774 
775  default:
776  Int3();
777  break;
778  }
779 
780  if (Cur_joystick >= 0) {
781  EnterCriticalSection(&joy_lock);
782  rs = joyGetPosEx(Cur_joystick, &ji);
783  LeaveCriticalSection(&joy_lock);
784 
785  } else
786  return 0;
787 
788  if (rs != JOYERR_NOERROR)
789  return 0;
790 
791  switch (num_axes) {
792  case 6:
793  if (joystick.axis_valid[5])
794  axis[5] = ji.dwVpos;
795 
796  case 5:
797  if (joystick.axis_valid[4])
798  axis[4] = ji.dwUpos;
799 
800  case 4:
801  if (joystick.axis_valid[3])
802  axis[3] = ji.dwRpos;
803 
804  case 3:
805  if (joystick.axis_valid[2])
806  axis[2] = ji.dwZpos;
807 
808  case 2:
809  if (joystick.axis_valid[1])
810  axis[1] = ji.dwYpos;
811 
812  case 1:
813  if (joystick.axis_valid[0])
814  axis[0] = ji.dwXpos;
815 
816  break;
817 
818  default:
819  Int3();
820  break;
821  }
822 
823  return 1;
824 }
825 
826 // --------------------------------------------------------------
827 // joy_set_ul()
828 //
829 // Get the minimum axis information (namely, joystick in upper left).
830 // This is called by a manual calibration routine.
831 //
832 // NOTE: sets the values in joystick.axis_min[]
833 //
834 void joy_set_ul()
835 {
836  joystick_read_raw_axis( 2, joystick.axis_min );
837 }
838 
839 // --------------------------------------------------------------
840 // joy_set_lr()
841 //
842 // Get the maximum axis information (namely, joystick in lower right).
843 // This is called by a manual calibration routine.
844 //
845 // NOTE: sets the values in joystick.axis_max[]
846 //
847 void joy_set_lr()
848 {
849  joystick_read_raw_axis( 2, joystick.axis_max );
850 }
851 
852 // --------------------------------------------------------------
853 // joy_set_cen()
854 //
855 // Get the center axis information (namely, joystick in dead zone).
856 // This is called by a manual calibration routine.
857 //
858 // NOTE: sets the values in joystick.axis_center[]
859 //
860 void joy_set_cen()
861 {
862  joystick_read_raw_axis( 2, joystick.axis_center );
863 }
864 
865 int joy_get_unscaled_reading(int raw, int axn)
866 {
867  int rng;
868 
869  // Make sure it's calibrated properly.
870  if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5)
871  return 0;
872 
873  if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5)
874  return 0;
875 
876  rng = joystick.axis_max[axn] - joystick.axis_min[axn];
877  raw -= joystick.axis_min[axn]; // adjust for linear range starting at 0
878 
879  // cap at limits
880  if (raw < 0)
881  raw = 0;
882  if (raw > rng)
883  raw = rng;
884 
885  return (int) ((unsigned int) raw * (unsigned int) F1_0 / (unsigned int) rng); // convert to 0 - F1_0 range.
886 }
887 
888 // --------------------------------------------------------------
889 // joy_get_scaled_reading()
890 //
891 // input: raw => the raw value for an axis position
892 // axn => axis number, numbered starting at 0
893 //
894 // return: joy_get_scaled_reading will return a value that represents
895 // the joystick pos from -1 to +1 for the specified axis number 'axn', and
896 // the raw value 'raw'
897 //
898 int joy_get_scaled_reading(int raw, int axn)
899 {
900  int x, d, dead_zone, rng;
901  float percent;
902 
903  // Make sure it's calibrated properly.
904  if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5)
905  return 0;
906 
907  if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5)
908  return 0;
909 
910  raw -= joystick.axis_center[axn];
911 
912  dead_zone = (joystick.axis_max[axn] - joystick.axis_min[axn]) * Dead_zone_size / 100;
913 
914  if (raw < -dead_zone) {
915  rng = joystick.axis_center[axn] - joystick.axis_min[axn] - dead_zone;
916  d = -raw - dead_zone;
917 
918  } else if (raw > dead_zone) {
919  rng = joystick.axis_max[axn] - joystick.axis_center[axn] - dead_zone;
920  d = raw - dead_zone;
921 
922  } else
923  return 0;
924 
925  if (d > rng)
926  d = rng;
927 
928  Assert(Joy_sensitivity >= 0 && Joy_sensitivity <= 9);
929 
930  // find percent of max axis is at
931  percent = (float) d / (float) rng;
932 
933  // work sensitivity on axis value
934  percent = pow(percent, (3.0f - ((float) Joy_sensitivity / 4.5f)));
935 
936  x = (int) ((float) F1_0 * percent);
937 
938  //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));
939 
940  if (raw < 0)
941  return -x;
942 
943  return x;
944 }
945 
946 // --------------------------------------------------------------
947 // joy_get_pos()
948 //
949 // input: x => OUTPUT PARAMETER: x-axis position of stick (-1 to 1)
950 // y => OUTPUT PARAMETER: y-axis position of stick (-1 to 1)
951 // z => OUTPUT PARAMETER: z-axis (throttle) position of stick (-1 to 1)
952 // r => OUTPUT PARAMETER: rudder position of stick (-1 to 1)
953 //
954 // return: success => 1
955 // failure => 0
956 //
957 int joy_get_pos(int *x, int *y, int *z, int *rx)
958 {
959  int axis[JOY_NUM_AXES];
960 
961  if (x) *x = 0;
962  if (y) *y = 0;
963  if (z) *z = 0;
964  if (rx) *rx = 0;
965 
966  if (joy_num_sticks < 1) return 0;
967 
968  joystick_read_raw_axis( 6, axis );
969 
970  // joy_get_scaled_reading will return a value represents the joystick pos from -1 to +1
971  if (x && joystick.axis_valid[0])
972  *x = joy_get_scaled_reading(axis[0], 0);
973  if (y && joystick.axis_valid[1])
974  *y = joy_get_scaled_reading(axis[1], 1);
975  if (z && joystick.axis_valid[2])
976  *z = joy_get_unscaled_reading(axis[2], 2);
977  if (rx && joystick.axis_valid[3])
978  *rx = joy_get_scaled_reading(axis[3], 3);
979 
980  if (x)
981  Joy_last_x_reading = *x;
982 
983  if (y)
984  Joy_last_x_reading = *y;
985 
986  return 1;
987 }
988 
989 // change in joy position since last call
990 void joy_get_delta(int *dx, int *dy)
991 {
992  static int old_joy_x = 0;
993  static int old_joy_y = 0;
994 
995  if ( !Joy_inited ) {
996  *dx = *dy = 0;
997  return;
998  }
999 
1000  *dx = Joy_last_x_reading - old_joy_x;
1001  *dy = Joy_last_y_reading - old_joy_y;
1002 
1003  old_joy_x = Joy_last_x_reading;
1004  old_joy_y = Joy_last_y_reading;
1005 }
1006 
1008 
1009 GUID Di_joy_guid;
1011 
1013 {
1014  char buf[64];
1015 
1016  nprintf(("Joystick", "Joystick detected: %s (%s)\n", lpddi->tszInstanceName, lpddi->tszProductName));
1017  sprintf(buf, "Joystick %d", Cur_joystick + 1);
1018  if (!stricmp(buf, lpddi->tszInstanceName)) {
1019  Di_joy_guid = lpddi->guidInstance;
1020  Di_joy_guid_valid = 1;
1021  nprintf(("Joystick", " (Selected joystick)\n"));
1022  }
1023 
1024  return DIENUM_CONTINUE;
1025 }
1026 /*
1027 BOOL FAR PASCAL InitJoystickInput(LPCDIDEVICEINSTANCE pdinst, LPVOID pvRef)
1028 {
1029  LPDIRECTINPUT pdi = pvRef;
1030  LPDIRECTINPUTDEVICE pdev;
1031  DIPROPRANGE diprg;
1032 
1033  // create the DirectInput joystick device
1034  if(pdi->lpVtbl->CreateDevice(pdi, &pdinst->guidInstance, &pdev, NULL) != DI_OK)
1035  {
1036  OutputDebugString("IDirectInput::CreateDevice FAILED\n");
1037  return DIENUM_CONTINUE;
1038  }
1039 
1040  // set joystick data format
1041  if (pdev->lpVtbl->SetDataFormat(pdev, &c_dfDIJoystick) != DI_OK)
1042  {
1043  OutputDebugString("IDirectInputDevice::SetDataFormat FAILED\n");
1044  pdev->lpVtbl->Release(pdev);
1045  return DIENUM_CONTINUE;
1046  }
1047 
1048  // set the cooperative level
1049  if (pdev->lpVtbl->SetCooperativeLevel(pdev, hWndMain,
1050  DISCL_NONEXCLUSIVE | DISCL_FOREGROUND) != DI_OK)
1051  {
1052  OutputDebugString("IDirectInputDevice::SetCooperativeLevel FAILED\n");
1053  pdev->lpVtbl->Release(pdev);
1054  return DIENUM_CONTINUE;
1055  }
1056 
1057  // set X-axis range to (-1000 ... +1000)
1058  // This lets us test against 0 to see which way the stick is pointed.
1059 
1060  diprg.diph.dwSize = sizeof(diprg);
1061  diprg.diph.dwHeaderSize = sizeof(diprg.diph);
1062  diprg.diph.dwObj = DIJOFS_X;
1063  diprg.diph.dwHow = DIPH_BYOFFSET;
1064  diprg.lMin = -1000;
1065  diprg.lMax = +1000;
1066 
1067  if (pdev->lpVtbl->SetProperty(pdev, DIPROP_RANGE, &diprg.diph) != DI_OK)
1068  {
1069  OutputDebugString("IDirectInputDevice::SetProperty(DIPH_RANGE) FAILED\n");
1070  pdev->lpVtbl->Release(pdev);
1071  return FALSE;
1072  }
1073 
1074  //
1075  // And again for Y-axis range
1076  //
1077  diprg.diph.dwObj = DIJOFS_Y;
1078 
1079  if (pdev->lpVtbl->SetProperty(pdev, DIPROP_RANGE, &diprg.diph) != DI_OK)
1080  {
1081  OutputDebugString("IDirectInputDevice::SetProperty(DIPH_RANGE) FAILED\n");
1082  pdev->lpVtbl->Release(pdev);
1083  return FALSE;
1084  }
1085 
1086  // set X axis dead zone to 50% (to avoid accidental turning)
1087  // Units are ten thousandths, so 50% = 5000/10000.
1088  if (SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_X, DIPH_BYOFFSET, 5000) != DI_OK)
1089  {
1090  OutputDebugString("IDirectInputDevice::SetProperty(DIPH_DEADZONE) FAILED\n");
1091  pdev->lpVtbl->Release(pdev);
1092  return FALSE;
1093  }
1094 
1095 
1096  // set Y axis dead zone to 50% (to avoid accidental thrust)
1097  // Units are ten thousandths, so 50% = 5000/10000.
1098  if (SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_Y, DIPH_BYOFFSET, 5000) != DI_OK)
1099  {
1100  OutputDebugString("IDirectInputDevice::SetProperty(DIPH_DEADZONE) FAILED\n");
1101  pdev->lpVtbl->Release(pdev);
1102  return FALSE;
1103  }
1104 
1105 
1106  // Add it to our list of devices. If AddInputDevice succeeds,
1107  // he will do an AddRef.
1108  AddInputDevice(pdev, pdinst);
1109  hRes = pdev->lpVtbl->QueryInterface(
1110  pdev, &IID_IDirectInputDevice2,
1111  (LPVOID *)&g_rgpdevFound[g_cpdevFound]);
1112 
1113  pdev->lpVtbl->Release(pdev);
1114 
1115  return DIENUM_CONTINUE;
1116 }
1117 */
1119 {
1120  HRESULT hr;
1121  LPDIRECTINPUTDEVICE pdev;
1122 
1123  Joy_di_inited = 0;
1124  hr = DirectInputCreate(GetModuleHandle(NULL), 0x500, &Di_joystick_obj, NULL);
1125  if (FAILED(hr)) {
1126  mprintf(( "DirectInputCreate() failed!\n" ));
1127  return -1;
1128  }
1129 
1130  Di_joy_guid_valid = 0;
1131  hr = Di_joystick_obj->EnumDevices(DIDEVTYPE_JOYSTICK, joy_di_enum, Di_joystick_obj, DIEDFL_ATTACHEDONLY);
1132  if (FAILED(hr)) {
1133  mprintf(( "EnumDevice() failed!\n" ));
1134  return -1;
1135  }
1136 
1137  if (!Di_joy_guid_valid) {
1138  mprintf(( "Correct joystick not found.\n" ));
1139  return -1;
1140  }
1141 
1142  hr = Di_joystick_obj->CreateDevice(Di_joy_guid, &pdev, NULL);
1143  if (FAILED(hr)) {
1144  mprintf(( "CreateDevice() failed!\n" ));
1145  return -1;
1146  }
1147 
1148  hr = pdev->SetDataFormat(&c_dfDIJoystick);
1149  if (FAILED(hr)) {
1150  mprintf(( "SetDataFormat() failed!\n" ));
1151  if (hr == DIERR_ACQUIRED)
1152  mprintf(( " (reason: DIERR_ACQUIRED)\n" ));
1153 
1154  if (hr == DIERR_INVALIDPARAM)
1155  mprintf(( " (reason: DIERR_INVALIDPARAM)\n" ));
1156 
1157  if (hr == DIERR_NOTINITIALIZED)
1158  mprintf(( " (reason: DIERR_NOTINITIALIZED)\n" ));
1159 
1160  pdev->Release();
1161  return -1;
1162  }
1163 
1164  hr = pdev->SetCooperativeLevel((HWND) os_get_window(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
1165  if (FAILED(hr)) {
1166  mprintf(( "SetCooperativeLevel() failed!\n" ));
1167  if (hr == DIERR_ACQUIRED)
1168  mprintf(( " (reason: DIERR_ACQUIRED)\n" ));
1169 
1170  if (hr == DIERR_INVALIDPARAM)
1171  mprintf(( " (reason: DIERR_INVALIDPARAM)\n" ));
1172 
1173  if (hr == DIERR_NOTINITIALIZED)
1174  mprintf(( " (reason: DIERR_NOTINITIALIZED)\n" ));
1175 
1176  pdev->Release();
1177  return -1;
1178  }
1179 
1180  hr = pdev->QueryInterface(IID_IDirectInputDevice2, (LPVOID *) &Di_joystick);
1181  if (FAILED(hr)) {
1182  pdev->Release();
1183  return -1;
1184  }
1185 
1186  Di_joystick->Acquire();
1187 
1188  pdev->Release();
1189  Joy_di_inited = 1;
1190  nprintf(("Joystick", "DirectInput initialization of joystick succeeded\n"));
1191  return 0;
1192 }
1193 
1195 {
1196  // Destroy any lingering IDirectInputDevice object.
1197  if (Di_joystick) {
1198  // Unacquire the device one last time just in case we got really confused
1199  // and tried to exit while the device is still acquired.
1200  Di_joystick->Unacquire();
1201 
1202  Di_joystick->Release();
1203  Di_joystick = NULL;
1204  }
1205 
1206  // Destroy any lingering IDirectInput object.
1207  if (Di_joystick_obj) {
1208  Di_joystick_obj->Release();
1209  Di_joystick_obj = NULL;
1210  }
1211 
1212  Joy_di_inited = 0;
1213  return 0;
1214 }
1215 
1216 int joystick_read_raw_axis_di(int num_axes, int *axis)
1217 {
1218  int repeat = 1;
1219  HRESULT hr = 0;
1220  DIJOYSTATE joy_state;
1221 
1222  if (!Joy_di_inited)
1223  return 0;
1224 
1225  repeat = 1;
1226  while (repeat) {
1227  repeat = 0;
1228 
1229  hr = Di_joystick->Poll();
1230  if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) {
1231  // DirectInput is telling us that the input stream has
1232  // been interrupted. We aren't tracking any state
1233  // between polls, so we don't have any special reset
1234  // that needs to be done. We just re-acquire and
1235  // try again.
1236  Sleep(1000); // Pause a second...
1237  hr = Di_joystick->Acquire();
1238  if (SUCCEEDED(hr))
1239  repeat = 1;
1240  }
1241  }
1242 
1243  repeat = 1;
1244  memset(&joy_state, 0, sizeof(joy_state));
1245  while (repeat) {
1246  repeat = 0;
1247 
1248  hr = Di_joystick->GetDeviceState(sizeof(joy_state), &joy_state);
1249  if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) {
1250  // DirectInput is telling us that the input stream has
1251  // been interrupted. We aren't tracking any state
1252  // between polls, so we don't have any special reset
1253  // that needs to be done. We just re-acquire and
1254  // try again.
1255  Sleep(1000); // Pause a second...
1256  hr = Di_joystick->Acquire();
1257  if (SUCCEEDED(hr))
1258  repeat = 1;
1259  }
1260  }
1261 
1262  if (SUCCEEDED(hr)) {
1263  switch (num_axes) {
1264  case 6:
1265  if (joystick.axis_valid[5])
1266  axis[5] = joy_state.lRy;
1267 
1268  case 5:
1269  if (joystick.axis_valid[4])
1270  axis[4] = joy_state.lRx;
1271 
1272  case 4:
1273  if (joystick.axis_valid[3])
1274  axis[3] = joy_state.lRz;
1275 
1276  case 3:
1277  if (joystick.axis_valid[2])
1278  axis[2] = joy_state.lZ;
1279 
1280  case 2:
1281  if (joystick.axis_valid[1])
1282  axis[1] = joy_state.lY;
1283 
1284  case 1:
1285  if (joystick.axis_valid[0])
1286  axis[0] = joy_state.lX;
1287 
1288  break;
1289  }
1290  }
1291 
1292  return 1;
1293 }
int axis_max[JOY_NUM_AXES]
Definition: joy.h:31
#define JOY_NUM_AXES
Definition: joy.h:18
#define DISCL_NONEXCLUSIVE
Definition: vdinput.h:623
DWORD joy_process(DWORD lparam)
Definition: joy.cpp:98
Joy_info joystick
Definition: joy.cpp:60
void * HWND
Definition: config.h:104
#define DIERR_INPUTLOST
Definition: vdinput.h:1649
int i
Definition: multi_pxo.cpp:466
uint os_config_read_uint(const char *section, const char *name, uint default_value)
Definition: osregistry.cpp:372
const DIDATAFORMAT c_dfDIJoystick
int axis_center[JOY_NUM_AXES]
Definition: joy.h:30
Definition: joy.h:27
int key_inkey()
Definition: key.cpp:424
int joy_down(int btn)
Definition: joy-unix.cpp:93
#define F1_0
Definition: fix.h:15
int Dead_zone_size
Definition: joy.cpp:31
int joy_up_count(int btn)
int joy_init()
Definition: joy-unix.cpp:466
Assert(pm!=NULL)
#define JOY_HATRIGHT
Definition: joy.h:23
#define mprintf(args)
Definition: pstypes.h:238
HANDLE Joy_tell_thread_to_end_event
Definition: joy.cpp:41
int joy_get_pos(int *x, int *y, int *z, int *rx)
Definition: joy-unix.cpp:267
void joy_close()
Definition: joy.cpp:238
int joy_get_unscaled_reading(int raw, int axn)
Definition: joy-unix.cpp:171
void joy_set_cen()
Definition: joy-unix.cpp:544
GLclampf f
Definition: Glext.h:7097
LONG lRy
Definition: vdinput.h:1220
#define DIERR_INVALIDPARAM
Definition: vdinput.h:1600
struct joy_button_info joy_button_info
SDL_mutex * CRITICAL_SECTION
Definition: config.h:213
#define DIERR_NOTACQUIRED
Definition: vdinput.h:1661
void joy_set_ul()
void joy_get_delta(int *dx, int *dy)
#define DirectInputCreate
Definition: vdinput.h:1487
int joy_ff_init()
Definition: joy_ff.cpp:63
#define Int3()
Definition: pstypes.h:292
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
#define IID_IDirectInputDevice2
Definition: vdinput.h:956
int axis_min[JOY_NUM_AXES]
Definition: joy.h:29
struct IDirectInputDevice2 * LPDIRECTINPUTDEVICE2
Definition: vdinput.h:960
void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
int joy_pollrate
Definition: joy.cpp:39
int joy_get_scaled_reading(int raw, int axn)
Definition: joy-unix.cpp:204
uint os_get_window()
Definition: osapi.cpp:208
CHAR tszInstanceName[MAX_PATH]
Definition: vdinput.h:663
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int Cur_joystick
Definition: joy.cpp:32
#define JOY_HATLEFT
Definition: joy.h:22
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
CRITICAL_SECTION joy_lock
Definition: joy.cpp:35
#define DIEDFL_ATTACHEDONLY
Definition: vdinput.h:1327
unsigned int uint
Definition: pstypes.h:64
int joystick_read_raw_axis(int num_axes, int *axis)
Definition: joy-unix.cpp:549
#define nprintf(args)
Definition: pstypes.h:239
void joy_get_caps(int max)
Definition: joy.cpp:273
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
GLdouble GLdouble z
Definition: Glext.h:5451
#define DISCL_FOREGROUND
Definition: vdinput.h:624
struct IDirectInput * LPDIRECTINPUT
Definition: vdinput.h:1381
uint last_down_check
Definition: joy-unix.cpp:42
int joystick_read_raw_axis_di(int num_axes, int *axis)
Definition: joy.cpp:1216
int joy_di_init()
Definition: joy.cpp:1118
int JOYSTICKID1
Definition: joy-unix.cpp:47
bool dc_optional_string_either(const char *str1, const char *str2)
Searches for an optional string and it's alias.
unsigned long DWORD
Definition: config.h:90
struct IDirectInputDevice * LPDIRECTINPUTDEVICE
Definition: vdinput.h:764
DWORD joy_thread_id
Definition: joy.cpp:38
int Joy_di_inited
Definition: joy.cpp:47
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
for(int idx=0;idx< i;idx++)
Definition: multi_pxo.cpp:472
GLclampd n
Definition: Glext.h:7286
BOOL CALLBACK joy_di_enum(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
Definition: joy.cpp:1012
long HRESULT
Definition: vddraw.h:115
#define DIERR_ACQUIRED
Definition: vdinput.h:1655
#define CALLBACK
Definition: config.h:75
int Joy_sensitivity
Definition: joy.cpp:33
int Di_joy_guid_valid
Definition: joy.cpp:1010
void joy_ff_shutdown()
Definition: joy_ff.cpp:99
int BOOL
Definition: config.h:80
float joy_down_time(int btn)
Definition: joy-unix.cpp:120
LONG lRz
Definition: vdinput.h:1221
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
CHAR tszProductName[MAX_PATH]
Definition: vdinput.h:664
#define JOY_TOTAL_BUTTONS
Definition: joy.h:17
#define KEY_ESC
Definition: key.h:124
void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
int joy_num_sticks
Definition: joy.cpp:30
#define DIERR_NOTINITIALIZED
Definition: vdinput.h:1626
UINT MMRESULT
Definition: msacm.h:153
LONG lRx
Definition: vdinput.h:1219
void Sleep(int mili)
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
ubyte keyd_pressed[NUM_KEYS]
Definition: key.cpp:42
#define JOY_NUM_BUTTONS
Definition: joy.h:15
typedef LPVOID
Definition: vddraw.h:119
#define i2fl(i)
Definition: floating.h:32
GLint GLsizei count
Definition: Gl.h:1491
joy_button_info joy_buttons[JOY_TOTAL_BUTTONS]
Definition: joy.cpp:62
int joy_down_count(int btn, int reset_count)
Definition: joy-unix.cpp:105
void dc_printf(const char *format,...)
Prints the given char string to the debug console.
Definition: console.cpp:358
void joy_set_lr()
#define JOY_HATBACK
Definition: joy.h:20
HANDLE Joy_thread_says_its_done_event
Definition: joy.cpp:42
LONG lX
Definition: vdinput.h:1216
#define DIDEVTYPE_JOYSTICK
Definition: vdinput.h:316
LONG lZ
Definition: vdinput.h:1218
void * HANDLE
Definition: config.h:106
HANDLE joy_thread
Definition: joy.cpp:37
int joy_di_shutdown()
Definition: joy.cpp:1194
void joy_flush()
Definition: joy.cpp:73
#define FALSE
Definition: pstypes.h:400
int axis_valid[JOY_NUM_AXES]
Definition: joy.h:28
void joy_cheap_cal()
int timer_get_milliseconds()
Definition: timer.cpp:150
#define stricmp(s1, s2)
Definition: config.h:271
#define DIENUM_CONTINUE
Definition: vdinput.h:1316
LONG lY
Definition: vdinput.h:1217
#define JOY_HATFORWARD
Definition: joy.h:21
GLint y
Definition: Gl.h:1505
DCF(joytest,"Test joystick")
Definition: joy.cpp:303