1 //JOYC.C for D1_3Dfx and D1OpenGL
2 //D1_3Dfx is a Win32 executable using Glide and DirectX 3
3 //D1OpenGL is a Win32 executable using OpenGL and DirectX 3
4 //This joystick code should run on DirectInput 2 and higher
5 //We are not using DirectX 5 for now, since we want to stay compatible to the HH-loved Windows NT :).
6 //So ForceFeedback is not supported
9 // 1) Windows DirectX supports up to 7 axes, D1/DOS only 4, so we needed to increase the number to 7 at several points
10 // Also JOY_ALL_AXIS must be (1+2+4+8+16+32+64) in JOY.H file
11 // 2) Windows DirectX supports up to 32 buttons. So far we however only support 4. Adding support for more should be however easily possible.
12 // 3) _enable and _disable are not needed
13 // 4) joy_bogus_reading is not needed, so all calls are just removed
14 // 5) The joystick query goes over the DirectInputs function
15 // MMRESULT joyGetPosEx(UINT uJoyID, LPJOYINFOEX pji);
16 // All functions reading over BIOS, including the ASM code are removed
21 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
22 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
23 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
24 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
25 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
26 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
27 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
28 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
29 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
30 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
34 Modifications by Heiko Herrmann
35 Later modified by Owen Evans to work with D1X (3/7/99)
42 #define _WIN32_OS //HH
45 #include <windows.h> //HH
46 #include <mmsystem.h> //HH
50 #undef min /* kludge */
51 #undef max /* kludge */
56 #define my_hwnd g_hWnd // D1X compatibility
59 char joy_installed = 0;
62 typedef struct Button_info {
71 typedef struct Joy_info {
78 Button_info buttons[MAX_BUTTONS];
79 int axis_min[JOY_NUM_AXES]; //changed
80 int axis_center[JOY_NUM_AXES]; //changed --orulz
81 int axis_max[JOY_NUM_AXES]; //changed
89 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
93 for (i=0; i<JOY_NUM_AXES; i++) { //changed - orulz
94 axis_min[i] = joystick.axis_min[i];
95 axis_center[i] = joystick.axis_center[i];
96 axis_max[i] = joystick.axis_max[i];
100 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
104 for (i=0; i<JOY_NUM_AXES; i++) { //changed - orulz
105 joystick.axis_min[i] = axis_min[i];
106 joystick.axis_center[i] = axis_center[i];
107 joystick.axis_max[i] = axis_max[i];
111 ubyte joy_get_present_mask() {
112 return joystick.present_mask;
115 void joy_set_timer_rate(int max_value ) {
116 joystick.max_timer = max_value;
119 int joy_get_timer_rate() {
120 return joystick.max_timer;
126 if (!joy_installed) return;
128 for (i=0; i<MAX_BUTTONS; i++ ) {
129 joystick.buttons[i].ignore = 0;
130 joystick.buttons[i].state = 0;
131 joystick.buttons[i].timedown = 0;
132 joystick.buttons[i].downcount = 0;
133 joystick.buttons[i].upcount = 0;
139 //Repalces joy_handler
140 //Since Windows calls us directly, we have to get our time difference since last time ourselves
141 //while in DOS we got it with the paramter ticks_this_time
142 LRESULT joy_handler32(HWND hWnd, UINT joymsg, UINT wParam, LPARAM lParam)
145 DWORD time_diff, time_now;
146 static DWORD time_last = 0xffffffff;
153 if (!joy_installed) return 1;
154 if (time_last == 0xffffffff) {
155 time_last = timer_get_fixed_seconds();
159 if (joymsg==MM_JOY1MOVE)
163 memset(&joy, 0, sizeof(joy));
164 joy.dwSize = sizeof(joy);
165 joy.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV;
166 if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR) {
169 value = joy.dwButtons;
172 time_now = timer_get_fixed_seconds();
173 if (time_now < time_last) {
174 time_last = abs(time_now-time_last);
176 time_diff = time_now - time_last;
178 for (i = 0; i < MAX_BUTTONS; i++)
180 button = &joystick.buttons[i];
182 if (!button->ignore) {
183 if ( i < (MAX_BUTTONS-4) )
184 state = (value >> i) & 1;
188 if ( button->last_state == state ) {
190 button->timedown += time_diff; //ticks_this_time;
194 button->downcount += state;
197 button->upcount += button->state;
200 button->last_state = state;
205 time_last = time_now;
211 //Begin section modified 3/7/99 - Owen Evans
213 ubyte joy_read_raw_buttons()
222 memset(&joy, 0, sizeof(joy));
223 joy.dwSize = sizeof(joy);
224 joy.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOVCTS | JOY_USEDEADZONE;
226 if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR)
229 for (i = 0; i < MAX_BUTTONS; i++) {
230 joystick.buttons[i].last_state = joystick.buttons[i].state;
231 joystick.buttons[i].state = (joy.dwButtons >> i) & 0x1;
232 if (!joystick.buttons[i].last_state && joystick.buttons[i].state) {
233 joystick.buttons[i].timedown = timer_get_fixed_seconds();
234 joystick.buttons[i].downcount++;
240 if (joy.dwPOV != JOY_POVCENTERED)
242 joystick.buttons[19].state = (joy.dwPOV < JOY_POVRIGHT || joy.dwPOV > JOY_POVLEFT);
243 joystick.buttons[15].state = (joy.dwPOV < JOY_POVBACKWARD && joy.dwPOV > JOY_POVFORWARD);
244 joystick.buttons[11].state = (joy.dwPOV < JOY_POVLEFT && joy.dwPOV > JOY_POVRIGHT);
245 joystick.buttons[7].state = (joy.dwPOV > JOY_POVBACKWARD);
248 return (ubyte)joy.dwButtons;
254 //end changed section - OE
257 ubyte joystick_read_raw_axis( ubyte mask, int * axis )
261 ubyte read_masks = 0;
263 axis[0] = 0; axis[1] = 0; //orulz: 1=x 2=y 3=r 4=z 5=u 6=v
264 axis[2] = 0; axis[3] = 0;
265 axis[4] = 0; axis[5] = 0; //HH: Added support for axes R and U
267 if (!joy_installed) {
271 memset(&joy, 0, sizeof(joy));
272 joy.dwSize = sizeof(joy);
273 joy.dwFlags = JOY_RETURNALL | JOY_USEDEADZONE;
274 if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR) {
278 mask &= joystick.present_mask; // Don't read non-present channels
280 return 0; // Don't read if no stick connected.
283 if (mask & JOY_1_X_AXIS) { axis[0] = joy.dwXpos; read_masks |= JOY_1_X_AXIS; }
284 if (mask & JOY_1_Y_AXIS) { axis[1] = joy.dwYpos; read_masks |= JOY_1_Y_AXIS; }
286 // if (mask & JOY_1_Z_AXIS) { axis[2] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
287 // if (mask & JOY_1_POV) { axis[3] = joy.dwPOV; read_masks |= JOY_1_POV; }
288 // if (mask & JOY_1_R_AXIS) { axis[4] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
289 // if (mask & JOY_1_U_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_U_AXIS; }
290 // if (mask & JOY_1_V_AXIS) { axis[6] = joy.dwVpos; read_masks |= JOY_1_V_AXIS; }
291 if (mask & JOY_1_R_AXIS) { axis[2] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
292 if (mask & JOY_1_Z_AXIS) { axis[3] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
293 if (mask & JOY_1_U_AXIS) { axis[4] = joy.dwZpos; read_masks |= JOY_1_U_AXIS; }
294 if (mask & JOY_1_V_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_V_AXIS; }
299 int hh_average(int val1, int val2)
301 return abs(val1-val2)/2;
304 int joy_init(int joyid) //HH: added joyid parameter
307 int temp_axis[JOY_NUM_AXES]; //changed - orulz
310 atexit(joy_close); //HH: we are a bit lazy :). Errors are ignored, so we are even double-lazy :)
313 memset(&joystick, 0, sizeof(joystick));
315 for (i=0; i<MAX_BUTTONS; i++)
316 joystick.buttons[i].last_state = 0;
318 if ( !joy_installed ) {
321 joystick.max_timer = 65536;
322 joystick.read_count = 0;
323 joystick.last_value = 0;
327 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
328 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, temp_axis );
330 if ( joystick.present_mask & 3 )
336 //HH: Main Win32 joystick initialization, incl. reading cal. stuff
338 if (joyGetDevCaps(joyid, &pjc, sizeof(pjc))!=JOYERR_NOERROR) {
342 if (joySetThreshold(joyid, pjc.wXmax/256)!=JOYERR_NOERROR) {
346 if (joySetCapture(my_hwnd, joyid, JOY_POLL_RATE, FALSE)!=JOYERR_NOERROR) {
350 joystick.max_timer = pjc.wPeriodMax;
351 joystick.axis_min[0] = pjc.wXmin;
352 joystick.axis_min[1] = pjc.wYmin;
354 // joystick.axis_min[2] = pjc.wZmin;
355 // //HH: joystick.axis_min[3] = pov-stuff
356 // joystick.axis_min[4] = pjc.wRmin;
357 // joystick.axis_min[5] = pjc.wUmin;
358 // joystick.axis_min[6] = pjc.wVmin;
359 joystick.axis_min[2] = pjc.wRmin;
360 joystick.axis_min[3] = pjc.wZmin;
361 joystick.axis_min[4] = pjc.wUmin;
362 joystick.axis_min[5] = pjc.wVmin;
364 joystick.axis_max[0] = pjc.wXmax;
365 joystick.axis_max[1] = pjc.wYmax;
367 // joystick.axis_max[2] = pjc.wZmax;
368 // //HH: joystick.axis_max[3] = pov-stuff
369 // joystick.axis_max[4] = pjc.wRmax;
370 // joystick.axis_max[5] = pjc.wUmax;
371 // joystick.axis_max[6] = pjc.wVmax;
372 joystick.axis_max[2] = pjc.wRmax;
373 joystick.axis_max[3] = pjc.wZmax;
374 joystick.axis_max[4] = pjc.wUmax;
375 joystick.axis_max[5] = pjc.wVmax;
377 joystick.axis_center[0] = hh_average(pjc.wXmax,pjc.wXmin);
378 joystick.axis_center[1] = hh_average(pjc.wYmax,pjc.wYmin);
380 // joystick.axis_center[2] = hh_average(pjc.wZmax,pjc.wZmin);
381 // joystick.axis_center[3] = JOY_POVCENTERED;
382 // joystick.axis_center[4] = hh_average(pjc.wRmax,pjc.wRmin);
383 // joystick.axis_center[5] = hh_average(pjc.wUmax,pjc.wUmin);
384 // joystick.axis_center[6] = hh_average(pjc.wVmax,pjc.wVmin);
385 joystick.axis_center[2] = hh_average(pjc.wRmax,pjc.wRmin);
386 joystick.axis_center[3] = hh_average(pjc.wZmax,pjc.wZmin);
387 joystick.axis_center[4] = hh_average(pjc.wUmax,pjc.wUmin);
388 joystick.axis_center[5] = hh_average(pjc.wVmax,pjc.wVmin);
390 joystick.present_mask = JOY_1_X_AXIS | JOY_1_Y_AXIS;
391 if (pjc.wCaps & JOYCAPS_HASZ) joystick.present_mask |= JOY_1_Z_AXIS;
392 // if (pjc.wCaps & JOYCAPS_HASPOV) joystick.present_mask |= JOY_1_POV;
393 if (pjc.wCaps & JOYCAPS_HASR) joystick.present_mask |= JOY_1_R_AXIS;
394 if (pjc.wCaps & JOYCAPS_HASU) joystick.present_mask |= JOY_1_U_AXIS;
395 if (pjc.wCaps & JOYCAPS_HASV) joystick.present_mask |= JOY_1_V_AXIS;
407 if (!joy_installed) return;
408 joyReleaseCapture(joystick.joyid); //HH: added to release joystick from the application. We ignore errors here
416 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
417 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_min );
419 if ( joystick.present_mask & 3 )
427 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
428 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_max );
430 if ( joystick.present_mask & 3 )
438 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
439 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_center );
441 if ( joystick.present_mask & 3 )
447 void joy_set_cen_fake(int channel)
451 int joy_get_scaled_reading( int raw, int axn )
455 // Make sure it's calibrated properly.
456 if ( joystick.axis_center[axn] - joystick.axis_min[axn] < 128 )
457 return 0; //HH: had to increase to 128
458 if ( joystick.axis_max[axn] - joystick.axis_center[axn] < 128 )
459 return 0; //HH: had to increase to 128
461 raw -= joystick.axis_center[axn];
464 d = joystick.axis_center[axn]-joystick.axis_min[axn];
466 d = joystick.axis_max[axn]-joystick.axis_center[axn];
475 if ( x < -128 ) x = -128;
476 if ( x > 127 ) x = 127;
478 //added on 4/13/99 by Victor Rachels to add deadzone control
479 d = (joy_deadzone) * 6;
480 if ((x > (-1*d)) && (x < d))
482 //end this section addition -VR
487 void joy_get_pos( int *x, int *y )
490 int axis[JOY_NUM_AXES];
492 if ((!joy_installed)||(!joy_present)) { *x=*y=0; return; }
494 flags=joystick_read_raw_axis( JOY_1_X_AXIS+JOY_1_Y_AXIS, axis );
496 if ( flags & JOY_1_X_AXIS )
497 *x = joy_get_scaled_reading( axis[0], 0 );
501 if ( flags & JOY_1_Y_AXIS )
502 *y = joy_get_scaled_reading( axis[1], 1 );
507 ubyte joy_read_stick( ubyte masks, int *axis )
510 int raw_axis[JOY_NUM_AXES];
512 if ((!joy_installed)||(!joy_present)) {
513 axis[0] = 0; axis[1] = 0;
514 axis[2] = 0; axis[3] = 0;
515 axis[4] = 0; axis[5] = 0;
519 flags=joystick_read_raw_axis( masks, raw_axis );
521 if ( flags & JOY_1_X_AXIS )
522 axis[0] = joy_get_scaled_reading( raw_axis[0], 0 );
526 if ( flags & JOY_1_Y_AXIS )
527 axis[1] = joy_get_scaled_reading( raw_axis[1], 1 );
531 if ( flags & JOY_1_R_AXIS )
532 axis[2] = joy_get_scaled_reading( raw_axis[2], 2 );
536 if ( flags & JOY_1_Z_AXIS )
537 axis[3] = joy_get_scaled_reading( raw_axis[3], 3 );
541 if ( flags & JOY_1_U_AXIS )
542 axis[4] = joy_get_scaled_reading( raw_axis[4], 4);
546 if ( flags & JOY_1_V_AXIS )
547 axis[5] = joy_get_scaled_reading( raw_axis[5], 5 );
557 if ((!joy_installed)||(!joy_present)) return 0;
559 return joy_read_raw_buttons();
563 //Begin section modified 3/7/99 - Owen Evans
565 void joy_get_btn_down_cnt( int *btn0, int *btn1 )
567 if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
571 *btn0 = joystick.buttons[0].downcount;
572 joystick.buttons[0].downcount = 0;
573 *btn1 = joystick.buttons[1].downcount;
574 joystick.buttons[1].downcount = 0;
577 int joy_get_button_state( int btn )
579 if ((!joy_installed)||(!joy_present)) return 0;
580 if ( btn >= MAX_BUTTONS ) return 0;
584 return joystick.buttons[btn].state;
587 int joy_get_button_up_cnt( int btn )
591 if ((!joy_installed)||(!joy_present)) return 0;
593 if ( btn >= MAX_BUTTONS ) return 0;
595 count = joystick.buttons[btn].upcount;
596 joystick.buttons[btn].upcount = 0;
601 int joy_get_button_down_cnt( int btn )
605 if ((!joy_installed)||(!joy_present)) return 0;
606 if ( btn >= MAX_BUTTONS ) return 0;
610 count = joystick.buttons[btn].downcount;
611 joystick.buttons[btn].downcount = 0;
616 fix joy_get_button_down_time( int btn )
620 if ((!joy_installed)||(!joy_present)) return 0;
621 if ( btn >= MAX_BUTTONS ) return 0;
625 if (joystick.buttons[btn].state) {
626 count = timer_get_fixed_seconds() - joystick.buttons[btn].timedown;
627 joystick.buttons[btn].timedown = 0;
633 //end changed section - OE
636 void joy_get_btn_up_cnt( int *btn0, int *btn1 )
638 if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
640 *btn0 = joystick.buttons[0].upcount;
641 joystick.buttons[0].upcount = 0;
642 *btn1 = joystick.buttons[1].upcount;
643 joystick.buttons[1].upcount = 0;
647 void joy_set_btn_values( int btn, int state, fix timedown, int downcount, int upcount )
649 joystick.buttons[btn].ignore = 1;
650 joystick.buttons[btn].state = state;
651 joystick.buttons[btn].timedown = fixmuldiv( timedown, 1193180, 65536 );
652 joystick.buttons[btn].downcount = downcount;
653 joystick.buttons[btn].upcount = upcount;
661 void joy_set_slow_reading(int flag) {