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
44 #include <windows.h> //HH
45 #include <mmsystem.h> //HH
53 #define my_hwnd g_hWnd // D1X compatibility
56 char joy_installed = 0;
59 typedef struct Button_info {
68 typedef struct Joy_info {
75 Button_info buttons[MAX_BUTTONS];
76 int axis_min[JOY_NUM_AXES]; //changed
77 int axis_center[JOY_NUM_AXES]; //changed --orulz
78 int axis_max[JOY_NUM_AXES]; //changed
86 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
90 for (i=0; i<JOY_NUM_AXES; i++) { //changed - orulz
91 axis_min[i] = joystick.axis_min[i];
92 axis_center[i] = joystick.axis_center[i];
93 axis_max[i] = joystick.axis_max[i];
97 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
101 for (i=0; i<JOY_NUM_AXES; i++) { //changed - orulz
102 joystick.axis_min[i] = axis_min[i];
103 joystick.axis_center[i] = axis_center[i];
104 joystick.axis_max[i] = axis_max[i];
108 ubyte joy_get_present_mask() {
109 return joystick.present_mask;
112 void joy_set_timer_rate(int max_value ) {
113 joystick.max_timer = max_value;
116 int joy_get_timer_rate() {
117 return joystick.max_timer;
123 if (!joy_installed) return;
125 for (i=0; i<MAX_BUTTONS; i++ ) {
126 joystick.buttons[i].ignore = 0;
127 joystick.buttons[i].state = 0;
128 joystick.buttons[i].timedown = 0;
129 joystick.buttons[i].downcount = 0;
130 joystick.buttons[i].upcount = 0;
136 //Repalces joy_handler
137 //Since Windows calls us directly, we have to get our time difference since last time ourselves
138 //while in DOS we got it with the paramter ticks_this_time
139 LRESULT joy_handler32(HWND hWnd, UINT joymsg, UINT wParam, LPARAM lParam)
142 DWORD time_diff, time_now;
143 static DWORD time_last = 0xffffffff;
150 if (!joy_installed) return 1;
151 if (time_last == 0xffffffff) {
152 time_last = timer_get_fixed_seconds();
156 if (joymsg==MM_JOY1MOVE)
160 memset(&joy, 0, sizeof(joy));
161 joy.dwSize = sizeof(joy);
162 joy.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV;
163 if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR) {
166 value = joy.dwButtons;
169 time_now = timer_get_fixed_seconds();
170 if (time_now < time_last) {
171 time_last = abs(time_now-time_last);
173 time_diff = time_now - time_last;
175 for (i = 0; i < MAX_BUTTONS; i++)
177 button = &joystick.buttons[i];
179 if (!button->ignore) {
180 if ( i < (MAX_BUTTONS-4) )
181 state = (value >> i) & 1;
185 if ( button->last_state == state ) {
187 button->timedown += time_diff; //ticks_this_time;
191 button->downcount += state;
194 button->upcount += button->state;
197 button->last_state = state;
202 time_last = time_now;
208 //Begin section modified 3/7/99 - Owen Evans
210 ubyte joy_read_raw_buttons()
219 memset(&joy, 0, sizeof(joy));
220 joy.dwSize = sizeof(joy);
221 joy.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOVCTS | JOY_USEDEADZONE;
223 if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR)
226 for (i = 0; i < MAX_BUTTONS; i++) {
227 joystick.buttons[i].last_state = joystick.buttons[i].state;
228 joystick.buttons[i].state = (joy.dwButtons >> i) & 0x1;
229 if (!joystick.buttons[i].last_state && joystick.buttons[i].state) {
230 joystick.buttons[i].timedown = timer_get_fixed_seconds();
231 joystick.buttons[i].downcount++;
237 if (joy.dwPOV != JOY_POVCENTERED)
239 joystick.buttons[19].state = (joy.dwPOV < JOY_POVRIGHT || joy.dwPOV > JOY_POVLEFT);
240 joystick.buttons[15].state = (joy.dwPOV < JOY_POVBACKWARD && joy.dwPOV > JOY_POVFORWARD);
241 joystick.buttons[11].state = (joy.dwPOV < JOY_POVLEFT && joy.dwPOV > JOY_POVRIGHT);
242 joystick.buttons[7].state = (joy.dwPOV > JOY_POVBACKWARD);
245 return (ubyte)joy.dwButtons;
249 //end changed section - OE
252 ubyte joystick_read_raw_axis( ubyte mask, int * axis )
256 ubyte read_masks = 0;
258 axis[0] = 0; axis[1] = 0; //orulz: 1=x 2=y 3=r 4=z 5=u 6=v
259 axis[2] = 0; axis[3] = 0;
260 axis[4] = 0; axis[5] = 0; //HH: Added support for axes R and U
262 if (!joy_installed) {
266 memset(&joy, 0, sizeof(joy));
267 joy.dwSize = sizeof(joy);
268 joy.dwFlags = JOY_RETURNALL | JOY_USEDEADZONE;
269 if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR) {
273 mask &= joystick.present_mask; // Don't read non-present channels
275 return 0; // Don't read if no stick connected.
278 if (mask & JOY_1_X_AXIS) { axis[0] = joy.dwXpos; read_masks |= JOY_1_X_AXIS; }
279 if (mask & JOY_1_Y_AXIS) { axis[1] = joy.dwYpos; read_masks |= JOY_1_Y_AXIS; }
281 // if (mask & JOY_1_Z_AXIS) { axis[2] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
282 // if (mask & JOY_1_POV) { axis[3] = joy.dwPOV; read_masks |= JOY_1_POV; }
283 // if (mask & JOY_1_R_AXIS) { axis[4] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
284 // if (mask & JOY_1_U_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_U_AXIS; }
285 // if (mask & JOY_1_V_AXIS) { axis[6] = joy.dwVpos; read_masks |= JOY_1_V_AXIS; }
286 if (mask & JOY_1_R_AXIS) { axis[2] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
287 if (mask & JOY_1_Z_AXIS) { axis[3] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
288 if (mask & JOY_1_U_AXIS) { axis[4] = joy.dwZpos; read_masks |= JOY_1_U_AXIS; }
289 if (mask & JOY_1_V_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_V_AXIS; }
294 int hh_average(int val1, int val2)
296 return abs(val1-val2)/2;
299 int joy_init(int joyid) //HH: added joyid parameter
302 int temp_axis[JOY_NUM_AXES]; //changed - orulz
305 atexit(joy_close); //HH: we are a bit lazy :). Errors are ignored, so we are even double-lazy :)
308 memset(&joystick, 0, sizeof(joystick));
310 for (i=0; i<MAX_BUTTONS; i++)
311 joystick.buttons[i].last_state = 0;
313 if ( !joy_installed ) {
316 joystick.max_timer = 65536;
317 joystick.read_count = 0;
318 joystick.last_value = 0;
322 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
323 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, temp_axis );
325 if ( joystick.present_mask & 3 )
331 //HH: Main Win32 joystick initialization, incl. reading cal. stuff
333 if (joyGetDevCaps(joyid, &pjc, sizeof(pjc))!=JOYERR_NOERROR) {
337 if (joySetThreshold(joyid, pjc.wXmax/256)!=JOYERR_NOERROR) {
341 if (joySetCapture(my_hwnd, joyid, JOY_POLL_RATE, FALSE)!=JOYERR_NOERROR) {
345 joystick.max_timer = pjc.wPeriodMax;
346 joystick.axis_min[0] = pjc.wXmin;
347 joystick.axis_min[1] = pjc.wYmin;
349 // joystick.axis_min[2] = pjc.wZmin;
350 // //HH: joystick.axis_min[3] = pov-stuff
351 // joystick.axis_min[4] = pjc.wRmin;
352 // joystick.axis_min[5] = pjc.wUmin;
353 // joystick.axis_min[6] = pjc.wVmin;
354 joystick.axis_min[2] = pjc.wRmin;
355 joystick.axis_min[3] = pjc.wZmin;
356 joystick.axis_min[4] = pjc.wUmin;
357 joystick.axis_min[5] = pjc.wVmin;
359 joystick.axis_max[0] = pjc.wXmax;
360 joystick.axis_max[1] = pjc.wYmax;
362 // joystick.axis_max[2] = pjc.wZmax;
363 // //HH: joystick.axis_max[3] = pov-stuff
364 // joystick.axis_max[4] = pjc.wRmax;
365 // joystick.axis_max[5] = pjc.wUmax;
366 // joystick.axis_max[6] = pjc.wVmax;
367 joystick.axis_max[2] = pjc.wRmax;
368 joystick.axis_max[3] = pjc.wZmax;
369 joystick.axis_max[4] = pjc.wUmax;
370 joystick.axis_max[5] = pjc.wVmax;
372 joystick.axis_center[0] = hh_average(pjc.wXmax,pjc.wXmin);
373 joystick.axis_center[1] = hh_average(pjc.wYmax,pjc.wYmin);
375 // joystick.axis_center[2] = hh_average(pjc.wZmax,pjc.wZmin);
376 // joystick.axis_center[3] = JOY_POVCENTERED;
377 // joystick.axis_center[4] = hh_average(pjc.wRmax,pjc.wRmin);
378 // joystick.axis_center[5] = hh_average(pjc.wUmax,pjc.wUmin);
379 // joystick.axis_center[6] = hh_average(pjc.wVmax,pjc.wVmin);
380 joystick.axis_center[2] = hh_average(pjc.wRmax,pjc.wRmin);
381 joystick.axis_center[3] = hh_average(pjc.wZmax,pjc.wZmin);
382 joystick.axis_center[4] = hh_average(pjc.wUmax,pjc.wUmin);
383 joystick.axis_center[5] = hh_average(pjc.wVmax,pjc.wVmin);
385 joystick.present_mask = JOY_1_X_AXIS | JOY_1_Y_AXIS;
386 if (pjc.wCaps & JOYCAPS_HASZ) joystick.present_mask |= JOY_1_Z_AXIS;
387 // if (pjc.wCaps & JOYCAPS_HASPOV) joystick.present_mask |= JOY_1_POV;
388 if (pjc.wCaps & JOYCAPS_HASR) joystick.present_mask |= JOY_1_R_AXIS;
389 if (pjc.wCaps & JOYCAPS_HASU) joystick.present_mask |= JOY_1_U_AXIS;
390 if (pjc.wCaps & JOYCAPS_HASV) joystick.present_mask |= JOY_1_V_AXIS;
400 if (!joy_installed) return;
401 joyReleaseCapture(joystick.joyid); //HH: added to release joystick from the application. We ignore errors here
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_min );
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_max );
423 if ( joystick.present_mask & 3 )
431 joystick.present_mask = JOY_ALL_AXIS; // Assume they're all present
432 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_center );
434 if ( joystick.present_mask & 3 )
440 void joy_set_cen_fake(int channel)
444 int joy_get_scaled_reading( int raw, int axn )
448 // Make sure it's calibrated properly.
449 if ( joystick.axis_center[axn] - joystick.axis_min[axn] < 128 )
450 return 0; //HH: had to increase to 128
451 if ( joystick.axis_max[axn] - joystick.axis_center[axn] < 128 )
452 return 0; //HH: had to increase to 128
454 raw -= joystick.axis_center[axn];
457 d = joystick.axis_center[axn]-joystick.axis_min[axn];
459 d = joystick.axis_max[axn]-joystick.axis_center[axn];
468 if ( x < -128 ) x = -128;
469 if ( x > 127 ) x = 127;
471 //added on 4/13/99 by Victor Rachels to add deadzone control
472 d = (joy_deadzone) * 6;
473 if ((x > (-1*d)) && (x < d))
475 //end this section addition -VR
480 void joy_get_pos( int *x, int *y )
483 int axis[JOY_NUM_AXES];
485 if ((!joy_installed)||(!joy_present)) { *x=*y=0; return; }
487 flags=joystick_read_raw_axis( JOY_1_X_AXIS+JOY_1_Y_AXIS, axis );
489 if ( flags & JOY_1_X_AXIS )
490 *x = joy_get_scaled_reading( axis[0], 0 );
494 if ( flags & JOY_1_Y_AXIS )
495 *y = joy_get_scaled_reading( axis[1], 1 );
500 ubyte joy_read_stick( ubyte masks, int *axis )
503 int raw_axis[JOY_NUM_AXES];
505 if ((!joy_installed)||(!joy_present)) {
506 axis[0] = 0; axis[1] = 0;
507 axis[2] = 0; axis[3] = 0;
508 axis[4] = 0; axis[5] = 0;
512 flags=joystick_read_raw_axis( masks, raw_axis );
514 if ( flags & JOY_1_X_AXIS )
515 axis[0] = joy_get_scaled_reading( raw_axis[0], 0 );
519 if ( flags & JOY_1_Y_AXIS )
520 axis[1] = joy_get_scaled_reading( raw_axis[1], 1 );
524 if ( flags & JOY_1_R_AXIS )
525 axis[2] = joy_get_scaled_reading( raw_axis[2], 2 );
529 if ( flags & JOY_1_Z_AXIS )
530 axis[3] = joy_get_scaled_reading( raw_axis[3], 3 );
534 if ( flags & JOY_1_U_AXIS )
535 axis[4] = joy_get_scaled_reading( raw_axis[4], 4);
539 if ( flags & JOY_1_V_AXIS )
540 axis[5] = joy_get_scaled_reading( raw_axis[5], 5 );
550 if ((!joy_installed)||(!joy_present)) return 0;
552 return joy_read_raw_buttons();
556 //Begin section modified 3/7/99 - Owen Evans
558 void joy_get_btn_down_cnt( int *btn0, int *btn1 )
560 if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
564 *btn0 = joystick.buttons[0].downcount;
565 joystick.buttons[0].downcount = 0;
566 *btn1 = joystick.buttons[1].downcount;
567 joystick.buttons[1].downcount = 0;
570 int joy_get_button_state( int btn )
572 if ((!joy_installed)||(!joy_present)) return 0;
573 if ( btn >= MAX_BUTTONS ) return 0;
577 return joystick.buttons[btn].state;
580 int joy_get_button_up_cnt( int btn )
584 if ((!joy_installed)||(!joy_present)) return 0;
586 if ( btn >= MAX_BUTTONS ) return 0;
588 count = joystick.buttons[btn].upcount;
589 joystick.buttons[btn].upcount = 0;
594 int joy_get_button_down_cnt( int btn )
598 if ((!joy_installed)||(!joy_present)) return 0;
599 if ( btn >= MAX_BUTTONS ) return 0;
603 count = joystick.buttons[btn].downcount;
604 joystick.buttons[btn].downcount = 0;
609 fix joy_get_button_down_time( int btn )
613 if ((!joy_installed)||(!joy_present)) return 0;
614 if ( btn >= MAX_BUTTONS ) return 0;
618 if (joystick.buttons[btn].state) {
619 count = timer_get_fixed_seconds() - joystick.buttons[btn].timedown;
620 joystick.buttons[btn].timedown = 0;
626 //end changed section - OE
629 void joy_get_btn_up_cnt( int *btn0, int *btn1 )
631 if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
633 *btn0 = joystick.buttons[0].upcount;
634 joystick.buttons[0].upcount = 0;
635 *btn1 = joystick.buttons[1].upcount;
636 joystick.buttons[1].upcount = 0;
640 void joy_set_btn_values( int btn, int state, fix timedown, int downcount, int upcount )
642 joystick.buttons[btn].ignore = 1;
643 joystick.buttons[btn].state = state;
644 joystick.buttons[btn].timedown = fixmuldiv( timedown, 1193180, 65536 );
645 joystick.buttons[btn].downcount = downcount;
646 joystick.buttons[btn].upcount = upcount;
654 void joy_set_slow_reading(int flag) {