summaryrefslogtreecommitdiff
path: root/src/setup/joystick.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/setup/joystick.c')
-rw-r--r--src/setup/joystick.c410
1 files changed, 54 insertions, 356 deletions
diff --git a/src/setup/joystick.c b/src/setup/joystick.c
index 1b2a00f3..41bde51c 100644
--- a/src/setup/joystick.c
+++ b/src/setup/joystick.c
@@ -25,19 +25,9 @@
#include "execute.h"
#include "joystick.h"
#include "mode.h"
+#include "txt_joyaxis.h"
#include "txt_joybinput.h"
-typedef enum
-{
- CALIBRATE_CENTER,
- CALIBRATE_LEFT,
- CALIBRATE_UP,
-
- // These are only used when defining button axes:
- CALIBRATE_RIGHT,
- CALIBRATE_DOWN,
-} calibration_stage_t;
-
typedef struct
{
char *name; // Config file name
@@ -69,15 +59,6 @@ int joystick_index = -1;
static int calibrate_button = -1;
-// "Bad" joystick axes. Sometimes an axis can be stuck or "bad". An
-// example I found is that if you unplug the nunchuck extension from
-// a Wii remote, the axes from the nunchuck can be stuck at one of
-// the maximum values. These have to be ignored, so when we ask the
-// user to center the joystick, we look for bad axes that are not
-// close to zero.
-
-static boolean *bad_axis = NULL;
-
// Which joystick axis to use for horizontal movement, and whether to
// invert the direction:
@@ -101,14 +82,14 @@ int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = {
};
static txt_button_t *joystick_button;
+static txt_joystick_axis_t *x_axis_widget;
+static txt_joystick_axis_t *y_axis_widget;
//
// Calibration
//
static txt_window_t *calibration_window;
-static txt_label_t *calibration_label;
-static calibration_stage_t calibrate_stage;
static SDL_Joystick **all_joysticks = NULL;
// Known controllers.
@@ -468,262 +449,13 @@ static void CloseAllJoysticks(void)
all_joysticks = NULL;
}
-static void SetCalibrationLabel(void)
-{
- char *message = "???";
-
- switch (calibrate_stage)
- {
- case CALIBRATE_CENTER:
- message = "Move the D-pad or joystick to the\n"
- "center, and press a button.";
- break;
- case CALIBRATE_UP:
- message = "Push the D-pad or joystick up,\n"
- "and press the button.";
- break;
- case CALIBRATE_LEFT:
- message = "Push the D-pad or joystick to the\n"
- "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);
-}
-
-// Search all axes on joystick being configured; find a button that is
-// pressed (other than the calibrate button). Returns the button number.
-
-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;
-}
-
-// Look for a hat that isn't centered. Returns the encoded hat axis.
-
-static int FindUncenteredHat(int *axis_invert)
-{
- SDL_Joystick *joystick;
- int i, hatval;
-
- joystick = all_joysticks[joystick_index];
-
- for (i = 0; i < SDL_JoystickNumHats(joystick); ++i)
- {
- hatval = SDL_JoystickGetHat(joystick, i);
-
- switch (hatval)
- {
- case SDL_HAT_LEFT:
- case SDL_HAT_RIGHT:
- *axis_invert = hatval != SDL_HAT_LEFT;
- return CREATE_HAT_AXIS(i, HAT_AXIS_HORIZONTAL);
-
- case SDL_HAT_UP:
- case SDL_HAT_DOWN:
- *axis_invert = hatval != SDL_HAT_UP;
- return CREATE_HAT_AXIS(i, HAT_AXIS_VERTICAL);
-
- // If the hat is centered, or is not pointing in a
- // definite direction, then ignore it. We don't accept
- // the hat being pointed to the upper-left for example,
- // because it's ambiguous.
- case SDL_HAT_CENTERED:
- default:
- break;
- }
- }
-
- // None found.
- return -1;
-}
-
-static boolean CalibrateAxis(int *axis_index, int *axis_invert)
-{
- SDL_Joystick *joystick;
- int best_axis;
- int best_value;
- int best_invert;
- Sint16 axis_value;
- int i;
-
- joystick = all_joysticks[joystick_index];
-
- // Check all axes to find which axis has the largest value. We test
- // for one axis at a time, so eg. when we prompt to push the joystick
- // left, whichever axis has the largest value is the left axis.
-
- best_axis = 0;
- best_value = 0;
- best_invert = 0;
-
- for (i=0; i<SDL_JoystickNumAxes(joystick); ++i)
- {
- if (bad_axis[i])
- {
- continue;
- }
-
- axis_value = SDL_JoystickGetAxis(joystick, i);
-
- if (abs(axis_value) > best_value)
- {
- best_value = abs(axis_value);
- best_invert = axis_value > 0;
- best_axis = i;
- }
- }
-
- // 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;
- }
-
- // Maybe it's a D-pad that is presented as a hat. This sounds weird
- // but gamepads like this really do exist; an example is the
- // Nyko AIRFLO Ex.
-
- i = FindUncenteredHat(axis_invert);
-
- if (i >= 0)
- {
- *axis_index = i;
- return true;
- }
-
- // User pressed the button without pushing the joystick anywhere.
- return false;
-}
-
-static boolean SetButtonAxisPositive(int *axis_index)
+static void CalibrateXAxis(void)
{
- 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 void IdentifyBadAxes(void)
-{
- SDL_Joystick *joystick;
- int i, val;
-
- free(bad_axis);
-
- joystick = all_joysticks[joystick_index];
- bad_axis = calloc(SDL_JoystickNumAxes(joystick), sizeof(boolean));
-
- // Look for uncentered axes.
-
- for (i = 0; i < SDL_JoystickNumAxes(joystick); ++i)
- {
- val = SDL_JoystickGetAxis(joystick, i);
-
- bad_axis[i] = abs(val) > (32768 / 5);
-
- if (bad_axis[i])
- {
- printf("Ignoring uncentered joystick axis #%i: %i\n", i, val);
- }
- }
+ TXT_ConfigureJoystickAxis(x_axis_widget, calibrate_button, NULL);
}
static int CalibrationEventCallback(SDL_Event *event, void *user_data)
{
- boolean advance;
-
if (event->type != SDL_JOYBUTTONDOWN)
{
return 0;
@@ -732,75 +464,28 @@ static int CalibrationEventCallback(SDL_Event *event, void *user_data)
// 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;
- IdentifyBadAxes();
+ joystick_index = event->jbutton.which;
+ calibrate_button = event->jbutton.button;
- // If the joystick is a known one, auto-load default
- // config for it.
- if (IsKnownJoystick(joystick_index))
- {
- LoadKnownConfiguration();
- usejoystick = 1;
- TXT_CloseWindow(calibration_window);
- }
- else
- {
- // Advance to next stage.
- calibrate_stage = CALIBRATE_LEFT;
- SetCalibrationLabel();
- }
-
- return 1;
+ // If the joystick is a known one, auto-load default
+ // config for it. Otherwise, proceed with calibration.
+ if (IsKnownJoystick(joystick_index))
+ {
+ LoadKnownConfiguration();
+ usejoystick = 1;
+ TXT_CloseWindow(calibration_window);
}
-
- // 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)
+ else
{
- switch (calibrate_stage)
- {
- default:
- case CALIBRATE_LEFT:
- advance = CalibrateAxis(&joystick_x_axis, &joystick_x_invert);
- break;
-
- case CALIBRATE_RIGHT:
- advance = SetButtonAxisPositive(&joystick_x_axis);
- break;
-
- case CALIBRATE_UP:
- advance = CalibrateAxis(&joystick_y_axis, &joystick_y_invert);
- break;
-
- case CALIBRATE_DOWN:
- advance = SetButtonAxisPositive(&joystick_y_axis);
- break;
- }
-
- // Advance to the next calibration stage?
+ TXT_CloseWindow(calibration_window);
- if (advance)
- {
- calibrate_stage = NextCalibrateStage();
- SetCalibrationLabel();
-
- // Finished?
- if (calibrate_stage == CALIBRATE_CENTER)
- {
- usejoystick = 1;
- TXT_CloseWindow(calibration_window);
- }
-
- return 1;
- }
+ // Calibrate joystick axes: Y axis first, then X axis once
+ // completed.
+ TXT_ConfigureJoystickAxis(y_axis_widget, calibrate_button,
+ CalibrateXAxis);
}
- return 0;
+ return 1;
}
static void NoJoystick(void)
@@ -823,8 +508,6 @@ static void CalibrateWindowClosed(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)
static void CalibrateJoystick(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
{
- calibrate_stage = CALIBRATE_CENTER;
-
// Try to open all available joysticks. If none are opened successfully,
// bomb out with an error.
@@ -837,10 +520,9 @@ static void CalibrateJoystick(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
calibration_window = TXT_NewWindow("Gamepad/Joystick calibration");
TXT_AddWidgets(calibration_window,
- TXT_NewLabel("Please follow the following instructions\n"
- "in order to calibrate your controller."),
TXT_NewStrut(0, 1),
- calibration_label = TXT_NewLabel("zzz"),
+ TXT_NewLabel("Center the D-pad or joystick,\n"
+ "and press a button."),
TXT_NewStrut(0, 1),
NULL);
@@ -849,7 +531,6 @@ static void CalibrateJoystick(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
TXT_NewWindowAbortAction(calibration_window));
TXT_SetWindowAction(calibration_window, TXT_HORIZ_RIGHT, NULL);
- TXT_SetWidgetAlign(calibration_label, TXT_HORIZ_CENTER);
TXT_SDL_SetEventCallback(CalibrationEventCallback, NULL);
TXT_SignalConnect(calibration_window, "closed", CalibrateWindowClosed, NULL);
@@ -857,9 +538,6 @@ static void CalibrateJoystick(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
// Start calibration
joystick_index = -1;
- calibrate_stage = CALIBRATE_CENTER;
-
- SetCalibrationLabel();
}
//
@@ -888,10 +566,10 @@ static void AddJoystickControl(txt_table_t *table, char *label, int *var)
void ConfigJoystick(void)
{
txt_window_t *window;
- txt_table_t *button_table;
+ txt_table_t *button_table, *axis_table;
txt_table_t *joystick_table;
- if (!joystick_initted)
+ if (!joystick_initted)
{
joystick_initted = SDL_Init(SDL_INIT_JOYSTICK) >= 0;
}
@@ -901,8 +579,27 @@ void ConfigJoystick(void)
TXT_AddWidgets(window,
TXT_NewCheckBox("Enable gamepad/joystick", &usejoystick),
joystick_table = TXT_NewTable(2),
+ TXT_NewSeparator("Axes"),
+ axis_table = TXT_NewTable(2),
TXT_NewSeparator("Buttons"),
- button_table = TXT_NewTable(2),
+ button_table = TXT_NewTable(4),
+ NULL);
+
+ TXT_SetColumnWidths(axis_table, 20, 15);
+
+ TXT_AddWidgets(axis_table,
+ TXT_NewLabel("Forward/backward"),
+ y_axis_widget = TXT_NewJoystickAxis(&joystick_y_axis,
+ &joystick_y_invert,
+ JOYSTICK_AXIS_VERTICAL),
+ TXT_NewLabel("Turn left/right"),
+ x_axis_widget = TXT_NewJoystickAxis(&joystick_x_axis,
+ &joystick_x_invert,
+ JOYSTICK_AXIS_HORIZONTAL),
+ TXT_NewLabel("Strafe left/right"),
+ TXT_NewJoystickAxis(&joystick_strafe_axis,
+ &joystick_strafe_invert,
+ JOYSTICK_AXIS_HORIZONTAL),
NULL);
TXT_SetColumnWidths(joystick_table, 20, 15);
@@ -912,10 +609,18 @@ void ConfigJoystick(void)
joystick_button = TXT_NewButton("zzzz"),
NULL);
- TXT_SetColumnWidths(button_table, 20, 15);
+ TXT_SetColumnWidths(button_table, 16, 12, 14, 11);
AddJoystickControl(button_table, "Fire/Attack", &joybfire);
+ AddJoystickControl(button_table, "Strafe Left", &joybstrafeleft);
+
AddJoystickControl(button_table, "Use", &joybuse);
+ AddJoystickControl(button_table, "Strafe Right", &joybstraferight);
+
+ AddJoystickControl(button_table, "Previous weapon", &joybprevweapon);
+ AddJoystickControl(button_table, "Strafe", &joybstrafe);
+
+ AddJoystickControl(button_table, "Next weapon", &joybnextweapon);
// High values of joybspeed are used to activate the "always run mode"
// trick in Vanilla Doom. If this has been enabled, not only is the
@@ -926,13 +631,6 @@ void ConfigJoystick(void)
AddJoystickControl(button_table, "Speed", &joybspeed);
}
- AddJoystickControl(button_table, "Strafe", &joybstrafe);
-
- AddJoystickControl(button_table, "Strafe Left", &joybstrafeleft);
- AddJoystickControl(button_table, "Strafe Right", &joybstraferight);
- AddJoystickControl(button_table, "Previous weapon", &joybprevweapon);
- AddJoystickControl(button_table, "Next weapon", &joybnextweapon);
-
if (gamemission == hexen || gamemission == strife)
{
AddJoystickControl(button_table, "Jump", &joybjump);