1 /* $Id: joyc.c,v 1.2 2005-04-04 09:21:25 btb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
16 #pragma off (unreferenced)
17 static char rcsid[] = "$Id: joyc.c,v 1.2 2005-04-04 09:21:25 btb Exp $";
18 #pragma on (unreferenced)
22 #define WIN32_LEAN_AND_MEAN
40 //#include "win\cyberimp.h"
41 //#include "spw_inp.h"
43 #define WIN_TACTILE_ON
45 #define JOY_READ_BUTTONS
46 #define JOY_MAX_BUTTONS 20
47 #define JOY_POLL_RATE 75 // 100 ms.
50 // Data Structures ============================================================
52 typedef struct Button_info {
61 typedef struct Joy_info {
67 Button_info buttons[JOY_MAX_BUTTONS];
73 int raw_x1, raw_y1, raw_z1, raw_r1, raw_u1, raw_v1, pov;
76 LRESULT joy_handler_win(HWND hWnd, UINT joymsg, UINT wParam, LPARAM lParam);
79 // Globals ====================================================================
82 int SpecialDevice = 0;
84 char SBall_installed = 0;
85 char joy_installed = 0;
89 // Extra Controls structures
90 //SPW_Control SBall_Control; // Space Ball Interface
92 static JOYCAPS WinJoyCaps;
93 static BOOL CHStickHack=0;
96 // Functions ==================================================================
99 Reset joystick information and request joystick notification from
100 Windows... Calibration shouldn't be a problem since Windows 95 takes
101 care of that. Also attaches a window to the joystick.
103 int joy_init(int joy, int spjoy)
110 // Reset Joystick information.
112 memset(&joystick, 0, sizeof(joystick));
114 for (i = 0; i < JOY_MAX_BUTTONS; i++)
115 joystick.buttons[i].last_state = 0;
117 if ( !joy_installed ) {
120 joystick.max_timer = 65536;
121 joystick.read_count = 0;
122 joystick.last_value = 0;
126 // Special joystick interface initialize.
132 // if (FindArg("-CyberImpact"))
133 // SpecialDevice = TACTILE_CYBERNET;
135 if (i = FindArg("-Iforce")) {
136 SpecialDevice = TACTILE_IMMERSION;
137 if (atoi(Args[i+1]) != 0) port = atoi(Args[i+1]);
141 mprintf((0, "Using Special Joystick!\n"));
143 switch(SpecialDevice)
145 #ifdef WIN_TACTILE_ON
146 case TACTILE_CYBERNET:
147 TactileStick = TACTILE_CYBERNET;
148 if (!Tactile_open(0)) joy_present = 0;
149 else joy_present = 1;
152 case TACTILE_IMMERSION:
153 TactileStick = TACTILE_IMMERSION;
154 if (!Tactile_open(port)) joy_present = 0;
155 else joy_present = 1;
159 if (!joy_present) SpecialDevice = 0;
162 joy_present = (char)joyGetNumDevs();
170 // closes to joystick by releasing it from the application window
176 switch (SpecialDevice)
178 case TACTILE_CYBERNET:
182 case TACTILE_IMMERSION:
186 joyReleaseCapture(joystick.joyid);
192 // joy_get/set_cal_vals
193 // functions that access all of the joystick axis'.
194 // An array of at least four elements must be passed to each function
196 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
200 for (i=0; i < 7; i++)
202 axis_min[i] = joystick.axis_min[i];
203 axis_center[i] = joystick.axis_center[i];
204 axis_max[i] = joystick.axis_max[i];
209 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
213 for (i=0; i < 7; i++)
215 joystick.axis_min[i] = axis_min[i];
216 joystick.axis_center[i] = axis_center[i];
217 joystick.axis_max[i] = axis_max[i];
222 // joy_get_present_mask
223 // returns the joystick axis' available to be used and accessed
225 ubyte joy_get_present_mask()
227 return joystick.present_mask;
233 // resets joystick button parameters
239 for (i = 0; i < JOY_MAX_BUTTONS; i++)
241 joystick.buttons[i].ignore = 0;
242 joystick.buttons[i].state = 0;
243 joystick.buttons[i].timedown = 0;
244 joystick.buttons[i].downcount = 0;
245 joystick.buttons[i].upcount = 0;
250 // joy_read_raw_buttons
251 // returns the status of the buttons at that moment.
253 ubyte joy_read_raw_buttons()
258 if (!joy_present) { return 0; }
260 memset(&joy, 0, sizeof(joy));
261 joy.dwSize = sizeof(joy);
262 joy.dwFlags = JOY_RETURNBUTTONS | JOY_USEDEADZONE;
263 joyGetPosEx(joystick.joyid, &joy);
265 // For now we support just four buttons
266 value = value | ((ubyte)joy.dwButtons & JOY_BUTTON1);
267 value = value | ((ubyte)joy.dwButtons & JOY_BUTTON2);
268 value = value | ((ubyte)joy.dwButtons & JOY_BUTTON3);
269 value = value | ((ubyte)joy.dwButtons & JOY_BUTTON4);
275 ubyte joystick_read_raw_axis( ubyte mask, int * axis )
278 ubyte read_masks = 0;
281 if (!joy_installed) return 0;
282 if (!joy_present) return 0;
284 for (i = 0; i < 7; i++)
287 axis[3] = JOY_POVCENTERED;
289 switch (SpecialDevice)
291 case TACTILE_CYBERNET:
292 //@@ CyberImpact_ReadRawValues(mask, axis);
293 //@@ joystick.raw_x1 = axis[0];
294 //@@ joystick.raw_y1 = axis[1];
295 //@@ joystick.raw_z1 = axis[2];
296 //@@ joystick.raw_r1 = axis[4];
297 //@@ joystick.raw_u1 = axis[5];
298 //@@ joystick.raw_v1 = axis[6];
299 //@@ joystick.pov = axis[3];
302 case TACTILE_IMMERSION:
303 #ifdef WIN_TACTILE_ON
304 IForce_ReadRawValues(axis);
306 joystick.raw_x1 = axis[0];
307 joystick.raw_y1 = axis[1];
308 joystick.raw_z1 = axis[2];
309 joystick.raw_r1 = axis[4];
310 joystick.raw_u1 = axis[5];
311 joystick.raw_v1 = axis[6];
312 joystick.pov = axis[3];
316 memset(&joy, 0, sizeof(joy));
317 joy.dwSize = sizeof(joy);
318 joy.dwFlags = JOY_RETURNALL | JOY_USEDEADZONE;
319 joyGetPosEx(joystick.joyid, &joy);
320 joystick.raw_x1 = joy.dwXpos;
321 joystick.raw_y1 = joy.dwYpos;
322 joystick.raw_z1 = joy.dwZpos;
323 joystick.raw_r1 = joy.dwRpos;
324 joystick.raw_u1 = joy.dwUpos;
325 joystick.raw_v1 = joy.dwVpos;
326 joystick.pov = joy.dwPOV;
329 mask &= joystick.present_mask;
330 if (mask == 0) return 0; // Don't read if no stick present
332 if (mask & JOY_1_X_AXIS) {
333 axis[0] = joystick.raw_x1;
334 read_masks |= JOY_1_X_AXIS;
336 if (mask & JOY_1_Y_AXIS) {
337 axis[1] = joystick.raw_y1;
338 read_masks |= JOY_1_Y_AXIS;
340 if (mask & JOY_1_Z_AXIS) {
341 axis[2] = joystick.raw_z1;
342 read_masks |= JOY_1_Z_AXIS;
344 if (mask & JOY_1_R_AXIS) {
345 axis[4] = joystick.raw_r1;
346 read_masks |= JOY_1_R_AXIS;
348 if (mask & JOY_1_U_AXIS) {
349 axis[5] = joystick.raw_u1;
350 read_masks |= JOY_1_U_AXIS;
352 if (mask & JOY_1_V_AXIS) {
353 axis[6] = joystick.raw_v1;
354 read_masks |= JOY_1_V_AXIS;
356 if (mask & JOY_1_POV) {
357 axis[3] = joystick.pov;
358 read_masks |= JOY_1_POV;
367 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS+JOY_EXT_AXIS, joystick.axis_min );
368 if ( joystick.present_mask & 3 )
377 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS+JOY_EXT_AXIS, joystick.axis_max );
378 if ( joystick.present_mask & 3 )
387 switch (SpecialDevice)
389 case TACTILE_CYBERNET:
390 //@@ CyberImpact_CalibCenter();
394 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS+JOY_EXT_AXIS, joystick.axis_center );
395 if ( joystick.present_mask & 3 )
402 void joy_set_cen_fake(int channel)
404 // Do we need this???
408 int joy_get_scaled_reading( int raw, int axn )
412 // Make sure it's calibrated properly.
413 if ( joystick.axis_center[axn] - joystick.axis_min[axn] < 128 ) return 0;
414 if ( joystick.axis_max[axn] - joystick.axis_center[axn] < 128 ) return 0;
416 raw -= joystick.axis_center[axn];
419 d = joystick.axis_center[axn]-joystick.axis_min[axn];
421 d = joystick.axis_max[axn]-joystick.axis_center[axn];
429 if ( x < -128 ) x = -128;
430 if ( x > 127 ) x = 127;
436 //@@ if ((joystick.axis_max[axn] - joystick.axis_min[axn]) == 0) return 0;
437 //@@ if (axn == 3) return raw;
439 //@@ x = (256 * raw)/(joystick.axis_max[axn]-joystick.axis_min[axn]);
446 void joy_get_pos( int *x, int *y )
452 if (!joy_installed || !joy_present) { *x = *y = 0; return; }
454 flags=joystick_read_raw_axis( JOY_1_X_AXIS+JOY_1_Y_AXIS, axis );
456 if ( flags & JOY_1_X_AXIS )
457 *x = joy_get_scaled_reading( axis[0], 0 );
461 if ( flags & JOY_1_Y_AXIS )
462 *y = joy_get_scaled_reading( axis[1], 1 );
468 ubyte joy_read_stick( ubyte masks, int *axis )
474 if ((!joy_installed)||(!joy_present)) {
475 axis[0] = 0; axis[1] = 0;
476 axis[2] = 0; axis[3] = 0;
477 axis[4] = 0; axis[5] = 0;
482 flags=joystick_read_raw_axis( masks, raw_axis );
484 if ( flags & JOY_1_X_AXIS )
485 axis[0] = joy_get_scaled_reading( raw_axis[0], 0 );
489 if ( flags & JOY_1_Y_AXIS )
490 axis[1] = joy_get_scaled_reading( raw_axis[1], 1 );
494 if ( flags & JOY_1_Z_AXIS )
495 axis[2] = joy_get_scaled_reading( raw_axis[2], 2 );
499 if ( flags & JOY_1_R_AXIS )
500 axis[4] = joy_get_scaled_reading( raw_axis[4], 4 );
504 if ( flags & JOY_1_U_AXIS )
505 axis[5] = joy_get_scaled_reading( raw_axis[5], 5 );
509 if ( flags & JOY_1_V_AXIS )
510 axis[6] = joy_get_scaled_reading( raw_axis[6], 6 );
514 if ( flags & JOY_1_POV )
515 axis[3] = joy_get_scaled_reading( raw_axis[3], 3 );
525 if ((!joy_installed)||(!joy_present)) return 0;
526 return joy_read_raw_buttons();
530 void joy_get_btn_down_cnt( int *btn0, int *btn1 )
532 if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
534 *btn0 = joystick.buttons[0].downcount;
535 joystick.buttons[0].downcount = 0;
536 *btn1 = joystick.buttons[1].downcount;
537 joystick.buttons[1].downcount = 0;
541 int joy_get_button_state( int btn )
545 if ((!joy_installed)||(!joy_present)) return 0;
547 if (btn >= JOY_MAX_BUTTONS)
550 count = joystick.buttons[btn].state;
556 int joy_get_button_up_cnt( int btn )
560 if ((!joy_installed)||(!joy_present)) return 0;
562 if (btn >= JOY_MAX_BUTTONS)
565 count = joystick.buttons[btn].upcount;
566 joystick.buttons[btn].upcount = 0;
572 int joy_get_button_down_cnt( int btn )
576 if ((!joy_installed)||(!joy_present)) return 0;
577 if (btn >= JOY_MAX_BUTTONS)
580 count = joystick.buttons[btn].downcount;
581 joystick.buttons[btn].downcount = 0;
587 fix joy_get_button_down_time( int btn )
591 if ((!joy_installed)||(!joy_present)) return 0;
592 if (btn >= JOY_MAX_BUTTONS)
595 count = joystick.buttons[btn].timedown;
596 joystick.buttons[btn].timedown = 0;
598 return count; //fixdiv(count, 1000);
602 void joy_get_btn_up_cnt( int *btn0, int *btn1 )
604 if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
606 *btn0 = joystick.buttons[0].upcount;
607 joystick.buttons[0].upcount = 0;
608 *btn1 = joystick.buttons[1].upcount;
609 joystick.buttons[1].upcount = 0;
613 void joy_set_btn_values( int btn, int state, fix timedown, int downcount, int upcount )
615 joystick.buttons[btn].ignore = 1;
616 joystick.buttons[btn].state = state;
617 joystick.buttons[btn].timedown = timedown; //fixmul(timedown,1000); //convert to miliseconds
618 joystick.buttons[btn].downcount = downcount;
619 joystick.buttons[btn].upcount = upcount;
623 // Windows 95 Custom joystick configuration.
624 // These are 'low level' routines to get information about a joystick
626 // Note: spjoy is for 'unique' joysticks.
628 int joy95_init_stick(int joy, int spjoy)
637 switch (SpecialDevice)
639 case TACTILE_CYBERNET:
640 //@@ joystick.present_mask = JOY_1_X_AXIS | JOY_1_Y_AXIS | JOY_1_Z_AXIS | JOY_1_POV;
641 //@@ joystick.has_pov = 1;
644 case TACTILE_IMMERSION:
645 mprintf((0, "Joystick name= I-Force compatible device.\n"));
649 // if (spjoy) return 1;
653 if (joy == 1) joystick.joyid = joyid = JOYSTICKID1;
657 mmresult = joyGetDevCaps(joyid, &WinJoyCaps, sizeof(WinJoyCaps));
658 if (mmresult != JOYERR_NOERROR) {
659 mprintf((1, "Attempt to get Joystick %d caps failed.\n", joy));
662 mprintf ((0,"Joystick name=%s\n",WinJoyCaps.szPname));
664 // Tell our Window App. about this joystick.
665 joySetThreshold(joyid, WinJoyCaps.wXmax/256);
666 mmresult = joySetCapture(GetLibraryWindow(),
671 if (mmresult != JOYERR_NOERROR) {
672 mprintf((1, "Unable to capture joystick %d. Error=%d\n", joy,mmresult));
676 // Get raw axis' min and max.
677 joystick.threshold = WinJoyCaps.wXmax/256;
678 joystick.max_timer = WinJoyCaps.wPeriodMax;
680 joystick.threshold = WinJoyCaps.wXmax/256;
681 joystick.max_timer = WinJoyCaps.wPeriodMax;
682 joystick.axis_min[0] = WinJoyCaps.wXmin;
683 joystick.axis_min[1] = WinJoyCaps.wYmin;
684 joystick.axis_min[2] = WinJoyCaps.wZmin;
685 joystick.axis_min[4] = WinJoyCaps.wRmin;
686 joystick.axis_min[5] = WinJoyCaps.wUmin;
687 joystick.axis_min[6] = WinJoyCaps.wVmin;
688 joystick.axis_max[0] = WinJoyCaps.wXmax;
689 joystick.axis_max[1] = WinJoyCaps.wYmax;
690 joystick.axis_max[2] = WinJoyCaps.wZmax;
691 joystick.axis_max[4] = WinJoyCaps.wRmax;
692 joystick.axis_max[5] = WinJoyCaps.wUmax;
693 joystick.axis_max[6] = WinJoyCaps.wVmax;
694 joystick.axis_center[0] = (WinJoyCaps.wXmax-WinJoyCaps.wXmin)/2;
695 joystick.axis_center[1] = (WinJoyCaps.wYmax-WinJoyCaps.wYmin)/2;
696 joystick.axis_center[2] = (WinJoyCaps.wZmax-WinJoyCaps.wZmin)/2;
697 joystick.axis_center[4] = (WinJoyCaps.wRmax-WinJoyCaps.wRmin)/2;
698 joystick.axis_center[5] = (WinJoyCaps.wUmax-WinJoyCaps.wUmin)/2;
699 joystick.axis_center[6] = (WinJoyCaps.wVmax-WinJoyCaps.wVmin)/2;
701 joystick.present_mask = JOY_1_X_AXIS | JOY_1_Y_AXIS;
703 if (WinJoyCaps.wCaps & JOYCAPS_HASPOV) {
704 joystick.has_pov = 1;
705 joystick.present_mask |= JOY_1_POV;
707 else joystick.has_pov = 0;
709 if (WinJoyCaps.wCaps & JOYCAPS_HASZ)
710 joystick.present_mask |= JOY_1_Z_AXIS;
711 if (WinJoyCaps.wCaps & JOYCAPS_HASR)
712 joystick.present_mask |= JOY_1_R_AXIS;
713 if (WinJoyCaps.wCaps & JOYCAPS_HASU)
714 joystick.present_mask |= JOY_1_U_AXIS;
715 if (WinJoyCaps.wCaps & JOYCAPS_HASV)
716 joystick.present_mask |= JOY_1_V_AXIS;
718 joy95_get_name(JOYSTICKID1, joyname, 255);
719 if (!strcmpi(joyname, "CH Flightstick Pro") || FindArg("-ordinaljoy")) {
722 else CHStickHack = 0;
728 void joy95_get_name(int joyid, char *name, int namesize)
735 registry_handle *rhandle;
740 switch(SpecialDevice)
742 case TACTILE_IMMERSION:
743 strcpy(name, "I-Force Force-Feedback");
747 res = joyGetDevCaps(joyid, &jc, sizeof(jc));
748 if (res != JOYERR_NOERROR) {
749 strcpy(name, "NO JOYSTICK DETECTED");
753 // we have the reg key!
754 registry_setpath(HKEY_LOCAL_MACHINE);
755 strcpy(regpath, "System\\CurrentControlSet\\control\\MediaResources\\joystick\\");
756 strcat(regpath, jc.szRegKey);
757 strcat(regpath, "\\CurrentJoystickSettings");
758 sprintf(reglabel, "Joystick%dOEMName", joyid+1);
760 if ((rhandle = registry_open(regpath))) {
761 if (!registry_getstring(rhandle, reglabel, name, namesize)) {
762 registry_close(rhandle);
763 strcpy(name, "JOYSTICK");
766 registry_close(rhandle);
768 // have reg entry for full name
769 strcpy(regpath, "System\\CurrentControlSet\\control\\MediaProperties\\PrivateProperties\\Joystick\\OEM\\");
770 strcat(regpath, name);
772 if ((rhandle = registry_open(regpath))) {
773 if (!registry_getstring(rhandle, "OEMName", name, namesize)) {
774 registry_close(rhandle);
775 strcpy(name, "JOYSTICK");
778 registry_close(rhandle);
780 else strcpy(name, "JOYSTICK");
782 else strcpy(name, "JOYSTICK");
788 This function takes the place of the joy_handler function for dos.
789 The main window procedure will call this function whenever a joystick message
792 LRESULT joy_handler_win(HWND hWnd, UINT joymsg, UINT wParam, LPARAM lParam)
796 static DWORD old_time = 0xffffffff;
803 // take care of first time initialization
804 if (!joy_installed) return 1;
805 if (old_time == 0xffffffff) {
806 old_time = timer_get_fixed_seconds();
810 // read and translate buttons 0-3
816 // For now we support just four buttons
817 memset(&joy, 0, sizeof(joy));
818 joy.dwSize = sizeof(joy);
819 joy.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV;
820 joyGetPosEx(joystick.joyid, &joy);
823 if (joy.dwPOV == JOY_POVCENTERED && joy.dwButtons > 0) {
824 value = (1 << (joy.dwButtons-1));
827 mprintf_at((0, 2, 32, "RAW:%08x OUR:%08x\n", joy.dwButtons, value));
830 value = joy.dwButtons;
835 new_time = timer_get_fixed_seconds();
836 if (new_time < old_time) old_time = abs(new_time - old_time);
837 interval_time = new_time - old_time;
839 for (i = 0; i < JOY_MAX_BUTTONS; i++)
841 // Check status of each button and translate information to the button
843 button = &joystick.buttons[i];
845 if (!button->ignore) {
846 if (i < (JOY_MAX_BUTTONS - 4))
847 state = (value >> i) & 1;
850 if ( button->last_state == state ) {
852 button->timedown += interval_time; //interval_ms;
856 button->downcount += state;
859 button->upcount += button->state;
862 button->last_state = state;
874 joyReleaseCapture(joystick.joyid);
878 void joy_start_poll()
880 joySetCapture(GetLibraryWindow(),
889 // joy_get/set_timer_rate
890 // these functions are currently implemented for compatability with
891 // DOS Descent2, but may be unecessary for now.
893 void joy_set_timer_rate(int max_value )
895 // No real effect, since Joystick runs on its own timer in Windows, for now.
899 int joy_get_timer_rate()
901 return joystick.max_timer;
904 void joy_handler(int ticks_this_time)
906 // replaced by joy_handler_win for Windows
909 void joy_set_slow_reading(int flag)
911 // No need to do this. In Windows, there are only slow readings.