]> icculus.org git repositories - btb/d2x.git/blob - arch/win32/joyhh.c
use PhysicsFS for saving levels
[btb/d2x.git] / arch / win32 / joyhh.c
1 /* $Id: joyhh.c,v 1.6 2005-04-04 09:18:08 btb Exp $ */
2 //JOYC.C for D1_3Dfx and D1OpenGL
3 //D1_3Dfx is a Win32 executable using Glide and DirectX 3
4 //D1OpenGL is a Win32 executable using OpenGL and DirectX 3
5 //This joystick code should run on DirectInput 2 and higher
6 //We are not using DirectX 5 for now, since we want to stay compatible to the HH-loved Windows NT :).
7 //So ForceFeedback is not supported
8
9 //Notes:
10 // 1) Windows DirectX supports up to 7 axes, D1/DOS only 4, so we needed to increase the number to 7 at several points
11 //    Also JOY_ALL_AXIS must be (1+2+4+8+16+32+64) in JOY.H file
12 // 2) Windows DirectX supports up to 32 buttons. So far we however only support 4. Adding support for more should be however easily possible.
13 // 3) _enable and _disable are not needed
14 // 4) joy_bogus_reading is not needed, so all calls are just removed
15 // 5) The joystick query goes over the DirectInputs function
16 //    MMRESULT joyGetPosEx(UINT uJoyID, LPJOYINFOEX pji);
17 //    All functions reading over BIOS, including the ASM code are removed
18
19
20
21 /*
22 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
23 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
24 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
25 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
26 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
27 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
28 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
29 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
30 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
31 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
32 */
33
34 /*
35 Modifications by Heiko Herrmann
36 Later modified by Owen Evans to work with D1X (3/7/99)
37 */
38
39
40 #define _WIN32_OS               //HH
41
42 #include <windows.h>    //HH
43 #include <mmsystem.h>   //HH
44 #include <stdlib.h>
45 #include <stdio.h>
46
47 #include "types.h"
48 #include "joy.h"
49 #include "timer.h"
50 #include "args.h"
51
52 #define my_hwnd g_hWnd // D1X compatibility
53 extern HWND g_hWnd;
54
55 char joy_installed = 0;
56 char joy_present = 0;
57
58 typedef struct Button_info {
59         ubyte           ignore;
60         ubyte           state;
61         ubyte           last_state;
62         int             timedown;
63         ubyte           downcount;
64         ubyte           upcount;
65 } Button_info;
66
67 typedef struct Joy_info {
68         int                     joyid;
69         ubyte                   present_mask;
70         ubyte       hat_present;
71         ubyte                   slow_read;
72         int                     max_timer;
73         int                     read_count;
74         ubyte                   last_value;
75         Button_info buttons[JOY_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 
79 } Joy_info;
80
81 Joy_info joystick;
82
83
84 int joy_deadzone = 0;
85
86 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
87 {
88         int i;
89
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];
94         }
95 }
96
97 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
98 {
99         int i;
100
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];
105         }
106 }
107
108 ubyte joy_get_present_mask()    {
109         return joystick.present_mask;
110 }
111
112 void joy_set_timer_rate(int max_value ) {
113         joystick.max_timer = max_value;
114 }
115
116 int joy_get_timer_rate()        {
117         return joystick.max_timer;
118 }
119
120 void joy_flush()        {
121         int i;
122
123         if (!joy_installed) return;
124
125         for (i = 0; i < JOY_MAX_BUTTONS; i++)
126         {
127                 joystick.buttons[i].ignore = 0;
128                 joystick.buttons[i].state = 0;  
129                 joystick.buttons[i].timedown = 0;       
130                 joystick.buttons[i].downcount = 0;      
131                 joystick.buttons[i].upcount = 0;        
132         }
133
134 }
135
136
137 //Begin section modified 3/7/99 - Owen Evans
138
139 ubyte joy_read_raw_buttons()
140 {
141         JOYINFOEX joy;
142         int i;
143
144         if (!joy_present)
145                 return 0; 
146         
147         memset(&joy, 0, sizeof(joy));
148         joy.dwSize = sizeof(joy);
149         joy.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOVCTS | JOY_USEDEADZONE;
150         
151         if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR)
152                 return 0;
153
154         for (i = 0; i < JOY_MAX_BUTTONS; i++)
155         {
156                 joystick.buttons[i].last_state = joystick.buttons[i].state;
157                 joystick.buttons[i].state = (joy.dwButtons >> i) & 0x1;
158                 if (!joystick.buttons[i].last_state && joystick.buttons[i].state) {
159                         joystick.buttons[i].timedown = timer_get_fixed_seconds();
160                         joystick.buttons[i].downcount++;
161                 }
162         }
163
164         /* Hat stuff */
165
166         if (joystick.hat_present && joy.dwPOV != JOY_POVCENTERED)
167          {
168            joystick.buttons[19].state = (joy.dwPOV < JOY_POVRIGHT || joy.dwPOV > JOY_POVLEFT);
169            joystick.buttons[15].state = (joy.dwPOV < JOY_POVBACKWARD && joy.dwPOV > JOY_POVFORWARD);
170            joystick.buttons[11].state = (joy.dwPOV < JOY_POVLEFT && joy.dwPOV > JOY_POVRIGHT);
171            joystick.buttons[7].state = (joy.dwPOV > JOY_POVBACKWARD);
172          }
173
174         return (ubyte)joy.dwButtons;
175 }
176
177 //end changed section - OE
178
179
180 ubyte joystick_read_raw_axis( ubyte mask, int * axis )
181 {
182         JOYINFOEX       joy;
183         ubyte read_masks = 0;
184
185         axis[0] = 0; axis[1] = 0; //orulz: 1=x 2=y 3=r 4=z 5=u 6=v
186         axis[2] = 0; axis[3] = 0;
187         axis[4] = 0; axis[5] = 0; //HH: Added support for axes R and U
188         
189         if (!joy_installed) {
190                 return 0;
191         }
192
193         memset(&joy, 0, sizeof(joy));
194         joy.dwSize = sizeof(joy);
195         joy.dwFlags = JOY_RETURNALL | JOY_USEDEADZONE;
196         if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR) {
197                 return 0;
198         }
199                         
200         mask &= joystick.present_mask;                  // Don't read non-present channels
201         if ( mask==0 )  {
202                 return 0;               // Don't read if no stick connected.
203         }
204
205         if (mask & JOY_1_X_AXIS) { axis[0] = joy.dwXpos; read_masks |= JOY_1_X_AXIS; }
206         if (mask & JOY_1_Y_AXIS) { axis[1] = joy.dwYpos; read_masks |= JOY_1_Y_AXIS; }
207 //orulz:
208 //        if (mask & JOY_1_Z_AXIS) { axis[2] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
209 //        if (mask & JOY_1_POV)    { axis[3] = joy.dwPOV;  read_masks |= JOY_1_POV;    }
210 //        if (mask & JOY_1_R_AXIS) { axis[4] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
211 //        if (mask & JOY_1_U_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_U_AXIS; }
212 //        if (mask & JOY_1_V_AXIS) { axis[6] = joy.dwVpos; read_masks |= JOY_1_V_AXIS; }
213         if (mask & JOY_1_R_AXIS) { axis[2] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
214         if (mask & JOY_1_Z_AXIS) { axis[3] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
215         if (mask & JOY_1_U_AXIS) { axis[4] = joy.dwZpos; read_masks |= JOY_1_U_AXIS; }
216         if (mask & JOY_1_V_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_V_AXIS; }
217
218         return read_masks;
219 }
220
221 int hh_average(int val1, int val2)
222 {
223         return abs(val1-val2)/2;
224 }
225
226 int joy_init(int joyid) //HH: added joyid parameter
227 {
228         int i;
229         int temp_axis[JOY_NUM_AXES];       //changed - orulz
230         JOYCAPS pjc;
231
232         if (FindArg("-nojoystick"))
233                 return 0;
234
235         atexit(joy_close);      //HH: we are a bit lazy :). Errors are ignored, so we are even double-lazy :)
236
237         joy_flush();
238         memset(&joystick, 0, sizeof(joystick));
239
240         for (i = 0; i < JOY_MAX_BUTTONS; i++)
241                 joystick.buttons[i].last_state = 0;
242
243         if ( !joy_installed )   {
244                 joy_present = 0;
245                 joy_installed = 1;
246                 joystick.max_timer = 65536;
247                 joystick.read_count = 0;
248                 joystick.last_value = 0;
249         }
250
251
252         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
253         joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, temp_axis );
254
255         if ( joystick.present_mask & 3 )
256                 joy_present = 1;
257         else
258                 joy_present = 0;
259
260         
261         //HH: Main Win32 joystick initialization, incl. reading cal. stuff
262
263         if (joyGetDevCaps(joyid, &pjc, sizeof(pjc))!=JOYERR_NOERROR) {
264                 return 0;
265         }
266
267         if (joySetThreshold(joyid, pjc.wXmax/256)!=JOYERR_NOERROR) {
268                 return 0;
269         }
270
271         joystick.max_timer      = pjc.wPeriodMax;
272         joystick.axis_min[0]    = pjc.wXmin;
273         joystick.axis_min[1]    = pjc.wYmin;
274 //orulz:
275 //        joystick.axis_min[2]    = pjc.wZmin;
276 //        //HH: joystick.axis_min[3]  = pov-stuff
277 //        joystick.axis_min[4]    = pjc.wRmin;
278 //        joystick.axis_min[5]    = pjc.wUmin;
279 //        joystick.axis_min[6]    = pjc.wVmin;
280         joystick.axis_min[2]    = pjc.wRmin;
281         joystick.axis_min[3]    = pjc.wZmin;
282         joystick.axis_min[4]    = pjc.wUmin;
283         joystick.axis_min[5]    = pjc.wVmin;
284
285         joystick.axis_max[0]    = pjc.wXmax;
286         joystick.axis_max[1]    = pjc.wYmax;
287 //orulz:
288 //        joystick.axis_max[2]    = pjc.wZmax;
289 //        //HH: joystick.axis_max[3]  = pov-stuff
290 //        joystick.axis_max[4]    = pjc.wRmax;
291 //        joystick.axis_max[5]    = pjc.wUmax;
292 //        joystick.axis_max[6]    = pjc.wVmax;
293         joystick.axis_max[2]    = pjc.wRmax;
294         joystick.axis_max[3]    = pjc.wZmax;
295         joystick.axis_max[4]    = pjc.wUmax;
296         joystick.axis_max[5]    = pjc.wVmax;
297
298         joystick.axis_center[0] = hh_average(pjc.wXmax,pjc.wXmin);
299         joystick.axis_center[1] = hh_average(pjc.wYmax,pjc.wYmin);
300 //orulz:
301 //        joystick.axis_center[2] = hh_average(pjc.wZmax,pjc.wZmin);
302 //        joystick.axis_center[3] = JOY_POVCENTERED;
303 //        joystick.axis_center[4] = hh_average(pjc.wRmax,pjc.wRmin);
304 //        joystick.axis_center[5] = hh_average(pjc.wUmax,pjc.wUmin);
305 //        joystick.axis_center[6] = hh_average(pjc.wVmax,pjc.wVmin);
306         joystick.axis_center[2] = hh_average(pjc.wRmax,pjc.wRmin);
307         joystick.axis_center[3] = hh_average(pjc.wZmax,pjc.wZmin);
308         joystick.axis_center[4] = hh_average(pjc.wUmax,pjc.wUmin);
309         joystick.axis_center[5] = hh_average(pjc.wVmax,pjc.wVmin);
310
311         joystick.present_mask = JOY_1_X_AXIS | JOY_1_Y_AXIS;
312         if (pjc.wCaps & JOYCAPS_HASZ)   joystick.present_mask |= JOY_1_Z_AXIS;
313         joystick.hat_present = (pjc.wCaps & JOYCAPS_HASPOV) > 0;
314         if (pjc.wCaps & JOYCAPS_HASR)   joystick.present_mask |= JOY_1_R_AXIS;
315         if (pjc.wCaps & JOYCAPS_HASU)   joystick.present_mask |= JOY_1_U_AXIS;
316         if (pjc.wCaps & JOYCAPS_HASV)   joystick.present_mask |= JOY_1_V_AXIS;
317
318         return joy_present;
319 }
320
321
322 void joy_close()
323 {
324         if (!joy_installed) return;
325         joy_installed = 0;
326 }
327
328
329 void joy_set_ul()       
330 {
331         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
332         joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_min );
333
334         if ( joystick.present_mask & 3 )
335                 joy_present = 1;
336         else
337                 joy_present = 0;
338 }
339
340 void joy_set_lr()       
341 {
342         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
343         joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_max );
344
345         if ( joystick.present_mask & 3 )
346                 joy_present = 1;
347         else
348                 joy_present = 0;
349 }
350
351 void joy_set_cen() 
352 {
353         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
354         joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_center );
355
356         if ( joystick.present_mask & 3 )
357                 joy_present = 1;
358         else
359                 joy_present = 0;
360 }
361
362 void joy_set_cen_fake(int channel)      
363 { }
364
365
366 int joy_get_scaled_reading( int raw, int axn )  
367 {
368  int x, d;
369
370   // Make sure it's calibrated properly.
371    if ( joystick.axis_center[axn] - joystick.axis_min[axn] < 128 )
372     return 0; //HH: had to increase to 128
373    if ( joystick.axis_max[axn] - joystick.axis_center[axn] < 128 )
374     return 0; //HH: had to increase to 128
375
376         if (!(joystick.present_mask & (1 << axn)))
377                 return 0; // fixes joy config bug where it'll always set an axis you don't even have. - 2000/01/14 Matt Mueller
378
379   raw -= joystick.axis_center[axn];
380
381    if ( raw < 0 )
382     d = joystick.axis_center[axn]-joystick.axis_min[axn];
383    else
384     d = joystick.axis_max[axn]-joystick.axis_center[axn];
385
386
387    if ( d )
388     x = (raw << 7) / d;
389    else 
390     x = 0;
391
392
393    if ( x < -128 ) x = -128;
394    if ( x > 127 ) x = 127;
395
396 //added on 4/13/99 by Victor Rachels to add deadzone control
397   d =  (joy_deadzone) * 6;
398    if ((x > (-1*d)) && (x < d))
399     x = 0;
400 //end this section addition -VR
401
402         return x;
403 }
404
405 void joy_get_pos( int *x, int *y )      
406 {
407         ubyte flags;
408         int axis[JOY_NUM_AXES];
409
410         if ((!joy_installed)||(!joy_present)) { *x=*y=0; return; }
411
412         flags=joystick_read_raw_axis( JOY_1_X_AXIS+JOY_1_Y_AXIS, axis );
413
414         if ( flags & JOY_1_X_AXIS )
415                 *x = joy_get_scaled_reading( axis[0], 0 );
416         else
417                 *x = 0;
418
419         if ( flags & JOY_1_Y_AXIS )
420                 *y = joy_get_scaled_reading( axis[1], 1 );
421         else
422                 *y = 0;
423 }
424
425 ubyte joy_read_stick( ubyte masks, int *axis )  
426 {
427         ubyte flags;
428         int raw_axis[JOY_NUM_AXES];
429
430         if ((!joy_installed)||(!joy_present)) { 
431                 axis[0] = 0; axis[1] = 0;
432                 axis[2] = 0; axis[3] = 0;
433                 axis[4] = 0; axis[5] = 0; 
434                 return 0;  
435         }
436
437         flags=joystick_read_raw_axis( masks, raw_axis );
438
439         if ( flags & JOY_1_X_AXIS )
440                 axis[0] = joy_get_scaled_reading( raw_axis[0], 0 );
441         else
442                 axis[0] = 0;
443
444         if ( flags & JOY_1_Y_AXIS )
445                 axis[1] = joy_get_scaled_reading( raw_axis[1], 1 );
446         else
447                 axis[1] = 0;
448
449         if ( flags & JOY_1_R_AXIS )
450                 axis[2] = joy_get_scaled_reading( raw_axis[2], 2 );
451         else
452                 axis[2] = 0;
453
454         if ( flags & JOY_1_Z_AXIS )
455                 axis[3] = joy_get_scaled_reading( raw_axis[3], 3 );
456         else
457                 axis[3] = 0;
458
459         if ( flags & JOY_1_U_AXIS )
460                 axis[4] = joy_get_scaled_reading( raw_axis[4], 4);
461         else
462                 axis[4] = 0;
463
464         if ( flags & JOY_1_V_AXIS )
465                 axis[5] = joy_get_scaled_reading( raw_axis[5], 5 );
466         else
467                 axis[5] = 0;
468
469
470         return flags;
471 }
472
473 int joy_get_btns()      
474 {
475         if ((!joy_installed)||(!joy_present)) return 0;
476
477         return joy_read_raw_buttons();
478 }
479
480
481 //Begin section modified 3/7/99 - Owen Evans
482
483 void joy_get_btn_down_cnt( int *btn0, int *btn1 )
484 {
485         if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
486
487         joy_get_btns();
488
489         *btn0 = joystick.buttons[0].downcount;
490         joystick.buttons[0].downcount = 0;
491         *btn1 = joystick.buttons[1].downcount;
492         joystick.buttons[1].downcount = 0;
493 }
494
495 int joy_get_button_state( int btn )     
496 {    
497         if ((!joy_installed)||(!joy_present)) return 0;
498         if (btn >= JOY_MAX_BUTTONS)
499                 return 0;
500
501         joy_get_btns();
502
503         return joystick.buttons[btn].state;
504 }
505
506 int joy_get_button_up_cnt( int btn ) 
507 {
508         int count;
509
510         if ((!joy_installed)||(!joy_present)) return 0;
511
512         if (btn >= JOY_MAX_BUTTONS)
513                 return 0;
514
515         count = joystick.buttons[btn].upcount;
516         joystick.buttons[btn].upcount = 0;
517
518         return count;
519 }
520
521 int joy_get_button_down_cnt( int btn ) 
522 {
523         int count;
524
525         if ((!joy_installed)||(!joy_present)) return 0;
526         if (btn >= JOY_MAX_BUTTONS)
527                 return 0;
528
529         joy_get_btns();
530
531         count = joystick.buttons[btn].downcount;
532         joystick.buttons[btn].downcount = 0;
533
534         return count;
535 }
536
537 fix joy_get_button_down_time( int btn ) 
538 {
539         fix count;
540
541         if ((!joy_installed)||(!joy_present)) return 0;
542         if (btn >= JOY_MAX_BUTTONS)
543                 return 0;
544
545         joy_get_btns();
546
547         if (joystick.buttons[btn].state) {
548                 count = timer_get_fixed_seconds() - joystick.buttons[btn].timedown;
549                 joystick.buttons[btn].timedown = 0;
550         } else count = 0;
551         
552         return count;
553 }
554
555 //end changed section - OE
556
557
558 void joy_get_btn_up_cnt( int *btn0, int *btn1 ) 
559 {
560         if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
561
562         *btn0 = joystick.buttons[0].upcount;
563         joystick.buttons[0].upcount = 0;
564         *btn1 = joystick.buttons[1].upcount;
565         joystick.buttons[1].upcount = 0;
566 }
567
568 void joy_set_btn_values( int btn, int state, fix timedown, int downcount, int upcount )
569 {
570         joystick.buttons[btn].ignore = 1;
571         joystick.buttons[btn].state = state;
572         joystick.buttons[btn].timedown = fixmuldiv( timedown, 1193180, 65536 );
573         joystick.buttons[btn].downcount = downcount;
574         joystick.buttons[btn].upcount = upcount;
575 }
576
577 void joy_poll()
578 {
579 }
580