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)
39 #define _WIN32_OS //HH
41 #include <windows.h> //HH
42 #include <mmsystem.h> //HH
50 #define my_hwnd g_hWnd // D1X compatibility
53 char joy_installed = 0;
56 typedef struct Button_info {
65 typedef struct Joy_info {
72 Button_info buttons[MAX_BUTTONS];
73 int axis_min[JOY_NUM_AXES]; //changed
74 int axis_center[JOY_NUM_AXES]; //changed --orulz
75 int axis_max[JOY_NUM_AXES]; //changed
83 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
87 for (i=0; i<JOY_NUM_AXES; i++) { //changed - orulz
88 axis_min[i] = joystick.axis_min[i];
89 axis_center[i] = joystick.axis_center[i];
90 axis_max[i] = joystick.axis_max[i];
94 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
98 for (i=0; i<JOY_NUM_AXES; i++) { //changed - orulz
99 joystick.axis_min[i] = axis_min[i];
100 joystick.axis_center[i] = axis_center[i];
101 joystick.axis_max[i] = axis_max[i];
105 ubyte joy_get_present_mask() {
106 return joystick.present_mask;
109 void joy_set_timer_rate(int max_value ) {
110 joystick.max_timer = max_value;
113 int joy_get_timer_rate() {
114 return joystick.max_timer;
120 if (!joy_installed) return;
122 for (i=0; i<MAX_BUTTONS; i++ ) {
123 joystick.buttons[i].ignore = 0;
124 joystick.buttons[i].state = 0;
125 joystick.buttons[i].timedown = 0;
126 joystick.buttons[i].downcount = 0;
127 joystick.buttons[i].upcount = 0;
133 //Repalces joy_handler
134 //Since Windows calls us directly, we have to get our time difference since last time ourselves
135 //while in DOS we got it with the paramter ticks_this_time
136 LRESULT joy_handler32(HWND hWnd, UINT joymsg, UINT wParam, LPARAM lParam)
138 DWORD time_diff, time_now;
139 static DWORD time_last = 0xffffffff;
146 if (!joy_installed) return 1;
147 if (time_last == 0xffffffff) {
148 time_last = timer_get_fixed_seconds();
152 if (joymsg==MM_JOY1MOVE)
156 memset(&joy, 0, sizeof(joy));
157 joy.dwSize = sizeof(joy);
158 joy.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV;
159 if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR) {
162 value = joy.dwButtons;
165 time_now = timer_get_fixed_seconds();
166 if (time_now < time_last) {
167 time_last = abs(time_now-time_last);
169 time_diff = time_now - time_last;
171 for (i = 0; i < MAX_BUTTONS; i++)
173 button = &joystick.buttons[i];
175 if (!button->ignore) {
176 if ( i < (MAX_BUTTONS-4) )
177 state = (value >> i) & 1;
181 if ( button->last_state == state ) {
183 button->timedown += time_diff; //ticks_this_time;
187 button->downcount += state;
190 button->upcount += button->state;
193 button->last_state = state;
198 time_last = time_now;
203 //Begin section modified 3/7/99 - Owen Evans
205 ubyte joy_read_raw_buttons()
213 memset(&joy, 0, sizeof(joy));
214 joy.dwSize = sizeof(joy);
215 joy.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOVCTS | JOY_USEDEADZONE;
217 if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR)
220 for (i = 0; i < MAX_BUTTONS; i++) {
221 joystick.buttons[i].last_state = joystick.buttons[i].state;
222 joystick.buttons[i].state = (joy.dwButtons >> i) & 0x1;
223 if (!joystick.buttons[i].last_state && joystick.buttons[i].state) {
224 joystick.buttons[i].timedown = timer_get_fixed_seconds();
225 joystick.buttons[i].downcount++;
231 if (joy.dwPOV != JOY_POVCENTERED)
233 joystick.buttons[19].state = (joy.dwPOV < JOY_POVRIGHT || joy.dwPOV > JOY_POVLEFT);
234 joystick.buttons[15].state = (joy.dwPOV < JOY_POVBACKWARD && joy.dwPOV > JOY_POVFORWARD);
235 joystick.buttons[11].state = (joy.dwPOV < JOY_POVLEFT && joy.dwPOV > JOY_POVRIGHT);
236 joystick.buttons[7].state = (joy.dwPOV > JOY_POVBACKWARD);
239 return (ubyte)joy.dwButtons;
242 //end changed section - OE
245 ubyte joystick_read_raw_axis( ubyte mask, int * axis )
248 ubyte read_masks = 0;
250 axis[0] = 0; axis[1] = 0; //orulz: 1=x 2=y 3=r 4=z 5=u 6=v
251 axis[2] = 0; axis[3] = 0;
252 axis[4] = 0; axis[5] = 0; //HH: Added support for axes R and U
254 if (!joy_installed) {
258 memset(&joy, 0, sizeof(joy));
259 joy.dwSize = sizeof(joy);
260 joy.dwFlags = JOY_RETURNALL | JOY_USEDEADZONE;
261 if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR) {
265 mask &= joystick.present_mask; // Don't read non-present channels
267 return 0; // Don't read if no stick connected.
270 if (mask & JOY_1_X_AXIS) { axis[0] = joy.dwXpos; read_masks |= JOY_1_X_AXIS; }
271 if (mask & JOY_1_Y_AXIS) { axis[1] = joy.dwYpos; read_masks |= JOY_1_Y_AXIS; }
273 // if (mask & JOY_1_Z_AXIS) { axis[2] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
274 // if (mask & JOY_1_POV) { axis[3] = joy.dwPOV; read_masks |= JOY_1_POV; }
275 // if (mask & JOY_1_R_AXIS) { axis[4] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
276 // if (mask & JOY_1_U_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_U_AXIS; }
277 // if (mask & JOY_1_V_AXIS) { axis[6] = joy.dwVpos; read_masks |= JOY_1_V_AXIS; }
278 if (mask & JOY_1_R_AXIS) { axis[2] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
279 if (mask & JOY_1_Z_AXIS) { axis[3] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
280 if (mask & JOY_1_U_AXIS) { axis[4] = joy.dwZpos; read_masks |= JOY_1_U_AXIS; }
281 if (mask & JOY_1_V_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_V_AXIS; }
286 int hh_average(int val1, int val2)
288 return abs(val1-val2)/2;
291 int joy_init(int joyid) //HH: added joyid parameter
294 int temp_axis[JOY_NUM_AXES]; //changed - orulz
297 atexit(joy_close); //HH: we are a bit lazy :). Errors are ignored, so we are even double-lazy :)
300 memset(&joystick, 0, sizeof(joystick));
302 for (i=0; i<MAX_BUTTONS; i++)
303 joystick.buttons[i].last_state = 0;
305 if ( !joy_installed ) {
308 joystick.max_timer = 65536;
309 joystick.read_count = 0;
310 joystick.last_value = 0;
314 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
315 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, temp_axis );
317 if ( joystick.present_mask & 3 )
323 //HH: Main Win32 joystick initialization, incl. reading cal. stuff
325 if (joyGetDevCaps(joyid, &pjc, sizeof(pjc))!=JOYERR_NOERROR) {
329 if (joySetThreshold(joyid, pjc.wXmax/256)!=JOYERR_NOERROR) {
333 if (joySetCapture(my_hwnd, joyid, JOY_POLL_RATE, FALSE)!=JOYERR_NOERROR) {
337 joystick.max_timer = pjc.wPeriodMax;
338 joystick.axis_min[0] = pjc.wXmin;
339 joystick.axis_min[1] = pjc.wYmin;
341 // joystick.axis_min[2] = pjc.wZmin;
342 // //HH: joystick.axis_min[3] = pov-stuff
343 // joystick.axis_min[4] = pjc.wRmin;
344 // joystick.axis_min[5] = pjc.wUmin;
345 // joystick.axis_min[6] = pjc.wVmin;
346 joystick.axis_min[2] = pjc.wRmin;
347 joystick.axis_min[3] = pjc.wZmin;
348 joystick.axis_min[4] = pjc.wUmin;
349 joystick.axis_min[5] = pjc.wVmin;
351 joystick.axis_max[0] = pjc.wXmax;
352 joystick.axis_max[1] = pjc.wYmax;
354 // joystick.axis_max[2] = pjc.wZmax;
355 // //HH: joystick.axis_max[3] = pov-stuff
356 // joystick.axis_max[4] = pjc.wRmax;
357 // joystick.axis_max[5] = pjc.wUmax;
358 // joystick.axis_max[6] = pjc.wVmax;
359 joystick.axis_max[2] = pjc.wRmax;
360 joystick.axis_max[3] = pjc.wZmax;
361 joystick.axis_max[4] = pjc.wUmax;
362 joystick.axis_max[5] = pjc.wVmax;
364 joystick.axis_center[0] = hh_average(pjc.wXmax,pjc.wXmin);
365 joystick.axis_center[1] = hh_average(pjc.wYmax,pjc.wYmin);
367 // joystick.axis_center[2] = hh_average(pjc.wZmax,pjc.wZmin);
368 // joystick.axis_center[3] = JOY_POVCENTERED;
369 // joystick.axis_center[4] = hh_average(pjc.wRmax,pjc.wRmin);
370 // joystick.axis_center[5] = hh_average(pjc.wUmax,pjc.wUmin);
371 // joystick.axis_center[6] = hh_average(pjc.wVmax,pjc.wVmin);
372 joystick.axis_center[2] = hh_average(pjc.wRmax,pjc.wRmin);
373 joystick.axis_center[3] = hh_average(pjc.wZmax,pjc.wZmin);
374 joystick.axis_center[4] = hh_average(pjc.wUmax,pjc.wUmin);
375 joystick.axis_center[5] = hh_average(pjc.wVmax,pjc.wVmin);
377 joystick.present_mask = JOY_1_X_AXIS | JOY_1_Y_AXIS;
378 if (pjc.wCaps & JOYCAPS_HASZ) joystick.present_mask |= JOY_1_Z_AXIS;
379 // if (pjc.wCaps & JOYCAPS_HASPOV) joystick.present_mask |= JOY_1_POV;
380 if (pjc.wCaps & JOYCAPS_HASR) joystick.present_mask |= JOY_1_R_AXIS;
381 if (pjc.wCaps & JOYCAPS_HASU) joystick.present_mask |= JOY_1_U_AXIS;
382 if (pjc.wCaps & JOYCAPS_HASV) joystick.present_mask |= JOY_1_V_AXIS;
390 if (!joy_installed) return;
391 joyReleaseCapture(joystick.joyid); //HH: added to release joystick from the application. We ignore errors here
398 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
399 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_min );
401 if ( joystick.present_mask & 3 )
409 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
410 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_max );
412 if ( joystick.present_mask & 3 )
420 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
421 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_center );
423 if ( joystick.present_mask & 3 )
429 void joy_set_cen_fake(int channel)
433 int joy_get_scaled_reading( int raw, int axn )
437 // Make sure it's calibrated properly.
438 if ( joystick.axis_center[axn] - joystick.axis_min[axn] < 128 )
439 return 0; //HH: had to increase to 128
440 if ( joystick.axis_max[axn] - joystick.axis_center[axn] < 128 )
441 return 0; //HH: had to increase to 128
443 raw -= joystick.axis_center[axn];
446 d = joystick.axis_center[axn]-joystick.axis_min[axn];
448 d = joystick.axis_max[axn]-joystick.axis_center[axn];
457 if ( x < -128 ) x = -128;
458 if ( x > 127 ) x = 127;
460 //added on 4/13/99 by Victor Rachels to add deadzone control
461 d = (joy_deadzone) * 6;
462 if ((x > (-1*d)) && (x < d))
464 //end this section addition -VR
469 void joy_get_pos( int *x, int *y )
472 int axis[JOY_NUM_AXES];
474 if ((!joy_installed)||(!joy_present)) { *x=*y=0; return; }
476 flags=joystick_read_raw_axis( JOY_1_X_AXIS+JOY_1_Y_AXIS, axis );
478 if ( flags & JOY_1_X_AXIS )
479 *x = joy_get_scaled_reading( axis[0], 0 );
483 if ( flags & JOY_1_Y_AXIS )
484 *y = joy_get_scaled_reading( axis[1], 1 );
489 ubyte joy_read_stick( ubyte masks, int *axis )
492 int raw_axis[JOY_NUM_AXES];
494 if ((!joy_installed)||(!joy_present)) {
495 axis[0] = 0; axis[1] = 0;
496 axis[2] = 0; axis[3] = 0;
497 axis[4] = 0; axis[5] = 0;
501 flags=joystick_read_raw_axis( masks, raw_axis );
503 if ( flags & JOY_1_X_AXIS )
504 axis[0] = joy_get_scaled_reading( raw_axis[0], 0 );
508 if ( flags & JOY_1_Y_AXIS )
509 axis[1] = joy_get_scaled_reading( raw_axis[1], 1 );
513 if ( flags & JOY_1_R_AXIS )
514 axis[2] = joy_get_scaled_reading( raw_axis[2], 2 );
518 if ( flags & JOY_1_Z_AXIS )
519 axis[3] = joy_get_scaled_reading( raw_axis[3], 3 );
523 if ( flags & JOY_1_U_AXIS )
524 axis[4] = joy_get_scaled_reading( raw_axis[4], 4);
528 if ( flags & JOY_1_V_AXIS )
529 axis[5] = joy_get_scaled_reading( raw_axis[5], 5 );
539 if ((!joy_installed)||(!joy_present)) return 0;
541 return joy_read_raw_buttons();
545 //Begin section modified 3/7/99 - Owen Evans
547 void joy_get_btn_down_cnt( int *btn0, int *btn1 )
549 if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
553 *btn0 = joystick.buttons[0].downcount;
554 joystick.buttons[0].downcount = 0;
555 *btn1 = joystick.buttons[1].downcount;
556 joystick.buttons[1].downcount = 0;
559 int joy_get_button_state( int btn )
561 if ((!joy_installed)||(!joy_present)) return 0;
562 if ( btn >= MAX_BUTTONS ) return 0;
566 return joystick.buttons[btn].state;
569 int joy_get_button_up_cnt( int btn )
573 if ((!joy_installed)||(!joy_present)) return 0;
575 if ( btn >= MAX_BUTTONS ) return 0;
577 count = joystick.buttons[btn].upcount;
578 joystick.buttons[btn].upcount = 0;
583 int joy_get_button_down_cnt( int btn )
587 if ((!joy_installed)||(!joy_present)) return 0;
588 if ( btn >= MAX_BUTTONS ) return 0;
592 count = joystick.buttons[btn].downcount;
593 joystick.buttons[btn].downcount = 0;
598 fix joy_get_button_down_time( int btn )
602 if ((!joy_installed)||(!joy_present)) return 0;
603 if ( btn >= MAX_BUTTONS ) return 0;
607 if (joystick.buttons[btn].state) {
608 count = timer_get_fixed_seconds() - joystick.buttons[btn].timedown;
609 joystick.buttons[btn].timedown = 0;
615 //end changed section - OE
618 void joy_get_btn_up_cnt( int *btn0, int *btn1 )
620 if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
622 *btn0 = joystick.buttons[0].upcount;
623 joystick.buttons[0].upcount = 0;
624 *btn1 = joystick.buttons[1].upcount;
625 joystick.buttons[1].upcount = 0;
628 void joy_set_btn_values( int btn, int state, fix timedown, int downcount, int upcount )
630 joystick.buttons[btn].ignore = 1;
631 joystick.buttons[btn].state = state;
632 joystick.buttons[btn].timedown = fixmuldiv( timedown, 1193180, 65536 );
633 joystick.buttons[btn].downcount = downcount;
634 joystick.buttons[btn].upcount = upcount;