e2c4fe8501cf8705a52e18f787b1b056936dbde5
[btb/d2x.git] / arch / win32 / joyhh.c
1 /* $Id: joyhh.c,v 1.4 2004-05-20 23:10:17 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                   slow_read;
71         int                     max_timer;
72         int                     read_count;
73         ubyte                   last_value;
74         Button_info     buttons[MAX_BUTTONS];
75         int                     axis_min[JOY_NUM_AXES];    //changed 
76         int                     axis_center[JOY_NUM_AXES]; //changed --orulz
77         int                     axis_max[JOY_NUM_AXES];    //changed 
78 } Joy_info;
79
80 Joy_info joystick;
81
82
83 int joy_deadzone = 0;
84
85 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
86 {
87         int i;
88
89         for (i=0; i<JOY_NUM_AXES; i++)             {       //changed - orulz
90                 axis_min[i] = joystick.axis_min[i];
91                 axis_center[i] = joystick.axis_center[i];
92                 axis_max[i] = joystick.axis_max[i];
93         }
94 }
95
96 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
97 {
98         int i;
99
100         for (i=0; i<JOY_NUM_AXES; i++)             {       //changed - orulz
101                 joystick.axis_min[i] = axis_min[i];
102                 joystick.axis_center[i] = axis_center[i];
103                 joystick.axis_max[i] = axis_max[i];
104         }
105 }
106
107 ubyte joy_get_present_mask()    {
108         return joystick.present_mask;
109 }
110
111 void joy_set_timer_rate(int max_value ) {
112         joystick.max_timer = max_value;
113 }
114
115 int joy_get_timer_rate()        {
116         return joystick.max_timer;
117 }
118
119 void joy_flush()        {
120         int i;
121
122         if (!joy_installed) return;
123
124         for (i=0; i<MAX_BUTTONS; i++ )  {
125                 joystick.buttons[i].ignore = 0;
126                 joystick.buttons[i].state = 0;  
127                 joystick.buttons[i].timedown = 0;       
128                 joystick.buttons[i].downcount = 0;      
129                 joystick.buttons[i].upcount = 0;        
130         }
131
132 }
133
134
135 //Begin section modified 3/7/99 - Owen Evans
136
137 ubyte joy_read_raw_buttons()
138 {
139         JOYINFOEX joy;
140         int i;
141
142         if (!joy_present)
143                 return 0; 
144         
145         memset(&joy, 0, sizeof(joy));
146         joy.dwSize = sizeof(joy);
147         joy.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOVCTS | JOY_USEDEADZONE;
148         
149         if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR)
150                 return 0;
151
152         for (i = 0; i < MAX_BUTTONS; i++) {
153                 joystick.buttons[i].last_state = joystick.buttons[i].state;
154                 joystick.buttons[i].state = (joy.dwButtons >> i) & 0x1;
155                 if (!joystick.buttons[i].last_state && joystick.buttons[i].state) {
156                         joystick.buttons[i].timedown = timer_get_fixed_seconds();
157                         joystick.buttons[i].downcount++;
158                 }
159         }
160
161         /* Hat stuff */
162
163         if (joy.dwPOV != JOY_POVCENTERED)
164          {
165            joystick.buttons[19].state = (joy.dwPOV < JOY_POVRIGHT || joy.dwPOV > JOY_POVLEFT);
166            joystick.buttons[15].state = (joy.dwPOV < JOY_POVBACKWARD && joy.dwPOV > JOY_POVFORWARD);
167            joystick.buttons[11].state = (joy.dwPOV < JOY_POVLEFT && joy.dwPOV > JOY_POVRIGHT);
168            joystick.buttons[7].state = (joy.dwPOV > JOY_POVBACKWARD);
169          }
170
171         return (ubyte)joy.dwButtons;
172 }
173
174 //end changed section - OE
175
176
177 ubyte joystick_read_raw_axis( ubyte mask, int * axis )
178 {
179         JOYINFOEX       joy;
180         ubyte read_masks = 0;
181
182         axis[0] = 0; axis[1] = 0; //orulz: 1=x 2=y 3=r 4=z 5=u 6=v
183         axis[2] = 0; axis[3] = 0;
184         axis[4] = 0; axis[5] = 0; //HH: Added support for axes R and U
185         
186         if (!joy_installed) {
187                 return 0;
188         }
189
190         memset(&joy, 0, sizeof(joy));
191         joy.dwSize = sizeof(joy);
192         joy.dwFlags = JOY_RETURNALL | JOY_USEDEADZONE;
193         if (joyGetPosEx(joystick.joyid, &joy)!=JOYERR_NOERROR) {
194                 return 0;
195         }
196                         
197         mask &= joystick.present_mask;                  // Don't read non-present channels
198         if ( mask==0 )  {
199                 return 0;               // Don't read if no stick connected.
200         }
201
202         if (mask & JOY_1_X_AXIS) { axis[0] = joy.dwXpos; read_masks |= JOY_1_X_AXIS; }
203         if (mask & JOY_1_Y_AXIS) { axis[1] = joy.dwYpos; read_masks |= JOY_1_Y_AXIS; }
204 //orulz:
205 //        if (mask & JOY_1_Z_AXIS) { axis[2] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
206 //        if (mask & JOY_1_POV)    { axis[3] = joy.dwPOV;  read_masks |= JOY_1_POV;    }
207 //        if (mask & JOY_1_R_AXIS) { axis[4] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
208 //        if (mask & JOY_1_U_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_U_AXIS; }
209 //        if (mask & JOY_1_V_AXIS) { axis[6] = joy.dwVpos; read_masks |= JOY_1_V_AXIS; }
210         if (mask & JOY_1_R_AXIS) { axis[2] = joy.dwRpos; read_masks |= JOY_1_R_AXIS; }
211         if (mask & JOY_1_Z_AXIS) { axis[3] = joy.dwZpos; read_masks |= JOY_1_Z_AXIS; }
212         if (mask & JOY_1_U_AXIS) { axis[4] = joy.dwZpos; read_masks |= JOY_1_U_AXIS; }
213         if (mask & JOY_1_V_AXIS) { axis[5] = joy.dwUpos; read_masks |= JOY_1_V_AXIS; }
214
215         return read_masks;
216 }
217
218 int hh_average(int val1, int val2)
219 {
220         return abs(val1-val2)/2;
221 }
222
223 int joy_init(int joyid) //HH: added joyid parameter
224 {
225         int i;
226         int temp_axis[JOY_NUM_AXES];       //changed - orulz
227         JOYCAPS pjc;
228
229         if (FindArg("-nojoystick"))
230                 return 0;
231
232         atexit(joy_close);      //HH: we are a bit lazy :). Errors are ignored, so we are even double-lazy :)
233
234         joy_flush();
235         memset(&joystick, 0, sizeof(joystick));
236
237         for (i=0; i<MAX_BUTTONS; i++)
238                 joystick.buttons[i].last_state = 0;
239
240         if ( !joy_installed )   {
241                 joy_present = 0;
242                 joy_installed = 1;
243                 joystick.max_timer = 65536;
244                 joystick.read_count = 0;
245                 joystick.last_value = 0;
246         }
247
248
249         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
250         joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, temp_axis );
251
252         if ( joystick.present_mask & 3 )
253                 joy_present = 1;
254         else
255                 joy_present = 0;
256
257         
258         //HH: Main Win32 joystick initialization, incl. reading cal. stuff
259
260         if (joyGetDevCaps(joyid, &pjc, sizeof(pjc))!=JOYERR_NOERROR) {
261                 return 0;
262         }
263
264         if (joySetThreshold(joyid, pjc.wXmax/256)!=JOYERR_NOERROR) {
265                 return 0;
266         }
267
268         joystick.max_timer      = pjc.wPeriodMax;
269         joystick.axis_min[0]    = pjc.wXmin;
270         joystick.axis_min[1]    = pjc.wYmin;
271 //orulz:
272 //        joystick.axis_min[2]    = pjc.wZmin;
273 //        //HH: joystick.axis_min[3]  = pov-stuff
274 //        joystick.axis_min[4]    = pjc.wRmin;
275 //        joystick.axis_min[5]    = pjc.wUmin;
276 //        joystick.axis_min[6]    = pjc.wVmin;
277         joystick.axis_min[2]    = pjc.wRmin;
278         joystick.axis_min[3]    = pjc.wZmin;
279         joystick.axis_min[4]    = pjc.wUmin;
280         joystick.axis_min[5]    = pjc.wVmin;
281
282         joystick.axis_max[0]    = pjc.wXmax;
283         joystick.axis_max[1]    = pjc.wYmax;
284 //orulz:
285 //        joystick.axis_max[2]    = pjc.wZmax;
286 //        //HH: joystick.axis_max[3]  = pov-stuff
287 //        joystick.axis_max[4]    = pjc.wRmax;
288 //        joystick.axis_max[5]    = pjc.wUmax;
289 //        joystick.axis_max[6]    = pjc.wVmax;
290         joystick.axis_max[2]    = pjc.wRmax;
291         joystick.axis_max[3]    = pjc.wZmax;
292         joystick.axis_max[4]    = pjc.wUmax;
293         joystick.axis_max[5]    = pjc.wVmax;
294
295         joystick.axis_center[0] = hh_average(pjc.wXmax,pjc.wXmin);
296         joystick.axis_center[1] = hh_average(pjc.wYmax,pjc.wYmin);
297 //orulz:
298 //        joystick.axis_center[2] = hh_average(pjc.wZmax,pjc.wZmin);
299 //        joystick.axis_center[3] = JOY_POVCENTERED;
300 //        joystick.axis_center[4] = hh_average(pjc.wRmax,pjc.wRmin);
301 //        joystick.axis_center[5] = hh_average(pjc.wUmax,pjc.wUmin);
302 //        joystick.axis_center[6] = hh_average(pjc.wVmax,pjc.wVmin);
303         joystick.axis_center[2] = hh_average(pjc.wRmax,pjc.wRmin);
304         joystick.axis_center[3] = hh_average(pjc.wZmax,pjc.wZmin);
305         joystick.axis_center[4] = hh_average(pjc.wUmax,pjc.wUmin);
306         joystick.axis_center[5] = hh_average(pjc.wVmax,pjc.wVmin);
307
308         joystick.present_mask = JOY_1_X_AXIS | JOY_1_Y_AXIS;
309         if (pjc.wCaps & JOYCAPS_HASZ)   joystick.present_mask |= JOY_1_Z_AXIS;
310 //        if (pjc.wCaps & JOYCAPS_HASPOV) joystick.present_mask |= JOY_1_POV;
311         if (pjc.wCaps & JOYCAPS_HASR)   joystick.present_mask |= JOY_1_R_AXIS;
312         if (pjc.wCaps & JOYCAPS_HASU)   joystick.present_mask |= JOY_1_U_AXIS;
313         if (pjc.wCaps & JOYCAPS_HASV)   joystick.present_mask |= JOY_1_V_AXIS;
314
315         return joy_present;
316 }
317
318
319 void joy_close()
320 {
321         if (!joy_installed) return;
322         joy_installed = 0;
323 }
324
325
326 void joy_set_ul()       
327 {
328         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
329         joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_min );
330
331         if ( joystick.present_mask & 3 )
332                 joy_present = 1;
333         else
334                 joy_present = 0;
335 }
336
337 void joy_set_lr()       
338 {
339         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
340         joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_max );
341
342         if ( joystick.present_mask & 3 )
343                 joy_present = 1;
344         else
345                 joy_present = 0;
346 }
347
348 void joy_set_cen() 
349 {
350         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
351         joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_center );
352
353         if ( joystick.present_mask & 3 )
354                 joy_present = 1;
355         else
356                 joy_present = 0;
357 }
358
359 void joy_set_cen_fake(int channel)      
360 { }
361
362
363 int joy_get_scaled_reading( int raw, int axn )  
364 {
365  int x, d;
366
367   // Make sure it's calibrated properly.
368    if ( joystick.axis_center[axn] - joystick.axis_min[axn] < 128 )
369     return 0; //HH: had to increase to 128
370    if ( joystick.axis_max[axn] - joystick.axis_center[axn] < 128 )
371     return 0; //HH: had to increase to 128
372
373         if (!(joystick.present_mask & (1 << axn)))
374                 return 0; // fixes joy config bug where it'll always set an axis you don't even have. - 2000/01/14 Matt Mueller
375
376   raw -= joystick.axis_center[axn];
377
378    if ( raw < 0 )
379     d = joystick.axis_center[axn]-joystick.axis_min[axn];
380    else
381     d = joystick.axis_max[axn]-joystick.axis_center[axn];
382
383
384    if ( d )
385     x = (raw << 7) / d;
386    else 
387     x = 0;
388
389
390    if ( x < -128 ) x = -128;
391    if ( x > 127 ) x = 127;
392
393 //added on 4/13/99 by Victor Rachels to add deadzone control
394   d =  (joy_deadzone) * 6;
395    if ((x > (-1*d)) && (x < d))
396     x = 0;
397 //end this section addition -VR
398
399         return x;
400 }
401
402 void joy_get_pos( int *x, int *y )      
403 {
404         ubyte flags;
405         int axis[JOY_NUM_AXES];
406
407         if ((!joy_installed)||(!joy_present)) { *x=*y=0; return; }
408
409         flags=joystick_read_raw_axis( JOY_1_X_AXIS+JOY_1_Y_AXIS, axis );
410
411         if ( flags & JOY_1_X_AXIS )
412                 *x = joy_get_scaled_reading( axis[0], 0 );
413         else
414                 *x = 0;
415
416         if ( flags & JOY_1_Y_AXIS )
417                 *y = joy_get_scaled_reading( axis[1], 1 );
418         else
419                 *y = 0;
420 }
421
422 ubyte joy_read_stick( ubyte masks, int *axis )  
423 {
424         ubyte flags;
425         int raw_axis[JOY_NUM_AXES];
426
427         if ((!joy_installed)||(!joy_present)) { 
428                 axis[0] = 0; axis[1] = 0;
429                 axis[2] = 0; axis[3] = 0;
430                 axis[4] = 0; axis[5] = 0; 
431                 return 0;  
432         }
433
434         flags=joystick_read_raw_axis( masks, raw_axis );
435
436         if ( flags & JOY_1_X_AXIS )
437                 axis[0] = joy_get_scaled_reading( raw_axis[0], 0 );
438         else
439                 axis[0] = 0;
440
441         if ( flags & JOY_1_Y_AXIS )
442                 axis[1] = joy_get_scaled_reading( raw_axis[1], 1 );
443         else
444                 axis[1] = 0;
445
446         if ( flags & JOY_1_R_AXIS )
447                 axis[2] = joy_get_scaled_reading( raw_axis[2], 2 );
448         else
449                 axis[2] = 0;
450
451         if ( flags & JOY_1_Z_AXIS )
452                 axis[3] = joy_get_scaled_reading( raw_axis[3], 3 );
453         else
454                 axis[3] = 0;
455
456         if ( flags & JOY_1_U_AXIS )
457                 axis[4] = joy_get_scaled_reading( raw_axis[4], 4);
458         else
459                 axis[4] = 0;
460
461         if ( flags & JOY_1_V_AXIS )
462                 axis[5] = joy_get_scaled_reading( raw_axis[5], 5 );
463         else
464                 axis[5] = 0;
465
466
467         return flags;
468 }
469
470 int joy_get_btns()      
471 {
472         if ((!joy_installed)||(!joy_present)) return 0;
473
474         return joy_read_raw_buttons();
475 }
476
477
478 //Begin section modified 3/7/99 - Owen Evans
479
480 void joy_get_btn_down_cnt( int *btn0, int *btn1 )
481 {
482         if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
483
484         joy_get_btns();
485
486         *btn0 = joystick.buttons[0].downcount;
487         joystick.buttons[0].downcount = 0;
488         *btn1 = joystick.buttons[1].downcount;
489         joystick.buttons[1].downcount = 0;
490 }
491
492 int joy_get_button_state( int btn )     
493 {    
494         if ((!joy_installed)||(!joy_present)) return 0;
495         if ( btn >= MAX_BUTTONS ) return 0;
496
497         joy_get_btns();
498
499         return joystick.buttons[btn].state;
500 }
501
502 int joy_get_button_up_cnt( int btn ) 
503 {
504         int count;
505
506         if ((!joy_installed)||(!joy_present)) return 0;
507
508         if ( btn >= MAX_BUTTONS ) return 0;
509
510         count = joystick.buttons[btn].upcount;
511         joystick.buttons[btn].upcount = 0;
512
513         return count;
514 }
515
516 int joy_get_button_down_cnt( int btn ) 
517 {
518         int count;
519
520         if ((!joy_installed)||(!joy_present)) return 0;
521         if ( btn >= MAX_BUTTONS ) return 0;
522
523         joy_get_btns();
524
525         count = joystick.buttons[btn].downcount;
526         joystick.buttons[btn].downcount = 0;
527
528         return count;
529 }
530
531 fix joy_get_button_down_time( int btn ) 
532 {
533         fix count;
534
535         if ((!joy_installed)||(!joy_present)) return 0;
536         if ( btn >= MAX_BUTTONS ) return 0;
537
538         joy_get_btns();
539
540         if (joystick.buttons[btn].state) {
541                 count = timer_get_fixed_seconds() - joystick.buttons[btn].timedown;
542                 joystick.buttons[btn].timedown = 0;
543         } else count = 0;
544         
545         return count;
546 }
547
548 //end changed section - OE
549
550
551 void joy_get_btn_up_cnt( int *btn0, int *btn1 ) 
552 {
553         if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
554
555         *btn0 = joystick.buttons[0].upcount;
556         joystick.buttons[0].upcount = 0;
557         *btn1 = joystick.buttons[1].upcount;
558         joystick.buttons[1].upcount = 0;
559 }
560
561 void joy_set_btn_values( int btn, int state, fix timedown, int downcount, int upcount )
562 {
563         joystick.buttons[btn].ignore = 1;
564         joystick.buttons[btn].state = state;
565         joystick.buttons[btn].timedown = fixmuldiv( timedown, 1193180, 65536 );
566         joystick.buttons[btn].downcount = downcount;
567         joystick.buttons[btn].upcount = upcount;
568 }
569
570 void joy_poll()
571 {
572 }
573