libmx2/MX2_Project/webmx/mx2/include/joystick.hpp
Source: libmx2/MX2_Project/webmx/mx2/include/joystick.hpp
/**
* @file joystick.hpp
* @brief SDL joystick and game controller RAII wrappers.
*
* Joystick wraps SDL_Joystick for generic axis/hat/button devices.
* Controller wraps SDL_GameController for the higher-level game controller
* API (standard button mappings, triggers, etc.).
*/
#ifndef __JOYSTICK__H__
#define __JOYSTICK__H__
#include "SDL.h"
#include "wrapper.hpp"
#include <optional>
#include <string>
namespace mx {
/**
* @class Joystick
* @brief RAII wrapper for a raw SDL_Joystick device.
*
* Opens an SDL joystick by index and provides axis, hat, and button
* read-back. The handle is automatically closed on destruction.
*/
class Joystick {
public:
/** @brief Default constructor — device not yet opened. */
Joystick();
/** @brief Destructor — closes the joystick if open. */
~Joystick();
Joystick(const Joystick &) = delete;
Joystick &operator=(const Joystick &) = delete;
Joystick(Joystick &&) = delete;
Joystick &operator=(Joystick &&) = delete;
/**
* @brief Open the joystick at the given device index.
* @param index SDL joystick index (0-based).
* @return @c true on success.
*/
bool open(int index);
/**
* @brief Return the joystick's name as reported by SDL.
* @return Device name string.
*/
std::string name() const;
/** @brief Close the joystick handle if open. */
void close();
/**
* @brief Return the underlying SDL_Joystick handle as an optional.
* @return std::optional containing the handle, or std::nullopt.
*/
std::optional<SDL_Joystick *> handle();
/**
* @brief Unwrap the SDL_Joystick pointer, asserting it is open.
* @return Raw SDL_Joystick pointer.
*/
SDL_Joystick *unwrap() const;
/**
* @brief Return the device index this joystick was opened with.
* @return Device index.
*/
int joystickIndex() const;
/**
* @brief Return the number of connected joysticks.
* @return SDL_NumJoysticks() result.
*/
static int joysticks() { return SDL_NumJoysticks(); }
/** @return Number of buttons on this joystick. */
int numButtons();
/** @return Number of hats on this joystick. */
int numHats();
/** @return Number of axes on this joystick. */
int numAxes();
/**
* @brief Test whether a button is currently pressed.
* @param button Button index.
* @return @c true if pressed.
*/
bool getButton(int button);
/**
* @brief Read the position of a POV hat.
* @param hat Hat index.
* @return SDL hat position bitmask.
*/
Uint8 getHat(int hat);
/**
* @brief Read the current axis value.
* @param axis Axis index.
* @return Axis value in the range [-32768, 32767].
*/
Sint16 getAxis(int axis);
/**
* @brief Return a Wrapper around the SDL_Joystick handle.
* @return Wrapper holding the pointer or nullopt.
*/
mx::Wrapper<SDL_Joystick *> wrapper() const {
if (stick)
return stick;
return std::nullopt;
}
protected:
SDL_Joystick *stick = nullptr; ///< Underlying SDL joystick handle.
int index = -1; ///< Device index (-1 if not open).
};
/**
* @class Controller
* @brief RAII wrapper for SDL_GameController (standard layout mapping).
*
* Provides button, hat, and axis queries using SDL's gamecontroller API,
* which normalises button layouts across different physical devices.
*/
class Controller {
public:
/** @brief Default constructor — device not yet opened. */
Controller();
/** @brief Destructor — closes the controller if open. */
~Controller();
Controller(const Controller &) = delete;
Controller &operator=(const Controller &) = delete;
Controller(Controller &&) = delete;
Controller &operator=(Controller &&) = delete;
/**
* @brief Open a game controller by device index.
* @param index SDL joystick index of the controller.
* @return @c true on success.
*/
bool open(int index);
/**
* @brief Handle a device-added/removed event to maintain connection state.
* @param e SDL event to inspect.
* @return @c true if the event was a controller connect/disconnect.
*/
bool connectEvent(SDL_Event &e);
/**
* @brief Return the controller's name as reported by SDL.
* @return Device name string.
*/
std::string name() const;
/** @brief Close the controller handle if open. */
void close();
/**
* @brief Return the underlying SDL_GameController handle as an optional.
* @return std::optional containing the handle, or std::nullopt.
*/
std::optional<SDL_GameController *> handle();
/**
* @brief Unwrap the SDL_GameController pointer, asserting it is open.
* @return Raw SDL_GameController pointer.
*/
SDL_GameController *unwrap() const;
/**
* @brief Return the device index this controller was opened with.
* @return Device index.
*/
int controllerIndex() const;
/**
* @brief Return the number of connected joysticks/controllers.
* @return SDL_NumJoysticks() result.
*/
static int joysticks() { return SDL_NumJoysticks(); }
/**
* @brief Test whether a mapped button is currently pressed.
* @param button SDL_GameControllerButton constant.
* @return @c true if pressed.
*/
bool getButton(SDL_GameControllerButton button);
/**
* @brief Read the position of a POV hat.
* @param hat Hat index.
* @return SDL hat position bitmask.
*/
Uint8 getHat(int hat);
/**
* @brief Read the current axis value.
* @param axis SDL_GameControllerAxis constant.
* @return Axis value in the range [-32768, 32767].
*/
Sint16 getAxis(SDL_GameControllerAxis axis);
/**
* @brief Return a Wrapper around the SDL_GameController handle.
* @return Wrapper holding the pointer or nullopt.
*/
mx::Wrapper<SDL_GameController *> wrapper() const {
if (stick)
return stick;
return std::nullopt;
}
/**
* @brief Check whether the controller is currently usable.
* @return @c true if the controller is open and has a valid index.
*/
bool active() const {
if (index >= 0 && stick != nullptr)
return true;
return false;
}
protected:
SDL_GameController *stick = nullptr; ///< Underlying SDL game controller handle.
int index = -1; ///< Device index (-1 if not open).
};
} // namespace mx
#endif