2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
14 #include "osregistry.h"
20 static int Joy_inited = 0;
21 int Dead_zone_size = 10;
22 int Cur_joystick = -1;
23 int Joy_sensitivity = 9;
25 static int Joy_last_x_reading = 0;
26 static int Joy_last_y_reading = 0;
28 typedef struct joy_button_info {
29 int actual_state; // Set if the button is physically down
30 int state; // Set when the button goes from up to down, cleared on down to up. Different than actual_state after a flush.
34 uint last_down_check; // timestamp in milliseconds of last
37 static Joy_info joystick;
40 static SDL_JoystickID joy_id = -1;
42 joy_button_info joy_buttons[JOY_TOTAL_BUTTONS];
60 if (SDL_JoystickGetAttached(sdljoy)) {
61 SDL_JoystickClose(sdljoy);
66 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
74 max_count = SDL_NumJoysticks();
76 for (j = 0; j < max_count; j++) {
77 joy = SDL_JoystickOpen(j);
80 // nprintf (("JOYSTICK", "Joystick #%d: %s\n", j - JOYSTICKID1 + 1, SDL_JoystickName(j)));
81 mprintf(("Joystick #%d: %s %s\n", j + 1, SDL_JoystickName(joy), (j == Cur_joystick) ? "*" : " "));
82 mprintf((" Axes: %d\n", SDL_JoystickNumAxes(joy)));
83 mprintf((" Buttons: %d\n", SDL_JoystickNumButtons(joy)));
84 mprintf((" Hats: %d\n", SDL_JoystickNumHats(joy)));
85 mprintf((" Balls: %d\n", SDL_JoystickNumBalls(joy)));
86 mprintf((" Haptic: %s\n", SDL_JoystickIsHaptic(joy) ? "Yes" : "No"));
88 SDL_JoystickClose (joy);
103 if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) {
107 tmp = joy_buttons[btn].state;
112 int joy_down_count(int btn, int reset_count)
120 if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) {
124 tmp = joy_buttons[btn].down_count;
126 joy_buttons[btn].down_count = 0;
132 float joy_down_time(int btn)
135 unsigned int now, delta;
142 if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) {
146 bi = &joy_buttons[btn];
148 now = timer_get_milliseconds();
149 delta = now - bi->last_down_check;
151 if ( (now - bi->last_down_check) > 0)
152 rval = i2fl((now - bi->down_time)) / delta;
157 bi->last_down_check = now;
167 void joy_mark_button(int btn, int state)
176 if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) {
180 bi = &joy_buttons[btn];
187 bi->down_time = timer_get_milliseconds();
189 // toggle off other positions if hat
190 if (btn >= JOY_HATBACK) {
191 for (i = JOY_HATBACK; i < (JOY_HATBACK+JOY_NUM_HAT_POS); i++) {
193 joy_buttons[i].state = 0;
203 // special hat handling - make sure all hat pos are off
204 if (btn == JOY_HATBACK) {
205 for (i = JOY_HATBACK; i < (JOY_HATBACK+JOY_NUM_HAT_POS); i++) {
206 joy_buttons[i].state = 0;
221 for ( i = 0; i < JOY_TOTAL_BUTTONS; i++) {
222 bi = &joy_buttons[i];
227 bi->last_down_check = timer_get_milliseconds();
231 int joy_get_unscaled_reading(int axn)
239 if (axn >= joystick.num_axes) {
243 // Make sure it's calibrated properly.
244 if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5)
247 if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5)
250 int raw = joystick.axis_current[axn];
252 rng = joystick.axis_max[axn] - joystick.axis_min[axn];
253 raw -= joystick.axis_min[axn]; // adjust for linear range starting at 0
261 return (int) ((unsigned int) raw * (unsigned int) F1_0 / (unsigned int) rng); // convert to 0 - F1_0 range.
264 // --------------------------------------------------------------
265 // joy_get_scaled_reading()
267 // input: raw => the raw value for an axis position
268 // axn => axis number, numbered starting at 0
270 // return: joy_get_scaled_reading will return a value that represents
271 // the joystick pos from -1 to +1 for the specified axis number 'axn', and
272 // the raw value 'raw'
274 int joy_get_scaled_reading(int axn)
276 int x, d, dead_zone, rng, raw;
277 float percent, sensitivity_percent, non_sensitivity_percent;
283 if (axn >= joystick.num_axes) {
287 // Make sure it's calibrated properly.
288 if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5) {
292 if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5) {
296 raw = joystick.axis_current[axn] - joystick.axis_center[axn];
298 dead_zone = (joystick.axis_max[axn] - joystick.axis_min[axn]) * Dead_zone_size / 100;
300 if (raw < -dead_zone) {
301 rng = joystick.axis_center[axn] - joystick.axis_min[axn] - dead_zone;
302 d = -raw - dead_zone;
304 } else if (raw > dead_zone) {
305 rng = joystick.axis_max[axn] - joystick.axis_center[axn] - dead_zone;
315 Assert(Joy_sensitivity >= 0 && Joy_sensitivity <= 9);
317 // compute percentages as a range between 0 and 1
318 sensitivity_percent = (float) Joy_sensitivity / 9.0f;
319 non_sensitivity_percent = (float) (9 - Joy_sensitivity) / 9.0f;
321 // find percent of max axis is at
322 percent = (float) d / (float) rng;
324 // work sensitivity on axis value
325 percent = (percent * sensitivity_percent + percent * percent * percent * percent * percent * non_sensitivity_percent);
327 x = (int) ((float) F1_0 * percent);
329 //nprintf(("AI", "d=%6i, sens=%3i, percent=%6.3f, val=%6i, ratio=%6.3f\n", d, Joy_sensitivity, percent, (raw<0) ? -x : x, (float) d/x));
338 // --------------------------------------------------------------
341 // input: x => OUTPUT PARAMETER: x-axis position of stick (-1 to 1)
342 // y => OUTPUT PARAMETER: y-axis position of stick (-1 to 1)
343 // z => OUTPUT PARAMETER: z-axis (throttle) position of stick (-1 to 1)
344 // r => OUTPUT PARAMETER: rudder position of stick (-1 to 1)
346 // return: success => 1
349 int joy_get_pos(int *x, int *y, int *z, int *rx)
360 // joy_get_scaled_reading will return a value represents the joystick
362 if (x && joystick.num_axes > 0) {
363 *x = joy_get_scaled_reading(0);
364 Joy_last_x_reading = *x;
367 if (y && joystick.num_axes > 1) {
368 *y = joy_get_scaled_reading(1);
369 Joy_last_y_reading = *y;
372 if (z && joystick.num_axes > 2) {
373 *z = joy_get_unscaled_reading(2);
376 if (rx && joystick.num_axes > 3) {
377 *rx = joy_get_scaled_reading(3);
391 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
392 mprintf(("Could not initialize joystick\n"));
396 num_sticks = SDL_NumJoysticks();
398 if (num_sticks < 1) {
399 mprintf(("No joysticks found\n"));
403 Cur_joystick = os_config_read_uint (NULL, "CurrentJoystick", 0);
405 if (Cur_joystick >= num_sticks) {
411 sdljoy = SDL_JoystickOpen(Cur_joystick);
413 if (sdljoy == NULL) {
414 mprintf(("Unable to init joystick %d\n", Cur_joystick));
420 joy_id = SDL_JoystickInstanceID(sdljoy);
422 joystick.num_axes = SDL_JoystickNumAxes(sdljoy);
426 // Fake a calibration
429 for (i = 0; i < JOY_NUM_AXES; i++) {
430 joystick.axis_min[i] = 0;
431 joystick.axis_max[i] = 65536;
432 joystick.axis_current[i] = 32768;
446 for (int i = 0; i < JOY_NUM_AXES; i++) {
447 // if (i < joystick.num_axes) {
448 // joystick.axis_center[i] = SDL_JoystickGetAxis(sdljoy, i) + 32768;
450 joystick.axis_center[i] = 32768;
455 int joystick_read_raw_axis(int num_axes, int *axis)
463 for (i = 0; i < num_axes; i++) {
464 if (i < joystick.num_axes) {
465 axis[i] = joystick.axis_current[i];
474 bool joy_axis_valid(int axis)
476 return (axis < joystick.num_axes);
479 void joystick_update_axis(int axis, int value)
481 if (axis < JOY_NUM_AXES) {
482 joystick.axis_current[axis] = value + 32768;
486 DCF(joytest, "Test joystick")
489 while (!key_pressed(SDLK_ESCAPE)) {
490 int x, y, axis[JOY_NUM_AXES];
495 joystick_read_raw_axis(JOY_NUM_AXES, axis);
497 x = joy_get_scaled_reading(0);
498 y = joy_get_scaled_reading(1);
500 mprintf(("X=%5d Y=%5d Calibrated X=%6d Y=%6d\n", axis[0], axis[1], x, y));
506 DCF(joytest2, "Test joystick (extended)")
509 while (!key_pressed(SDLK_ESCAPE)) {
510 int x, y, z, r, axis[JOY_NUM_AXES];
515 joystick_read_raw_axis(JOY_NUM_AXES, axis);
517 x = joy_get_scaled_reading(0);
518 y = joy_get_scaled_reading(1);
519 z = joy_get_unscaled_reading(2);
520 r = joy_get_scaled_reading(3);
522 mprintf(("X=%5d Y=%5d Z=%5d Rx=%5d Ry=%5d Rz=%5d Cal X=%6d Y=%6d Z=%6d R=%6d\n", axis[0], axis[1], axis[2], axis[3], axis[4], axis[5], x, y, z, r));