From ba5470ce7422e54d87dfdd5b24c4e13bb58b095a Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 28 Apr 2014 21:06:23 -0400 Subject: setup: Add support for button axis calibration. Detect when we need to configure a "button axis" by falling back to buttons when none of the joystick axes are significantly outside of the centered range. Add extra calibration stages to get the D-pad buttons for right and down in these cases. --- src/setup/joystick.c | 202 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 176 insertions(+), 26 deletions(-) (limited to 'src/setup/joystick.c') diff --git a/src/setup/joystick.c b/src/setup/joystick.c index fcb907a0..acabb61f 100644 --- a/src/setup/joystick.c +++ b/src/setup/joystick.c @@ -23,6 +23,7 @@ #include #include "doomtype.h" +#include "i_joystick.h" #include "m_config.h" #include "m_controls.h" #include "textscreen.h" @@ -37,6 +38,10 @@ typedef enum CALIBRATE_CENTER, CALIBRATE_LEFT, CALIBRATE_UP, + + // These are only used when defining button axes: + CALIBRATE_RIGHT, + CALIBRATE_DOWN, } calibration_stage_t; // SDL joystick successfully initialized? @@ -51,6 +56,12 @@ static int usejoystick = 0; int joystick_index = -1; +// Calibration button. This is the button the user pressed at the +// start of the calibration sequence. They *must* press this button +// for each subsequent sequence. + +static int calibrate_button = -1; + // Which joystick axis to use for horizontal movement, and whether to // invert the direction: @@ -185,18 +196,52 @@ static void SetCalibrationLabel(void) break; case CALIBRATE_UP: message = "Push the D-pad or joystick up,\n" - "and press a button."; + "and press the button."; break; case CALIBRATE_LEFT: message = "Push the D-pad or joystick to the\n" - "left, and press a button."; + "left, and press the button."; + break; + case CALIBRATE_DOWN: + message = "Push the D-pad or joystick down,\n" + "and press the button."; + break; + case CALIBRATE_RIGHT: + message = "Push the D-pad or joystick to the\n" + "right, and press the button."; break; } TXT_SetLabel(calibration_label, message); } -static void CalibrateAxis(int *axis_index, int *axis_invert) +// Search all axes on joystick being configured; find a button that is +// pressed (other than the calibrate button). + +static int FindPressedAxisButton(void) +{ + SDL_Joystick *joystick; + int i; + + joystick = all_joysticks[joystick_index]; + + for (i = 0; i < SDL_JoystickNumButtons(joystick); ++i) + { + if (i == calibrate_button) + { + continue; + } + + if (SDL_JoystickGetButton(joystick, i)) + { + return i; + } + } + + return -1; +} + +static boolean CalibrateAxis(int *axis_index, int *axis_invert) { SDL_Joystick *joystick; int best_axis; @@ -218,7 +263,7 @@ static void CalibrateAxis(int *axis_index, int *axis_invert) for (i=0; i best_value) { best_value = abs(axis_value); @@ -227,48 +272,153 @@ static void CalibrateAxis(int *axis_index, int *axis_invert) } } - // Save the best values we have found + // Did we find one axis that had a significant value? + + if (best_value > 32768 / 4) + { + // Save the best values we have found + + *axis_index = best_axis; + *axis_invert = best_invert; + return true; + } + + // Otherwise, maybe this is a "button axis", like the PS3 SIXAXIS + // controller that exposes the D-pad as four individual buttons. + // Search for a button. + + i = FindPressedAxisButton(); + + if (i >= 0) + { + *axis_index = CREATE_BUTTON_AXIS(i, 0); + *axis_invert = 0; + return true; + } - *axis_index = best_axis; - *axis_invert = best_invert; + // User pressed the button without pushing the joystick anywhere. + return false; +} + +static boolean SetButtonAxisPositive(int *axis_index) +{ + int button; + + button = FindPressedAxisButton(); + + if (button >= 0) + { + *axis_index |= CREATE_BUTTON_AXIS(0, button); + return true; + } + + return false; +} + +static int NextCalibrateStage(void) +{ + switch (calibrate_stage) + { + case CALIBRATE_CENTER: + return CALIBRATE_LEFT; + + // After pushing to the left, there are two possibilities: + // either it is a button axis, in which case we need to find + // the other button, or we can just move on to the next axis. + case CALIBRATE_LEFT: + if (IS_BUTTON_AXIS(joystick_x_axis)) + { + return CALIBRATE_RIGHT; + } + else + { + return CALIBRATE_UP; + } + + case CALIBRATE_RIGHT: + return CALIBRATE_UP; + + case CALIBRATE_UP: + if (IS_BUTTON_AXIS(joystick_y_axis)) + { + return CALIBRATE_DOWN; + } + else + { + // Finished. + return CALIBRATE_CENTER; + } + + case CALIBRATE_DOWN: + // Finished. + return CALIBRATE_CENTER; + } } static int CalibrationEventCallback(SDL_Event *event, void *user_data) { - if (event->type == SDL_JOYBUTTONDOWN - && (joystick_index == -1 || event->jbutton.which == joystick_index)) + boolean advance; + + if (event->type != SDL_JOYBUTTONDOWN) + { + return 0; + } + + // At this point, we have a button press. + // In the first "center" stage, we're just trying to work out which + // joystick is being configured and which button the user is pressing. + if (calibrate_stage == CALIBRATE_CENTER) + { + joystick_index = event->jbutton.which; + calibrate_button = event->jbutton.button; + + // Advance to next stage. + calibrate_stage = CALIBRATE_LEFT; + SetCalibrationLabel(); + return 1; + } + + // In subsequent stages, the user is asked to push in a specific + // direction and press the button. They must push the same button + // as they did before; this is necessary to support button axes. + if (event->jbutton.which == joystick_index + && event->jbutton.button == calibrate_button) { switch (calibrate_stage) { - case CALIBRATE_CENTER: - // Centering stage selects which joystick to use. - joystick_index = event->jbutton.which; + default: + case CALIBRATE_LEFT: + advance = CalibrateAxis(&joystick_x_axis, &joystick_x_invert); break; - case CALIBRATE_LEFT: - CalibrateAxis(&joystick_x_axis, &joystick_x_invert); + case CALIBRATE_RIGHT: + advance = SetButtonAxisPositive(&joystick_x_axis); break; case CALIBRATE_UP: - CalibrateAxis(&joystick_y_axis, &joystick_y_invert); + advance = CalibrateAxis(&joystick_y_axis, &joystick_y_invert); + break; + + case CALIBRATE_DOWN: + advance = SetButtonAxisPositive(&joystick_y_axis); break; } - if (calibrate_stage == CALIBRATE_UP) - { - // Final stage; close the window + // Advance to the next calibration stage? - TXT_CloseWindow(calibration_window); - } - else + if (advance) { - // Advance to the next calibration stage - - ++calibrate_stage; + calibrate_stage = NextCalibrateStage(); SetCalibrationLabel(); - } - return 1; + // Finished? + if (calibrate_stage == CALIBRATE_CENTER) + { + TXT_CloseWindow(calibration_window); + } + + return 1; + } } return 0; -- cgit v1.2.3