2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 // $Header: r:/t2repos/thief2/src/ui/joypoll.cpp,v 1.4 2000/02/19 13:28:21 toml Exp $
8 //taken from flight 2 - DL
33 #include <dbmem.h> // must be last header!
35 #define MAX_BUTTONS 32
36 #define DOWN(x) ((x)|KB_FLAG_DOWN)
38 static IJoystick
*g_pJoystick
;
41 static bool bHasNoRudder
= FALSE
;
42 static bool bHasNoThrottle
= FALSE
;
44 void DispatchFrameEvent(void);
45 // return cooked keycode given a string like 'alt_shift_g'
46 // bit16 is set if "rep" modifier was present
47 //ulong ParseKeyName( char *pKeyName );
49 long joyRangeX
, joyMidX
;
50 long joyRangeY
, joyMidY
;
51 long joyRangeZ
, joyMidZ
;
52 long joyRangeRudder
, joyMidRudder
;
54 // array of cooked keycodes for joystick buttons
55 static ulong buttonKeys
[kJoyButtonsMax
];
57 // if bit 16 of buttonKeys is set, button will repeat
58 #define BUTTON_KEY_REPEAT 0x10000
59 static float buttonRepeatTime
[kJoyButtonsMax
];
61 #define DEFAULT_BUTTON_REPEAT_INTERVAL 0.1
62 static float buttonRepeatInterval
;
63 #define DEFAULT_BUTTON_REPEAT_DELAY 0.25
64 static float buttonRepeatDelay
;
66 // an invalid keycode which indicates that this button
67 // doesn't generate a keycode OR a button event
68 #define JOYBUTTON_DISABLED 0xFFFF
70 // These are to determine if there has been a change
71 static Point joyAPos
= {0,0}; // joystick
72 static Point joyBPos
= {0,0}; // throttle,rudder
73 static Point joyCPos
= {0,0}; // hat
74 static char joyButtons
[MAX_BUTTONS
] =
75 { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
76 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; // 0 is up
77 // Hat translation values
78 static Point hatVals
[9] = {{0,0},{0,1},{1,0},{0,-1},{-1,0}, {1,1},{1,-1},{-1,-1},{-1,1}};
79 static int lastHat
= 0; // for spoofing key events
80 static int hatCodes
[5] = {0,KEY_PAD_UP
,KEY_PAD_RIGHT
,KEY_PAD_DOWN
,KEY_PAD_LEFT
};
82 cDarkJoyProcControl g_dark_joy_control
;
84 cDarkJoyProcControl :: cDarkJoyProcControl() : cIBJoyAxisProcess()
92 // set and get axis ranges
93 void UiJoyAxisConfigure(eJoystickObjs axis
, long *pRange
, long *pMid
, int deadZone
)
97 // By default, we don't know what the range is, init to reasonable values
98 // in case there is no joystick and player wants to use the mouse, for instance
104 g_pJoystick
->SetAxisRange(axis
, SHRT_MIN
, SHRT_MAX
);
105 g_pJoystick
->SetAxisDeadZone(axis
, deadZone
);
107 if (SUCCEEDED(g_pJoystick
->GetAxisRange(axis
, &joyMin
, &joyMax
)))
109 // round up range to keep us -1<x<1
110 *pRange
= (joyMax
-joyMin
)/2+1;
113 // on the (bad) off-chance that the set didn't work properly
114 *pMid
= (joyMax
+joyMin
)/2;
120 // setup joystick for use
123 sInputDeviceIter iter
;
126 IInputManager
*g_pInputMan
= AppGetObj(IInputManager
);
127 g_pInputMan
->IterStart(&iter
, IID_IJoystick
);
128 if (g_pInputMan
->IterFinished(&iter
))
129 Warning(("No joystick devices found\n"));
132 g_pJoystick
= (IJoystick
*)(g_pInputMan
->IterGet(&iter
));
134 UiJoyAxisConfigure(kJoystickXAxis
, &joyRangeX
, &joyMidX
, 0);
135 UiJoyAxisConfigure(kJoystickYAxis
, &joyRangeY
, &joyMidY
, 0);
136 UiJoyAxisConfigure(kJoystickZAxis
, &joyRangeZ
, &joyMidZ
, 0);
137 UiJoyAxisConfigure(kJoystickRudder
, &joyRangeRudder
, &joyMidRudder
, 0);
141 SafeRelease(g_pInputMan
);
143 // get the user joybutton->key mapping
144 for ( i
= 0; i
< kJoyButtonsMax
; i
++ ) {
146 sprintf( buttonName, "button%d_key", i + 1 );
148 config_get_raw( buttonName, keyName, sizeof(keyName) );
150 if ( keyName[0] != 0 ) {
151 if ( strcmpi( keyName, "off" ) == 0 ) {
152 // disable the joystick button entirely
153 buttonKeys[i] = JOYBUTTON_DISABLED;
155 // turn the button into a key
156 buttonKeys[i] = ParseKeyName( keyName );
159 */ // leave the button a button
164 // get the joystick key repeat rate
165 buttonRepeatInterval
= DEFAULT_BUTTON_REPEAT_INTERVAL
;
166 config_get_float( "joykey_repeat_interval", &buttonRepeatInterval
);
167 buttonRepeatDelay
= DEFAULT_BUTTON_REPEAT_DELAY
;
168 config_get_float( "joykey_repeat_delay", &buttonRepeatDelay
);
170 // get the no-rudder & no-throttle overrides
171 bHasNoRudder
= config_is_defined( "has_no_rudder" );
172 bHasNoThrottle
= config_is_defined( "has_no_throttle" );
174 // set rudder amidships, so if user has a throttle but no rudder, the throttle
175 // triggered joy event will have a reasonable value for the rudder
176 joyBPos
.x
= joyMidRudder
;
178 g_pInputBinder
->RegisterJoyProcObj((void *)&g_dark_joy_control
);
183 // This is to create/dispatch/handle joystick events
185 // I guess it's mostly so we can record/playback joystick events
188 void DispatchJoystickMoveEvent(char joyNum
, int x
, int y
)
192 uiMakeMotionEvent((uiMouseEvent
*)&ev
);
194 ev
.type
= UI_EVENT_JOY
;
195 ev
.action
= UI_JOY_MOTION
;
200 uiDispatchEvent( (uiEvent
*)&ev
);
204 void DispatchJoystickButtonEvent(char buttNum
, char state
)
208 uiMakeMotionEvent((uiMouseEvent
*)&ev
);
209 ev
.type
= UI_EVENT_JOY
;
211 // this is pretty hackly, but the deal is that joystick buttonup
212 // and down messages always use the 'button1' types, and the button
213 // number goes into the joynum member
215 ev
.action
= UI_JOY_BUTTON1UP
;
217 ev
.action
= UI_JOY_BUTTON1DOWN
;
223 uiDispatchEvent( (uiEvent
*)&ev
);
227 void uiJoystickPoller(void)
229 // for filtering out button presses from flightstick hats
230 static bool bHatHasEverMoved
= FALSE
;
231 static bool bRudderHasEverMoved
= FALSE
;
232 static bool bFirstPoll
= TRUE
;
233 static int oldRudderPos
;
234 static int oldPOV
= -1;
236 // spike rejection stuff (could be merged into oldPOV, but I'm tired)
237 static int hatHist1
= -1;
238 static int hatHist2
= -1;
249 // This is for retarded machines that
250 // can't deal with having i/o and the
253 IDisplayDevice
*pDisp
= AppGetObj(IDisplayDevice
);
254 l
= pDisp
->BreakLock();
256 if (g_pJoystick
!= NULL
)
257 hRes
= g_pJoystick
->GetState(&joyState
);
261 pDisp
->RestoreLock(l
);
267 if ( (joyState
.x
!= joyAPos
.x
) || (joyState
.y
!= joyAPos
.y
) )
269 DispatchJoystickMoveEvent( 0, joyState
.x
, joyState
.y
);
270 joyAPos
.x
= joyState
.x
;
271 joyAPos
.y
= joyState
.y
;
274 // clamp these to fit in 16-bits
275 joyState
.rz
= ( SHRT_MAX
< joyState
.rz
) ? SHRT_MAX
: joyState
.rz
;
276 joyState
.rz
= ( SHRT_MIN
> joyState
.rz
) ? SHRT_MIN
: joyState
.rz
;
277 joyState
.z
= ( SHRT_MAX
< joyState
.z
) ? SHRT_MAX
: joyState
.z
;
278 joyState
.z
= ( SHRT_MIN
> joyState
.z
) ? SHRT_MIN
: joyState
.z
;
280 if ( bFirstPoll
== TRUE
) {
281 // ignore the first rudder value - this is to handle screwed
282 // up drivers which say there are rudders when there are none
284 oldRudderPos
= joyState
.rz
;
286 if ( oldRudderPos
!= joyState
.rz
) {
287 bRudderHasEverMoved
= TRUE
;
289 oldRudderPos
= joyState
.rz
;
290 if ( !bRudderHasEverMoved
) {
291 // if the rudder has never moved, pretend it is centered
292 joyState
.rz
= joyMidRudder
;
295 if ( (joyState
.rz
!= joyBPos
.x
) || (joyState
.z
!= joyBPos
.y
) )
297 DispatchJoystickMoveEvent( 1, joyState
.rz
, joyState
.z
);
298 joyBPos
.x
= joyState
.rz
;
299 joyBPos
.y
= joyState
.z
;
303 // Pretend the hat is joystick C
304 switch(joyState
.POV
[0])
321 case JOY_HAT_UPRIGHT
:
324 case JOY_HAT_DOWNRIGHT
:
327 case JOY_HAT_DOWNLEFT
:
335 // has the hat ever moved?
336 if (joyState
.POV
[0] != oldPOV
)
339 oldPOV
= joyState
.POV
[0];
341 bHatHasEverMoved
= TRUE
;
344 hatval
= hatVals
[hat
];
346 // spike reject - if the hat hasn't been held for 2 successive frames, don't
347 // let the message code know about it
348 if ((hat
==hatHist1
) && (hat
!= hatHist2
))
351 if ( (hatval
.x
!= joyCPos
.x
) || (hatval
.y
!= joyCPos
.y
) )
353 DispatchJoystickMoveEvent( 2, hatval
.x
, hatval
.y
);
355 joyCPos
.x
= hatval
.x
;
356 joyCPos
.y
= hatval
.y
;
358 // Now we dispatch key events to spoof
364 ev.type = UI_EVENT_KBD_COOKED;
365 ev.code = hatCodes[lastHat];
366 uiDispatchEvent((uiEvent *)&ev);
371 // dispatch down event
372 ev.type = UI_EVENT_KBD_COOKED;
373 ev.code = DOWN(hatCodes[hat]);
374 uiDispatchEvent((uiEvent *)&ev);
386 now
= (double)(tm_get_millisec()/1000.0);
387 for(i
=0;i
<MAX_BUTTONS
;i
++)
390 // this ugliness is because a CH hat shows up as a button pattern
391 // and our joystick lib doesn't know if you have a hat, and if you don't,
392 // 'hat' is always HAT_UP. Jeez.
393 if ( (i
>3) || ( !hat
) || (!bHatHasEverMoved
))
396 buttonVal
= (joyState
.buttons
[i
] != 0);
397 if ( buttonVal
!= joyButtons
[i
] )
399 joyButtons
[i
] = buttonVal
;
400 DispatchJoystickButtonEvent( i
, joyButtons
[i
] );
401 // set first button repeat time
402 buttonRepeatTime
[i
] = now
+ buttonRepeatDelay
;
403 } else if ( buttonVal
!= 0 ) {
404 // button is still depressed - see if it should repeat
405 if ( (buttonKeys
[i
] & BUTTON_KEY_REPEAT
)
406 && (now
> buttonRepeatTime
[i
]) ) {
407 // button has repeated
408 buttonRepeatTime
[i
] = now
+ buttonRepeatInterval
;
409 DispatchJoystickButtonEvent( i
, joyButtons
[i
] );
418 // set midpoint of x, y and rudders to current joystick position
420 void uiSetControlCenter( void )
425 if ( g_pJoystick
!= NULL
) {
426 hRes
= g_pJoystick
->GetState(&joyState
);
427 if ( SUCCEEDED( hRes
) ) {
428 // set midpoints to be current joystick/throttle/rudder position
429 joyMidX
= joyState
.x
;
430 joyMidY
= joyState
.y
;
431 joyMidRudder
= joyState
.rz
;
437 // Okay, this is how we set the global
438 // joystick state, which is actually more
439 // useful for most of our stuff than making
441 bool uiJoystickHandler(uiEvent* pEv, Region* pReg, void* state)
445 if (pEv->type != UI_EVENT_JOY)
448 pJ = (uiJoyEvent*)pEv;
452 case UI_JOY_BUTTON1UP:
453 joyButtons[pJ->joynum] = 0;
454 gJoyInfo.buttons[pJ->joynum] = FALSE;
456 case UI_JOY_BUTTON1DOWN:
457 joyButtons[pJ->joynum] = 1;
458 gJoyInfo.buttons[pJ->joynum] = TRUE;
464 joyAPos.x = pJ->joypos.x;
465 joyAPos.y = pJ->joypos.y;
466 gJoyInfo.joyAX = (float)(joyAPos.x-joyMidX) / joyRangeX;
467 gJoyInfo.joyAY = (float)(joyAPos.y-joyMidY) / joyRangeY;
471 joyBPos.x = pJ->joypos.x;
472 joyBPos.y = pJ->joypos.y;
473 if ( !bHasNoRudder ) {
474 gJoyInfo.joyBX = (float)(joyBPos.x-joyMidRudder) / joyRangeRudder;
476 if ( !bHasNoThrottle ) {
477 gJoyInfo.joyBY = (float)(joyBPos.y-joyMidZ) / joyRangeZ;
481 joyCPos.x = pJ->joypos.x;
482 joyCPos.y = pJ->joypos.y;
483 gJoyInfo.hatX = (float)joyCPos.x;
484 gJoyInfo.hatY = (float)joyCPos.y;