diff --git a/include/wups/button_combo.h b/include/wups/button_combo.h new file mode 100644 index 0000000..8c19e8d --- /dev/null +++ b/include/wups/button_combo.h @@ -0,0 +1,299 @@ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum WUPSButtonCombo_Buttons { + //! The A button. + WUPS_BUTTON_COMBO_BUTTON_A = 0x8000, + //! The B button. + WUPS_BUTTON_COMBO_BUTTON_B = 0x4000, + //! The X button. + WUPS_BUTTON_COMBO_BUTTON_X = 0x2000, + //! The Y button. + WUPS_BUTTON_COMBO_BUTTON_Y = 0x1000, + //! The left button of the D-pad. + WUPS_BUTTON_COMBO_BUTTON_LEFT = 0x0800, + //! The right button of the D-pad. + WUPS_BUTTON_COMBO_BUTTON_RIGHT = 0x0400, + //! The up button of the D-pad. + WUPS_BUTTON_COMBO_BUTTON_UP = 0x0200, + //! The down button of the D-pad. + WUPS_BUTTON_COMBO_BUTTON_DOWN = 0x0100, + //! The ZL button. + WUPS_BUTTON_COMBO_BUTTON_ZL = 0x0080, + //! The ZR button. + WUPS_BUTTON_COMBO_BUTTON_ZR = 0x0040, + //! The L button. + WUPS_BUTTON_COMBO_BUTTON_L = 0x0020, + //! The R button. + WUPS_BUTTON_COMBO_BUTTON_R = 0x0010, + //! The + button. + WUPS_BUTTON_COMBO_BUTTON_PLUS = 0x0008, + //! The - button. + WUPS_BUTTON_COMBO_BUTTON_MINUS = 0x0004, + //! The right stick button. + WUPS_BUTTON_COMBO_BUTTON_STICK_R = 0x00020000, + //! The left stick button. + WUPS_BUTTON_COMBO_BUTTON_STICK_L = 0x00040000, + //! The TV button. + WUPS_BUTTON_COMBO_BUTTON_TV = 0x00010000, + //! The reserved bit + WUPS_BUTTON_COMBO_BUTTON_RESERVED_BIT = 0x80000, +} WUPSButtonCombo_Buttons; +WUT_ENUM_BITMASK_TYPE(WUPSButtonCombo_Buttons); + +typedef enum WUPSButtonCombo_ControllerTypes { + WUPS_BUTTON_COMBO_CONTROLLER_NONE = 0, + WUPS_BUTTON_COMBO_CONTROLLER_VPAD_0 = 1 << 0, + WUPS_BUTTON_COMBO_CONTROLLER_VPAD_1 = 1 << 1, + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_0 = 1 << 2, + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_1 = 1 << 3, + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_2 = 1 << 4, + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_3 = 1 << 5, + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_4 = 1 << 6, + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_5 = 1 << 7, + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_6 = 1 << 8, + WUPS_BUTTON_COMBO_CONTROLLER_VPAD = WUPS_BUTTON_COMBO_CONTROLLER_VPAD_0 | WUPS_BUTTON_COMBO_CONTROLLER_VPAD_1, + WUPS_BUTTON_COMBO_CONTROLLER_WPAD = (WUPS_BUTTON_COMBO_CONTROLLER_WPAD_0 | + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_1 | + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_2 | + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_3 | + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_4 | + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_5 | + WUPS_BUTTON_COMBO_CONTROLLER_WPAD_6), + WUPS_BUTTON_COMBO_CONTROLLER_ALL = WUPS_BUTTON_COMBO_CONTROLLER_VPAD | WUPS_BUTTON_COMBO_CONTROLLER_WPAD, +} WUPSButtonCombo_ControllerTypes; +WUT_ENUM_BITMASK_TYPE(WUPSButtonCombo_ControllerTypes); + +typedef enum WUPSButtonCombo_ComboType { + WUPS_BUTTON_COMBO_COMBO_TYPE_INVALID = 0, + WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD = 1, // Does check for conflicts + WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN = 2, // Does check for conflicts + WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD_OBSERVER = 3, // Does not check for conflicts + WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN_OBSERVER = 4, // Does not check for conflicts +} WUPSButtonCombo_ComboType; + +typedef enum WUPSButtonCombo_ComboStatus { + WUPS_BUTTON_COMBO_COMBO_STATUS_INVALID_STATUS = 0, + WUPS_BUTTON_COMBO_COMBO_STATUS_VALID = 1, + WUPS_BUTTON_COMBO_COMBO_STATUS_CONFLICT = 2, +} WUPSButtonCombo_ComboStatus; + +/** + * @enum WUPSButtonComboError + * @brief Represents error codes returned by storage API functions. + */ +typedef enum { + WUPS_BUTTON_COMBO_ERROR_SUCCESS = 0, /**< Success. */ + WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS = -0x01, /**< Invalid arguments passed to the function. */ + WUPS_BUTTON_COMBO_ERROR_MALLOC_FAILED = -0x02, /**< Memory allocation failed. */ + WUPS_BUTTON_COMBO_ERROR_NOT_FOUND = -0x03, /**< Not found. */ + WUPS_BUTTON_COMBO_ERROR_ABORTED = -0x04, /**< Not found. */ + WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED = -0xF0, /**< Library not initialized properly. */ + WUPS_BUTTON_COMBO_ERROR_INTERNAL_INVALID_VERSION = -0xF1, /**< Invalid API version. */ + WUPS_BUTTON_COMBO_ERROR_UNKNOWN_ERROR = -0x100 /**< Unknown error. */ +} WUPSButtonCombo_Error; + +typedef struct WUPSButtonCombo_ComboHandle { + void *handle; +#ifdef __cplusplus + WUPSButtonCombo_ComboHandle() { + handle = nullptr; + } + explicit WUPSButtonCombo_ComboHandle(void *handle) : handle(handle) {} + bool operator==(const WUPSButtonCombo_ComboHandle other) const { + return handle == other.handle; + } + bool operator==(const void *other) const { + return handle == other; + } +#endif +} WUPSButtonCombo_ComboHandle; + +typedef void (*WUPSButtonCombo_ComboCallback)(WUPSButtonCombo_ComboHandle handle, void *context); + +typedef struct WUPSButtonCombo_MetaOptions { + const char *label; +} WUPSButtonCombo_MetaOptions; + +typedef struct WUPSButtonCombo_MetaOptionsOut { + char *labelBuffer; + uint32_t labelBufferLength; +} WUPSButtonCombo_MetaOptionsOut; + +typedef struct WUPSButtonCombo_CallbackOptions { + WUPSButtonCombo_ComboCallback callback; + void *context; +} WUPSButtonCombo_CallbackOptions; + +typedef struct WUPSButtonCombo_ButtonComboOptions { + WUPSButtonCombo_ControllerTypes controllerMask; + WUPSButtonCombo_Buttons combo; +} WUPSButtonCombo_ButtonComboOptions; + +typedef struct WUPSButtonCombo_ButtonComboInfoEx { + WUPSButtonCombo_ComboType type; + WUPSButtonCombo_ButtonComboOptions basicCombo; + uint32_t optionalHoldForXFrames; +} WUPSButtonCombo_ButtonComboInfoEx; + +typedef struct WUPSButtonCombo_ComboOptions { + WUPSButtonCombo_MetaOptions metaOptions; + WUPSButtonCombo_CallbackOptions callbackOptions; + WUPSButtonCombo_ButtonComboInfoEx buttonComboOptions; +} WUPSButtonCombo_ComboOptions; + +typedef struct WUPSButtonCombo_DetectButtonComboOptions { + WUPSButtonCombo_ControllerTypes controllerMask; + uint32_t holdComboForInMs; + uint32_t holdAbortForInMs; + WUPSButtonCombo_Buttons abortButtonCombo; +} WUPSButtonCombo_DetectButtonComboOptions; + +/** + * @brief Get a string representation of the specified button_combo status. + * + * This function returns a string representation of the provided button_combo status. + * + * @param status The button_combo status to get the string representation for. + * @return A pointer to a string describing the provided button_combo status. + **/ +const char *WUPSButtonComboAPI_GetStatusStr(WUPSButtonCombo_Error status); + +/** + * @brief Adds a button combo which triggers a callback if a certain button combination is pressed on any controller. + * + * Registers a unique button combination which will trigger a callback if the combo is pressed down **on any connected controller** and the button combo is valid + * + * A press down is only detecting while pressing down buttons. Releasing a button will never trigger the callback. + * For example if the combo is "L+R+X" but you hold down "L+R+Y", press then "X" and release "Y" the combo won't be triggered. + * + * Conflict management: + * The button combination is only active if this function returns WUPS_BUTTON_COMBO_ERROR_SUCCESS and outStatus is WUPS_BUTTON_COMBO_COMBO_STATUS_VALID. + * + * If any other (valid) button combination overlaps with the button combo, the outStatus WUPS_BUTTON_COMBO_COMBO_STATUS_CONFLICT and the callback will not be triggered + * even if the combination is pressed. + * + * Even if the button combination would be unique and valid (due to the change or removal of other combos), the status won't update itself. + * To resolve a WUPS_BUTTON_COMBO_COMBO_STATUS_CONFLICT combo state you **always** have to the combo information via WUPSButtonComboAPI_UpdateButtonComboInfo or WUPSButtonComboAPI_UpdateButtonComboSimple. + * + * Conflict example: It's not possible to add any new valid button combo containing "L+R" (e.g. "X+L+R"), if there already is a button combination "L+R". + * Furthermore, it's also not possible to add a "L" or "R" combo if there already is a button combination "L+R". + * + * @param label Label of this button combo + * @param combo Combination which should be checked + * @param callbackOptions Information about the callbacks that will be called if the combo is triggered + * @param outHandle The handle of the combo will be stored here. Must not be nullptr. + * @param outStatus The status of the combo will be stored here. Only if the status is WUPS_BUTTON_COMBO_COMBO_STATUS_VALID the combo is valid. Must not be nullptr. + * @return + **/ +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboPressDown(const char *label, + WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboCallback callback, + void *context, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus); + +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboPressDownObserver(const char *label, + WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboCallback callback, + void *context, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus); +/** + * @brief Adds a button combo which triggers a callback if a certain button combination was hold for X frames on any controller. + * + * Registers a unique button combination which will trigger a callback if the combo is held for a certain amount of frames **on any connected controller** and the button combo is valid. + * + * The callback is triggered if the given button combination has been held down for the given number of frames (frame rate might vary from game to game). + * + * Conflict management: + * The button combination is only active if this function returns WUPS_BUTTON_COMBO_ERROR_SUCCESS and outStatus is WUPS_BUTTON_COMBO_COMBO_STATUS_VALID. + * + * If any other (valid) button combination overlaps with the button combo, the outStatus WUPS_BUTTON_COMBO_COMBO_STATUS_CONFLICT and the callback will not be triggered + * even if the combination is pressed. + * + * Even if the button combination would be unique and valid (due to the change or removal of other combos), the status won't update itself. + * To resolve a WUPS_BUTTON_COMBO_COMBO_STATUS_CONFLICT combo state you **always** have to the combo information via WUPSButtonComboAPI_UpdateButtonComboInfo or WUPSButtonComboAPI_UpdateButtonComboSimple. + * + * Conflict example: It's not possible to add any new valid button combo containing "L+R" (e.g. "X+L+R"), if there already is a button combination "L+R". + * Furthermore, it's also not possible to add a "L" or "R" combo if there already is a button combination "L+R". + * + * @param label Label of this button combo + * @param combo Combination which should be checked + * @param holdDurationInFrames + * @param callbackOptions Information about the callbacks that will be called if the combo is triggered + * @param outHandle The handle of the combo will be stored here. Must not be nullptr. + * @param outStatus The status of the combo will be stored here. Only if the status is WUPS_BUTTON_COMBO_COMBO_STATUS_VALID the combo is valid. Must not be nullptr. + * @return + **/ +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboHold(const char *label, + WUPSButtonCombo_Buttons combo, + uint32_t holdDurationInFrames, + WUPSButtonCombo_ComboCallback callback, + void *context, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus); + +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboHoldObserver(const char *label, + WUPSButtonCombo_Buttons combo, + uint32_t holdDurationInFrames, + WUPSButtonCombo_ComboCallback callback, + void *context, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus); + +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonCombo(const WUPSButtonCombo_ComboOptions *options, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus); + +/** +* Removes a button combo for the given handle. +*/ +WUPSButtonCombo_Error WUPSButtonComboAPI_RemoveButtonCombo(WUPSButtonCombo_ComboHandle handle); + +/** +* Returns the combo status for the given handle +*/ +WUPSButtonCombo_Error WUPSButtonComboAPI_GetButtonComboStatus(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ComboStatus *outStatus); + +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateButtonComboMeta(WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_MetaOptions *metaOptions); + +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateButtonComboCallback(WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_CallbackOptions *callbackOptions); + +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateControllerMask(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ControllerTypes controllerMask, + WUPSButtonCombo_ComboStatus *outStatus); + +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateButtonCombo(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboStatus *outStatus); + +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateHoldDuration(WUPSButtonCombo_ComboHandle handle, + uint32_t holdDurationInFrames); + +WUPSButtonCombo_Error WUPSButtonComboAPI_GetButtonComboMeta(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_MetaOptionsOut *outOptions); + +WUPSButtonCombo_Error WUPSButtonComboAPI_GetButtonComboCallback(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_CallbackOptions *outOptions); + +WUPSButtonCombo_Error WUPSButtonComboAPI_GetButtonComboInfoEx(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ButtonComboInfoEx *outOptions); + +WUPSButtonCombo_Error WUPSButtonComboAPI_CheckComboAvailable(const WUPSButtonCombo_ButtonComboOptions *options, + WUPSButtonCombo_ComboStatus *outStatus); + +WUPSButtonCombo_Error WUPSButtonComboAPI_DetectButtonCombo_Blocking(const WUPSButtonCombo_DetectButtonComboOptions *options, + WUPSButtonCombo_Buttons *outButtons); + +#ifdef __cplusplus +} +#endif diff --git a/include/wups/button_combo_internal.h b/include/wups/button_combo_internal.h new file mode 100644 index 0000000..47ed44b --- /dev/null +++ b/include/wups/button_combo_internal.h @@ -0,0 +1,141 @@ +#pragma once +#include + +/** + * @typedef WUPSButtonCombo_AddButtonComboFunction + * @brief Type alias for the function pointer to add a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_AddButtonComboFunction)(void *identifier, + const WUPSButtonCombo_ComboOptions *options, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus); + +/** + * @typedef WUPSButtonCombo_RemoveButtonComboFunction + * @brief Type alias for the function pointer to remove a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_RemoveButtonComboFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle); +/** + * @typedef WUPSButtonCombo_GetButtonComboStatusFunction + * @brief Type alias for the function pointer to check the status of a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_GetButtonComboStatusFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ComboStatus *outStatus); + + +/** + * @typedef WUPSButtonCombo_UpdateButtonComboMetaFunction + * @brief Type alias for the function pointer to update the meta data of a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_UpdateButtonComboMetaFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_MetaOptions *metaOptions); + +/** + * @typedef WUPSButtonCombo_UpdateButtonComboMetaFunction + * @brief Type alias for the function pointer to update the meta data of a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_UpdateButtonComboCallbackFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_CallbackOptions *callbackOptions); +/** + * @typedef WUPSButtonCombo_UpdateButtonComboMetaFunction + * @brief Type alias for the function pointer to update the controller mask of a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_UpdateControllerMaskFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ControllerTypes controllerMask, + WUPSButtonCombo_ComboStatus *outStatus); + +/** + * @typedef WUPSButtonCombo_UpdateButtonCallbackFunction + * @brief Type alias for the function pointer to update the callback data of a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_UpdateButtonComboFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboStatus *outStatus); + +/** + * @typedef WUPSButtonCombo_UpdateButtonComboInfoFunction + * @brief Type alias for the function pointer to update the info data of a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_UpdateHoldDurationFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle, + uint32_t holdDurationInFrames); + +/** + * @typedef WUPSButtonCombo_GetButtonComboMetaFunction + * @brief Type alias for the function pointer to get the meta data of a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_GetButtonComboMetaFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_MetaOptionsOut *outOptions); + +/** + * @typedef WUPSButtonCombo_GetButtonComboCallbackFunction + * @brief Type alias for the function pointer to get the callback data of a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_GetButtonComboCallbackFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_CallbackOptions *outOptions); + +/** + * @typedef WUPSButtonCombo_GetButtonComboInfoFunction + * @brief Type alias for the function pointer to get the info data of a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_GetButtonComboInfoExFunction)(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ButtonComboInfoEx *outOptions); + +/** + * @typedef WUPSButtonCombo_CheckComboAvailableFunction + * @brief Type alias for the function pointer check if a button combo is available. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_CheckComboAvailableFunction)(void *identifier, + const WUPSButtonCombo_ButtonComboOptions *options, + WUPSButtonCombo_ComboStatus *outStatus); + +/** + * @typedef WUPSButtonCombo_CheckComboAvailableFunction + * @brief Type alias for the function pointer to detect a button combo. For internal usage only. + */ +typedef WUPSButtonCombo_Error (*WUPSButtonCombo_DetectButtonComboBlockingFunction)(void *identifier, + const WUPSButtonCombo_DetectButtonComboOptions *options, + WUPSButtonCombo_Buttons *outButtons); + +/** + * @typedef WUPS_BUTTON_COMBO_API_VERSION + * @brief Type alias for the API version. For internal usage only. + */ +typedef uint32_t WUPS_BUTTON_COMBO_API_VERSION; + +/** + * @def WUPS_BUTTON_COMBO_CUR_API_VERSION + * @brief Current version of the button_combo API. For internal usage only. + */ +#define WUPS_BUTTON_COMBO_CUR_API_VERSION 0x01 + +/** + * @struct wups_loader_init_button_combo_args_t_ + * @brief Structure containing initialization arguments for the button_combo API. For internal usage only. + */ +typedef struct wups_loader_init_button_combo_args_t_ { + WUPS_BUTTON_COMBO_API_VERSION version; /**< API version. */ + void *identifier; /**< Unique identifier */ + WUPSButtonCombo_AddButtonComboFunction add_button_combo_function_ptr; /**< AddButtonCombo function pointer. */ + WUPSButtonCombo_RemoveButtonComboFunction remove_button_combo_function_ptr; /**< RemoveButtonCombo function pointer. */ + WUPSButtonCombo_GetButtonComboStatusFunction get_button_combo_status_function_ptr; /**< GetButtonComboStatus function pointer. */ + WUPSButtonCombo_UpdateButtonComboMetaFunction update_button_combo_meta_function_ptr; /**< UpdateButtonComboMeta function pointer. */ + WUPSButtonCombo_UpdateButtonComboCallbackFunction update_button_combo_callback_function_ptr; /**< UpdateButtonComboCallback function pointer. */ + WUPSButtonCombo_UpdateControllerMaskFunction update_controller_mask_function_ptr; /**< UpdateButtonComboExFunction function pointer. */ + WUPSButtonCombo_UpdateButtonComboFunction update_button_combo_function_ptr; /**< UpdateButtonComboExFunction function pointer. */ + WUPSButtonCombo_UpdateHoldDurationFunction update_hold_duration_function_ptr; /**< UpdateButtonComboExFunction function pointer. */ + WUPSButtonCombo_GetButtonComboMetaFunction get_button_combo_meta_function_ptr; /**< GetButtonComboMeta function pointer. */ + WUPSButtonCombo_GetButtonComboCallbackFunction get_button_combo_callback_function_ptr; /**< GetButtonComboCallback function pointer. */ + WUPSButtonCombo_GetButtonComboInfoExFunction get_button_combo_info_ex_function_ptr; /**< GetButtonComboEx function pointer. */ + WUPSButtonCombo_CheckComboAvailableFunction check_button_combo_available_function_ptr; /**< CheckComboAvailable function pointer. */ + WUPSButtonCombo_DetectButtonComboBlockingFunction detect_button_combo_blocking_function_ptr; /**< DetectButtonCombo_Blocking function pointer. */ +} wups_loader_init_button_combo_args_t; diff --git a/include/wups/common.h b/include/wups/common.h index 8f4f05c..c6b9fc2 100644 --- a/include/wups/common.h +++ b/include/wups/common.h @@ -25,15 +25,6 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include - #ifdef __cplusplus extern "C" { #endif diff --git a/include/wups/config.h b/include/wups/config.h index 387119e..f691f9d 100644 --- a/include/wups/config.h +++ b/include/wups/config.h @@ -42,6 +42,7 @@ typedef enum WUPS_CONFIG_SIMPLE_INPUT { WUPS_CONFIG_BUTTON_PLUS = (1 << 14), WUPS_CONFIG_BUTTON_MINUS = (1 << 15), } WUPS_CONFIG_SIMPLE_INPUT; +WUT_ENUM_BITMASK_TYPE(WUPS_CONFIG_SIMPLE_INPUT); typedef struct { WUPS_CONFIG_SIMPLE_INPUT buttons_h; diff --git a/include/wups/config/WUPSConfigItem.h b/include/wups/config/WUPSConfigItem.h index 4a2a2ba..4547515 100644 --- a/include/wups/config/WUPSConfigItem.h +++ b/include/wups/config/WUPSConfigItem.h @@ -3,11 +3,10 @@ #ifdef __cplusplus #include "wups/config.h" -#include class WUPSConfigItem { protected: - explicit WUPSConfigItem(WUPSConfigItemHandle itemHandle) : mHandle(itemHandle) { + explicit WUPSConfigItem(const WUPSConfigItemHandle itemHandle) : mHandle(itemHandle) { } public: diff --git a/include/wups/config/WUPSConfigItemButtonCombo.h b/include/wups/config/WUPSConfigItemButtonCombo.h new file mode 100644 index 0000000..b1598db --- /dev/null +++ b/include/wups/config/WUPSConfigItemButtonCombo.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum ConfigItemButtonCombo_State { + WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_NONE, + WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_PREPARE_FOR_HOLD, + WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_WAIT_FOR_HOLD, + WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_INVALID_HANDLE, +} ConfigItemButtonCombo_State; + +typedef struct ConfigItemButtonCombo { + char *identifier; + WUPSConfigItemHandle itemHandle; + ConfigItemButtonCombo_State itemState; + WUPSButtonCombo_ComboHandle comboHandle; + WUPSButtonCombo_Buttons defaultButtonCombo; + WUPSButtonCombo_Buttons currentButtonCombo; + WUPSButtonCombo_Buttons comboComboAtCreation; + uint32_t detectComboHoldDurationInMs; + WUPSButtonCombo_Buttons detectAbortButton; + uint32_t detectAbortHoldButtonInMs; + void *valueChangedCallback; + struct { + uint32_t conflictMsgShownForXFrames; + } intern; +} ConfigItemButtonCombo; + +typedef void (*ButtonComboValueChangedCallback)(ConfigItemButtonCombo *item, uint32_t buttonComboInWUPSButtonComboButtons); + + +WUPSConfigAPIStatus +WUPSConfigItemButtonCombo_CreateEx(const char *identifier, + const char *displayName, + WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, WUPSButtonCombo_ComboHandle comboHandle, + uint32_t detectHoldDurationInMs, WUPSButtonCombo_Buttons detectAbortButtonCombo, uint32_t detectAbortHoldButtonInMs, + ButtonComboValueChangedCallback callback, + WUPSConfigItemHandle *outItemHandle); + +WUPSConfigAPIStatus +WUPSConfigItemButtonCombo_AddToCategoryEx(WUPSConfigCategoryHandle cat, + const char *identifier, const char *displayName, + WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, WUPSButtonCombo_ComboHandle comboHandle, + uint32_t detectHoldDurationInMs, WUPSButtonCombo_Buttons detectAbortButtonCombo, uint32_t detectAbortHoldButtonInMs, + ButtonComboValueChangedCallback callback); + +WUPSConfigAPIStatus +WUPSConfigItemButtonCombo_AddToCategory(WUPSConfigCategoryHandle cat, + const char *identifier, const char *displayName, + WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, WUPSButtonCombo_ComboHandle comboHandle, + ButtonComboValueChangedCallback callback); +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus + +#include +#include +#include + +class WUPSConfigItemButtonCombo : public WUPSConfigItem { +public: + static std::optional CreateEx(const std::optional &identifier, + std::string_view displayName, + WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, WUPSButtonCombo_ComboHandle comboHandle, + uint32_t detectHoldDurationInMs, WUPSButtonCombo_Buttons detectAbortButtonCombo, uint32_t detectAbortHoldButtonInMs, + ButtonComboValueChangedCallback callback, + WUPSConfigAPIStatus &err) noexcept; + + static WUPSConfigItemButtonCombo CreateEx(const std::optional &identifier, + std::string_view displayName, + WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, WUPSButtonCombo_ComboHandle comboHandle, + uint32_t detectHoldDurationInMs, WUPSButtonCombo_Buttons detectAbortButtonCombo, uint32_t detectAbortHoldButtonInMs, + ButtonComboValueChangedCallback callback); + + static std::optional Create(const std::optional &identifier, + std::string_view displayName, + WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, WUPSButtonCombo_ComboHandle comboHandle, + ButtonComboValueChangedCallback callback, + WUPSConfigAPIStatus &err) noexcept; + + static WUPSConfigItemButtonCombo Create(const std::optional &identifier, + std::string_view displayName, + WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, WUPSButtonCombo_ComboHandle comboHandle, + ButtonComboValueChangedCallback callback); + +private: + explicit WUPSConfigItemButtonCombo(const WUPSConfigItemHandle itemHandle) : WUPSConfigItem(itemHandle) { + } +}; +#endif \ No newline at end of file diff --git a/include/wups/config_api.h b/include/wups/config_api.h index 6a214e6..c3c8c98 100644 --- a/include/wups/config_api.h +++ b/include/wups/config_api.h @@ -1,9 +1,6 @@ #pragma once #include "config.h" -#include "config/WUPSConfigCategory.h" -#include "config/WUPSConfigItem.h" -#include #include #ifdef __cplusplus @@ -79,7 +76,7 @@ WUPSConfigAPIStatus WUPSConfigAPI_Category_CreateEx(WUPSConfigAPICreateCategoryO * a different category */ static inline WUPSConfigAPIStatus WUPSConfigAPI_Category_Create(WUPSConfigAPICreateCategoryOptionsV1 options, WUPSConfigCategoryHandle *out) { - WUPSConfigAPICreateCategoryOptions optionsWrapper = { + const WUPSConfigAPICreateCategoryOptions optionsWrapper = { .version = WUPS_API_CATEGORY_OPTION_VERSION_V1, .data = {.v1 = options}, }; @@ -173,7 +170,7 @@ WUPSConfigAPIStatus WUPSConfigAPI_Item_CreateEx(WUPSConfigAPICreateItemOptions o * a category */ static inline WUPSConfigAPIStatus WUPSConfigAPI_Item_Create(WUPSConfigAPIItemOptionsV2 options, WUPSConfigItemHandle *out) { - WUPSConfigAPICreateItemOptions itemOptions = { + const WUPSConfigAPICreateItemOptions itemOptions = { .version = WUPS_API_ITEM_OPTION_VERSION_V2, .data = {.v2 = options}, }; diff --git a/include/wups/hooks.h b/include/wups/hooks.h index 46e470d..1a52b13 100644 --- a/include/wups/hooks.h +++ b/include/wups/hooks.h @@ -17,6 +17,9 @@ #pragma once #include "common.h" +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -56,8 +59,9 @@ typedef enum wups_loader_hook_type_t { WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT, /* Called when an application wants to exit */ WUPS_LOADER_HOOK_APPLICATION_ENDS, /* Called when an application ends */ - WUPS_LOADER_HOOK_INIT_STORAGE, /* Only for internal usage */ - WUPS_LOADER_HOOK_INIT_CONFIG, /* Only for internal usage */ + WUPS_LOADER_HOOK_INIT_STORAGE, /* Only for internal usage */ + WUPS_LOADER_HOOK_INIT_CONFIG, /* Only for internal usage */ + WUPS_LOADER_HOOK_INIT_BUTTON_COMBO, /* Only for internal usage */ } wups_loader_hook_type_t; typedef struct wups_loader_hook_t { @@ -123,10 +127,18 @@ typedef struct wups_loader_hook_t { #define WUPS_INIT_CONFIG_FUNCTIONS() \ __EXTERN_C_MACRO WUPSConfigAPIStatus WUPSConfigAPI_InitLibrary_Internal(wups_loader_init_config_args_t args); \ - void wups_init_config_functions(wups_loader_init_config_args_t); \ + WUPSConfigAPIStatus wups_init_config_functions(wups_loader_init_config_args_t); \ WUPS_HOOK_EX(WUPS_LOADER_HOOK_INIT_CONFIG, wups_init_config_functions); \ - void wups_init_config_functions(wups_loader_init_config_args_t args) { \ - WUPSConfigAPI_InitLibrary_Internal(args); \ + WUPSConfigAPIStatus wups_init_config_functions(wups_loader_init_config_args_t args) { \ + return WUPSConfigAPI_InitLibrary_Internal(args); \ + } + +#define WUPS_INIT_BUTTON_COMBO_FUNCTIONS() \ + __EXTERN_C_MACRO WUPSButtonCombo_Error WUPSButtonComboAPI_InitInternal(wups_loader_init_button_combo_args_t args); \ + WUPSButtonCombo_Error wups_init_button_combo_functions(wups_loader_init_button_combo_args_t); \ + WUPS_HOOK_EX(WUPS_LOADER_HOOK_INIT_BUTTON_COMBO, wups_init_button_combo_functions); \ + WUPSButtonCombo_Error wups_init_button_combo_functions(wups_loader_init_button_combo_args_t args) { \ + return WUPSButtonComboAPI_InitInternal(args); \ } #define WUPS_USE_WUT_MALLOC() \ diff --git a/include/wups/meta.h b/include/wups/meta.h index d2ad739..418b459 100644 --- a/include/wups/meta.h +++ b/include/wups/meta.h @@ -49,6 +49,7 @@ extern "C" { WUPS___INIT_WRAPPER(); \ WUPS___FINI_WRAPPER(); \ WUPS_INIT_CONFIG_FUNCTIONS(); \ + WUPS_INIT_BUTTON_COMBO_FUNCTIONS(); \ WUPS_META(buildtimestamp, __DATE__ " " __TIME__); \ WUPS_SECTION("meta") \ const char wups_meta_plugin_name[] = __plugin_name; \ @@ -61,11 +62,10 @@ extern "C" { "Function \"wut_get_thread_specific\" returned unexpected value.\n" \ "Please check linking order (expected \"-lwups -lwut\")"; -#define WUPS_PLUGIN_AUTHOR(x) WUPS_META(author, x) -#define WUPS_PLUGIN_VERSION(x) WUPS_META(version, x) -#define WUPS_PLUGIN_LICENSE(x) WUPS_META(license, x) -#define WUPS_PLUGIN_DESCRIPTION(x) WUPS_META(description, x) -#define WUPS_PLUGIN_CONFIG_REVISION(x) WUPS_META(config_revision, #x) +#define WUPS_PLUGIN_AUTHOR(x) WUPS_META(author, x) +#define WUPS_PLUGIN_VERSION(x) WUPS_META(version, x) +#define WUPS_PLUGIN_LICENSE(x) WUPS_META(license, x) +#define WUPS_PLUGIN_DESCRIPTION(x) WUPS_META(description, x) #ifdef __cplusplus } diff --git a/libraries/libwups/WUPSConfigCategory.cpp b/libraries/libwups/WUPSConfigCategory.cpp index 896338a..7757627 100644 --- a/libraries/libwups/WUPSConfigCategory.cpp +++ b/libraries/libwups/WUPSConfigCategory.cpp @@ -29,7 +29,6 @@ WUPSConfigCategory WUPSConfigCategory::Create(std::string_view name) { bool WUPSConfigCategory::add(WUPSConfigCategory &&cat, WUPSConfigAPIStatus &error) noexcept { if (mHandle.handle == nullptr || cat.getHandle().handle == nullptr) { - OSReport("mHandle %08X item %08X\n", mHandle.handle, cat.getHandle().handle); return false; } if ((error = WUPSConfigAPI_Category_AddCategory(mHandle, cat.getHandle())) != WUPSCONFIG_API_RESULT_SUCCESS) { @@ -48,7 +47,6 @@ void WUPSConfigCategory::add(WUPSConfigCategory &&cat) { bool WUPSConfigCategory::add(WUPSConfigItem &&item, WUPSConfigAPIStatus &error) noexcept { if (mHandle.handle == nullptr || item.getHandle().handle == nullptr) { - OSReport("mHandle %08X item %08X\n", mHandle.handle, item.getHandle().handle); error = WUPSCONFIG_API_RESULT_INVALID_ARGUMENT; return false; } diff --git a/libraries/libwups/WUPSConfigItemButtonCombo.cpp b/libraries/libwups/WUPSConfigItemButtonCombo.cpp new file mode 100644 index 0000000..ef84aee --- /dev/null +++ b/libraries/libwups/WUPSConfigItemButtonCombo.cpp @@ -0,0 +1,325 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + const char *getButtonChar(const WUPSButtonCombo_Buttons value) { + std::string combo; + if (value & WUPS_BUTTON_COMBO_BUTTON_A) { + return "\ue000"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_B) { + return "\ue001"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_X) { + return "\ue002"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_Y) { + return "\ue003"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_L) { + return "\ue083"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_R) { + return "\ue084"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_ZL) { + return "\ue085"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_ZR) { + return "\ue086"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_UP) { + return "\ue079"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_DOWN) { + return "\ue07A"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_LEFT) { + return "\ue07B"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_RIGHT) { + return "\ue07C"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_STICK_L) { + return "\ue081"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_STICK_R) { + return "\ue082"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_PLUS) { + return "\ue045"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_MINUS) { + return "\ue046"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_TV) { + return "\ue089"; + } + if (value & WUPS_BUTTON_COMBO_BUTTON_RESERVED_BIT) { + return "\ue01E"; + } + return ""; + } + + std::string getComboAsString(const uint32_t value) { + char comboString[60] = {}; + + for (uint32_t i = 0; i < 32; i++) { + uint32_t bitMask = 1 << i; + if (value & bitMask) { + auto val = getButtonChar(static_cast(bitMask)); + if (val[0] != '\0') { + strcat(comboString, val); + strcat(comboString, "+"); + } + } + } + std::string res(comboString); + if (res.ends_with("+")) { + res.pop_back(); + } + return res; + } + + bool checkForHold(ConfigItemButtonCombo *item) { + const auto oldCombo = item->currentButtonCombo; + + auto buttonCombo = static_cast(0); + + // This call is **blocking** it only returns if a button combo was detected or abort was triggered + WUPSButtonCombo_DetectButtonComboOptions options; + options.controllerMask = WUPS_BUTTON_COMBO_CONTROLLER_ALL; + options.abortButtonCombo = item->detectAbortButton; + options.holdAbortForInMs = item->detectAbortHoldButtonInMs; + options.holdComboForInMs = item->detectComboHoldDurationInMs; + if (const auto res = WUPSButtonComboAPI_DetectButtonCombo_Blocking(&options, &buttonCombo); res != WUPS_BUTTON_COMBO_ERROR_SUCCESS) { + OSReport("WUPSButtonComboAPI_DetectButtonCombo_Blocking returned %s\n", WUPSButtonComboAPI_GetStatusStr(res)); + return false; + } + + WUPSButtonCombo_ComboStatus status = WUPS_BUTTON_COMBO_COMBO_STATUS_INVALID_STATUS; + if (const auto res = WUPSButtonComboAPI_UpdateButtonCombo(item->comboHandle, buttonCombo, &status); res != WUPS_BUTTON_COMBO_ERROR_SUCCESS) { + OSReport("Failed to update combo info\n"); + return false; + } + if (status != WUPS_BUTTON_COMBO_COMBO_STATUS_VALID) { + // (Try) to restore "old" button combo + + if (WUPSButtonComboAPI_UpdateButtonCombo(item->comboHandle, oldCombo, &status) == WUPS_BUTTON_COMBO_ERROR_SUCCESS) { + OSReport("Failed to update combo info\n"); + } + return false; + } + + item->currentButtonCombo = buttonCombo; + return true; + } + + int32_t getCurrentValueDisplayGeneric(void *context, bool isSelected, char *out_buf, int32_t out_size) { + auto *item = static_cast(context); + + WUPSButtonCombo_ComboStatus comboStatus = WUPS_BUTTON_COMBO_COMBO_STATUS_INVALID_STATUS; + if (const auto res = WUPSButtonComboAPI_GetButtonComboStatus(item->comboHandle, &comboStatus); res != WUPS_BUTTON_COMBO_ERROR_SUCCESS) { + OSReport("WUPSConfigItemButtonCombo_getCurrentValueDisplayGeneric: GetButtonComboStatus returned %d\n", WUPSButtonComboAPI_GetStatusStr(res)); + } + + switch (item->itemState) { + case WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_INVALID_HANDLE: { + snprintf(out_buf, out_size, "ERROR: Invalid combo handle"); + return 0; + } + case WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_PREPARE_FOR_HOLD: + case WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_WAIT_FOR_HOLD: { + if (item->itemState == WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_PREPARE_FOR_HOLD) { + item->itemState = WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_WAIT_FOR_HOLD; + snprintf(out_buf, out_size, "", item->detectAbortHoldButtonInMs, getButtonChar(item->detectAbortButton)); + return 0; + } + if (checkForHold(item)) { + item->itemState = WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_NONE; + } else { + item->itemState = WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_PREPARE_FOR_HOLD; + snprintf(out_buf, out_size, "ERROR: Conflict detected. Try again"); + OSSleepTicks(OSMillisecondsToTicks(2000)); + return 0; + } + break; + } + case WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_NONE: + break; + } + + if (isSelected) { + snprintf(out_buf, out_size, "(Press \ue000 to change) %s%s", comboStatus == WUPS_BUTTON_COMBO_COMBO_STATUS_VALID ? "" : "[CONFLICT] ", getComboAsString(item->currentButtonCombo).c_str()); + } else { + snprintf(out_buf, out_size, "%s%s", comboStatus == WUPS_BUTTON_COMBO_COMBO_STATUS_VALID ? "" : "[CONFLICT] ", getComboAsString(item->currentButtonCombo).c_str()); + } + return 0; + } +} // namespace + +static int32_t WUPSConfigItemButtonCombo_getCurrentValueDisplay(void *context, char *out_buf, int32_t out_size) { + return getCurrentValueDisplayGeneric(context, false, out_buf, out_size); +} + +static void WUPSConfigItemButtonCombo_onCloseCallback(void *context) { + auto *item = static_cast(context); + if (item->comboComboAtCreation != item->currentButtonCombo && item->valueChangedCallback != nullptr) { + reinterpret_cast(item->valueChangedCallback)(item, item->currentButtonCombo); + } +} + +static void WUPSConfigItemButtonCombo_onInput(void *context, WUPSConfigSimplePadData input) { + auto *item = static_cast(context); + if (item->itemState == WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_NONE) { + if ((input.buttons_d & WUPS_CONFIG_BUTTON_A) == WUPS_CONFIG_BUTTON_A) { + item->itemState = WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_PREPARE_FOR_HOLD; + } + } +} + +static int32_t +WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay(void *context, char *out_buf, int32_t out_size) { + return getCurrentValueDisplayGeneric(context, true, out_buf, out_size); +} + +static void WUPSConfigItemButtonCombo_restoreDefault(void *context) { + auto *item = static_cast(context); + + if (const auto res = WUPSButtonComboAPI_UpdateButtonCombo(item->comboHandle, item->defaultButtonCombo, nullptr); res != WUPS_BUTTON_COMBO_ERROR_SUCCESS) { + OSReport("WUPSConfigItemButtonCombo_restoreDefault: Failed to update combo info\n"); + return; + } + item->currentButtonCombo = item->defaultButtonCombo; +} + +static bool WUPSConfigItemButtonCombo_isMovementAllowed(void *context) { + const auto *item = static_cast(context); + return item->itemState != WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_PREPARE_FOR_HOLD && item->itemState != WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_WAIT_FOR_HOLD; +} + +static void WUPSConfigItemButtonCombo_Cleanup(ConfigItemButtonCombo *item) { + if (!item) { + return; + } + free(item->identifier); + free(item); +} + +static void WUPSConfigItemButtonCombo_onDelete(void *context) { + WUPSConfigItemButtonCombo_Cleanup(static_cast(context)); +} + +WUPSConfigAPIStatus +WUPSConfigItemButtonCombo_CreateEx(const char *identifier, + const char *displayName, + const WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, const WUPSButtonCombo_ComboHandle comboHandle, + const uint32_t detectHoldDurationInMs, const WUPSButtonCombo_Buttons detectAbortButtonCombo, const uint32_t detectAbortHoldButtonInMs, + const ButtonComboValueChangedCallback callback, + WUPSConfigItemHandle *outItemHandle) { + if (outItemHandle == nullptr) { + return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT; + } + auto *item = static_cast(malloc(sizeof(ConfigItemButtonCombo))); + if (item == nullptr) { + OSReport("WUPSConfigItemButtonCombo_CreateEx: Failed to allocate memory for item data.\n"); + return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT; + } + + if (identifier != nullptr) { + item->identifier = strdup(identifier); + } else { + item->identifier = nullptr; + } + + item->comboHandle = comboHandle; + item->defaultButtonCombo = static_cast(defaultComboInWUPSButtonComboButtons); + item->currentButtonCombo = static_cast(0); + item->comboComboAtCreation = defaultComboInWUPSButtonComboButtons; + item->detectComboHoldDurationInMs = detectHoldDurationInMs; + item->detectAbortButton = detectAbortButtonCombo; + item->detectAbortHoldButtonInMs = detectAbortHoldButtonInMs; + item->valueChangedCallback = reinterpret_cast(callback); + item->intern.conflictMsgShownForXFrames = 0; + + + item->itemState = WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_NONE; + + WUPSButtonCombo_ButtonComboInfoEx comboOptions = {}; + if (const WUPSButtonCombo_Error comboErr = WUPSButtonComboAPI_GetButtonComboInfoEx(comboHandle, &comboOptions); comboErr == WUPS_BUTTON_COMBO_ERROR_SUCCESS) { + item->comboComboAtCreation = comboOptions.basicCombo.combo; + item->currentButtonCombo = comboOptions.basicCombo.combo; + } else { + OSReport("WUPSButtonComboAPI_GetButtonComboInfo failed %s\n", WUPSButtonComboAPI_GetStatusStr(comboErr)); + item->itemState = WUPS_CONFIG_ITEM_BUTTON_COMBO_STATE_INVALID_HANDLE; + } + + constexpr WUPSConfigAPIItemCallbacksV2 callbacks = { + .getCurrentValueDisplay = &WUPSConfigItemButtonCombo_getCurrentValueDisplay, + .getCurrentValueSelectedDisplay = &WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay, + .onSelected = nullptr, + .restoreDefault = &WUPSConfigItemButtonCombo_restoreDefault, + .isMovementAllowed = &WUPSConfigItemButtonCombo_isMovementAllowed, + .onCloseCallback = &WUPSConfigItemButtonCombo_onCloseCallback, + .onInput = &WUPSConfigItemButtonCombo_onInput, + .onInputEx = nullptr, + .onDelete = &WUPSConfigItemButtonCombo_onDelete, + }; + + const WUPSConfigAPIItemOptionsV2 options = { + .displayName = displayName, + .context = item, + .callbacks = callbacks, + }; + + if (const WUPSConfigAPIStatus err = WUPSConfigAPI_Item_Create(options, &item->itemHandle); err != WUPSCONFIG_API_RESULT_SUCCESS) { + OSReport("WUPSConfigItemButtonCombo_tAddToCategoryEx: Failed to create config item.\n"); + WUPSConfigItemButtonCombo_Cleanup(item); + return err; + } + + *outItemHandle = item->itemHandle; + return WUPSCONFIG_API_RESULT_SUCCESS; +} + + +WUPSConfigAPIStatus +WUPSConfigItemButtonCombo_AddToCategoryEx(const WUPSConfigCategoryHandle cat, + const char *identifier, const char *displayName, + const WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, const WUPSButtonCombo_ComboHandle comboHandle, + const uint32_t detectHoldDurationInMs, const WUPSButtonCombo_Buttons detectAbortButtonCombo, const uint32_t detectAbortHoldButtonInMs, + const ButtonComboValueChangedCallback callback) { + WUPSConfigItemHandle itemHandle; + WUPSConfigAPIStatus res; + if ((res = WUPSConfigItemButtonCombo_CreateEx(identifier, + displayName, + defaultComboInWUPSButtonComboButtons, comboHandle, + detectHoldDurationInMs, detectAbortButtonCombo, detectAbortHoldButtonInMs, + callback, &itemHandle)) != WUPSCONFIG_API_RESULT_SUCCESS) { + return res; + } + + if ((res = WUPSConfigAPI_Category_AddItem(cat, itemHandle)) != WUPSCONFIG_API_RESULT_SUCCESS) { + WUPSConfigAPI_Item_Destroy(itemHandle); + return res; + } + return WUPSCONFIG_API_RESULT_SUCCESS; +} + +WUPSConfigAPIStatus +WUPSConfigItemButtonCombo_AddToCategory(const WUPSConfigCategoryHandle cat, + const char *identifier, const char *displayName, + const WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, const WUPSButtonCombo_ComboHandle comboHandle, + const ButtonComboValueChangedCallback callback) { + return WUPSConfigItemButtonCombo_AddToCategoryEx(cat, identifier, displayName, + defaultComboInWUPSButtonComboButtons, comboHandle, + 2000, WUPS_BUTTON_COMBO_BUTTON_B, 250, + callback); +} diff --git a/libraries/libwups/WUPSConfigItemButtonComboCpp.cpp b/libraries/libwups/WUPSConfigItemButtonComboCpp.cpp new file mode 100644 index 0000000..5165674 --- /dev/null +++ b/libraries/libwups/WUPSConfigItemButtonComboCpp.cpp @@ -0,0 +1,54 @@ +#include +#include +#include + +std::optional WUPSConfigItemButtonCombo::CreateEx(const std::optional &identifier, + const std::string_view displayName, + const WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, const WUPSButtonCombo_ComboHandle comboHandle, + const uint32_t detectHoldDurationInMs, const WUPSButtonCombo_Buttons detectAbortButtonCombo, const uint32_t detectAbortHoldButtonInMs, + const ButtonComboValueChangedCallback callback, + WUPSConfigAPIStatus &err) noexcept { + WUPSConfigItemHandle itemHandle; + if ((err = WUPSConfigItemButtonCombo_CreateEx(identifier ? identifier->data() : nullptr, + displayName.data(), + defaultComboInWUPSButtonComboButtons, comboHandle, + detectHoldDurationInMs, detectAbortButtonCombo, detectAbortHoldButtonInMs, + callback, + &itemHandle)) != WUPSCONFIG_API_RESULT_SUCCESS) { + return std::nullopt; + } + return WUPSConfigItemButtonCombo(itemHandle); +} + +WUPSConfigItemButtonCombo WUPSConfigItemButtonCombo::CreateEx(const std::optional &identifier, + const std::string_view displayName, + const WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, const WUPSButtonCombo_ComboHandle comboHandle, + const uint32_t detectHoldDurationInMs, const WUPSButtonCombo_Buttons detectAbortButtonCombo, const uint32_t detectAbortHoldButtonInMs, + const ButtonComboValueChangedCallback callback) { + WUPSConfigAPIStatus err; + auto result = CreateEx(identifier, displayName, defaultComboInWUPSButtonComboButtons, comboHandle, detectHoldDurationInMs, detectAbortButtonCombo, detectAbortHoldButtonInMs, callback, err); + if (!result) { + throw std::runtime_error(std::string("Failed to create WUPSConfigItemButtonCombo: ").append(WUPSConfigAPI_GetStatusStr(err))); + } + return std::move(*result); +} + +std::optional WUPSConfigItemButtonCombo::Create(const std::optional &identifier, + const std::string_view displayName, + const WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, const WUPSButtonCombo_ComboHandle comboHandle, + const ButtonComboValueChangedCallback callback, + WUPSConfigAPIStatus &err) noexcept { + return CreateEx(identifier, displayName, defaultComboInWUPSButtonComboButtons, comboHandle, 2000, WUPS_BUTTON_COMBO_BUTTON_B, 250, callback, err); +} + +WUPSConfigItemButtonCombo WUPSConfigItemButtonCombo::Create(const std::optional &identifier, + const std::string_view displayName, + const WUPSButtonCombo_Buttons defaultComboInWUPSButtonComboButtons, const WUPSButtonCombo_ComboHandle comboHandle, + const ButtonComboValueChangedCallback callback) { + WUPSConfigAPIStatus err = WUPSCONFIG_API_RESULT_UNKNOWN_ERROR; + auto res = Create(identifier, displayName, defaultComboInWUPSButtonComboButtons, comboHandle, callback, err); + if (!res) { + throw std::runtime_error(std::string("Failed to create WUPSConfigItemButtonCombo: ").append(WUPSConfigAPI_GetStatusStr(err))); + } + return std::move(*res); +} diff --git a/libraries/libwups/button_combo.cpp b/libraries/libwups/button_combo.cpp new file mode 100644 index 0000000..b318e0a --- /dev/null +++ b/libraries/libwups/button_combo.cpp @@ -0,0 +1,314 @@ +#include +#include +#include + +struct wups_internal_button_combo_functions_t { + void *identifier = nullptr; + WUPSButtonCombo_AddButtonComboFunction add_button_combo_function_ptr = nullptr; + WUPSButtonCombo_RemoveButtonComboFunction remove_button_combo_function_ptr = nullptr; + WUPSButtonCombo_GetButtonComboStatusFunction get_button_combo_status_function_ptr = nullptr; + WUPSButtonCombo_UpdateButtonComboMetaFunction update_button_combo_meta_function_ptr = nullptr; + WUPSButtonCombo_UpdateButtonComboCallbackFunction update_button_combo_callback_function_ptr = nullptr; + WUPSButtonCombo_UpdateControllerMaskFunction update_controller_mask_function_ptr = nullptr; + WUPSButtonCombo_UpdateButtonComboFunction update_button_combo_function_ptr = nullptr; + WUPSButtonCombo_UpdateHoldDurationFunction update_hold_duration_function_ptr = nullptr; + WUPSButtonCombo_GetButtonComboMetaFunction get_button_combo_meta_function_ptr = nullptr; + WUPSButtonCombo_GetButtonComboCallbackFunction get_button_combo_callback_function_ptr = nullptr; + WUPSButtonCombo_GetButtonComboInfoExFunction get_button_combo_info_ex_function_ptr = nullptr; + WUPSButtonCombo_CheckComboAvailableFunction check_button_combo_available_function_ptr = nullptr; + WUPSButtonCombo_DetectButtonComboBlockingFunction detect_button_combo_blocking_function_ptr = nullptr; +}; + +static wups_internal_button_combo_functions_t __internal_functions = {}; + +extern "C" WUPSButtonCombo_Error WUPSButtonComboAPI_InitInternal(const wups_loader_init_button_combo_args_t &args) { + if (args.version > WUPS_BUTTON_COMBO_CUR_API_VERSION) { + __internal_functions = {}; + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_INVALID_VERSION; + } + __internal_functions.identifier = args.identifier; + __internal_functions.add_button_combo_function_ptr = args.add_button_combo_function_ptr; + __internal_functions.remove_button_combo_function_ptr = args.remove_button_combo_function_ptr; + __internal_functions.get_button_combo_status_function_ptr = args.get_button_combo_status_function_ptr; + __internal_functions.update_button_combo_meta_function_ptr = args.update_button_combo_meta_function_ptr; + __internal_functions.update_button_combo_callback_function_ptr = args.update_button_combo_callback_function_ptr; + __internal_functions.update_controller_mask_function_ptr = args.update_controller_mask_function_ptr; + __internal_functions.update_button_combo_function_ptr = args.update_button_combo_function_ptr; + __internal_functions.update_hold_duration_function_ptr = args.update_hold_duration_function_ptr; + __internal_functions.get_button_combo_meta_function_ptr = args.get_button_combo_meta_function_ptr; + __internal_functions.get_button_combo_callback_function_ptr = args.get_button_combo_callback_function_ptr; + __internal_functions.get_button_combo_info_ex_function_ptr = args.get_button_combo_info_ex_function_ptr; + __internal_functions.check_button_combo_available_function_ptr = args.check_button_combo_available_function_ptr; + __internal_functions.detect_button_combo_blocking_function_ptr = args.detect_button_combo_blocking_function_ptr; + + return WUPS_BUTTON_COMBO_ERROR_SUCCESS; +} + +const char *WUPSButtonComboAPI_GetStatusStr(const WUPSButtonCombo_Error status) { + switch (status) { + case WUPS_BUTTON_COMBO_ERROR_SUCCESS: + return "WUPS_BUTTON_COMBO_ERROR_SUCCESS"; + case WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS: + return "WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS"; + case WUPS_BUTTON_COMBO_ERROR_MALLOC_FAILED: + return "WUPS_BUTTON_COMBO_ERROR_MALLOC_FAILED"; + case WUPS_BUTTON_COMBO_ERROR_NOT_FOUND: + return "WUPS_BUTTON_COMBO_ERROR_NOT_FOUND"; + case WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED: + return "WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED"; + case WUPS_BUTTON_COMBO_ERROR_INTERNAL_INVALID_VERSION: + return "WUPS_BUTTON_COMBO_ERROR_INTERNAL_INVALID_VERSION"; + case WUPS_BUTTON_COMBO_ERROR_UNKNOWN_ERROR: + return "WUPS_BUTTON_COMBO_ERROR_UNKNOWN_ERROR"; + case WUPS_BUTTON_COMBO_ERROR_ABORTED: + return "WUPS_BUTTON_COMBO_ERROR_ABORTED"; + } + return "WUPS_BUTTON_COMBO_ERROR_UNKNOWN_ERROR"; +} + +static WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboPressEx(const char *label, + const WUPSButtonCombo_Buttons combo, + const WUPSButtonCombo_ComboCallback callback, + void *context, + const bool observer, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus) { + WUPSButtonCombo_ComboOptions options = {}; + options.metaOptions.label = label; + options.callbackOptions = {.callback = callback, .context = context}; + options.buttonComboOptions.type = observer ? WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN_OBSERVER : WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN; + options.buttonComboOptions.basicCombo.combo = combo; + options.buttonComboOptions.basicCombo.controllerMask = WUPS_BUTTON_COMBO_CONTROLLER_ALL; + + return WUPSButtonComboAPI_AddButtonCombo(&options, outHandle, outStatus); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboPressDown(const char *label, + const WUPSButtonCombo_Buttons combo, + const WUPSButtonCombo_ComboCallback callback, + void *context, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus) { + return WUPSButtonComboAPI_AddButtonComboPressEx(label, combo, callback, context, false, outHandle, outStatus); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboPressDownObserver(const char *label, + const WUPSButtonCombo_Buttons combo, + const WUPSButtonCombo_ComboCallback callback, + void *context, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus) { + return WUPSButtonComboAPI_AddButtonComboPressEx(label, combo, callback, context, true, outHandle, outStatus); +} + +static WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboHoldEx(const char *label, + const WUPSButtonCombo_Buttons combo, + const uint32_t holdDurationInFrames, + const WUPSButtonCombo_ComboCallback callback, + void *context, + const bool observer, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus) { + WUPSButtonCombo_ComboOptions options = {}; + options.metaOptions.label = label; + options.callbackOptions = {.callback = callback, .context = context}; + options.buttonComboOptions.type = observer ? WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD_OBSERVER : WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD; + options.buttonComboOptions.basicCombo.combo = combo; + options.buttonComboOptions.basicCombo.controllerMask = WUPS_BUTTON_COMBO_CONTROLLER_ALL; + options.buttonComboOptions.optionalHoldForXFrames = holdDurationInFrames; + + return WUPSButtonComboAPI_AddButtonCombo(&options, outHandle, outStatus); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboHold(const char *label, + const WUPSButtonCombo_Buttons combo, + const uint32_t holdDurationInFrames, + const WUPSButtonCombo_ComboCallback callback, + void *context, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus) { + return WUPSButtonComboAPI_AddButtonComboHoldEx(label, combo, holdDurationInFrames, callback, context, false, outHandle, outStatus); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonComboHoldObserver(const char *label, + const WUPSButtonCombo_Buttons combo, + const uint32_t holdDurationInFrames, + const WUPSButtonCombo_ComboCallback callback, + void *context, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus) { + return WUPSButtonComboAPI_AddButtonComboHoldEx(label, combo, holdDurationInFrames, callback, context, true, outHandle, outStatus); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_AddButtonCombo(const WUPSButtonCombo_ComboOptions *options, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus) { + if (__internal_functions.add_button_combo_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (options == nullptr || outHandle == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return __internal_functions.add_button_combo_function_ptr(__internal_functions.identifier, options, outHandle, outStatus); +} + + +WUPSButtonCombo_Error WUPSButtonComboAPI_RemoveButtonCombo(const WUPSButtonCombo_ComboHandle handle) { + if (__internal_functions.remove_button_combo_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + return __internal_functions.remove_button_combo_function_ptr(__internal_functions.identifier, handle); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_GetButtonComboStatus(const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ComboStatus *outStatus) { + if (__internal_functions.get_button_combo_status_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (outStatus == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return __internal_functions.get_button_combo_status_function_ptr(__internal_functions.identifier, handle, outStatus); +} +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateButtonComboMeta(const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_MetaOptions *metaOptions) { + if (__internal_functions.update_button_combo_meta_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (metaOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return __internal_functions.update_button_combo_meta_function_ptr(__internal_functions.identifier, handle, metaOptions); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateButtonComboCallback(const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_CallbackOptions *callbackOptions) { + if (__internal_functions.update_button_combo_callback_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (callbackOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return __internal_functions.update_button_combo_callback_function_ptr(__internal_functions.identifier, handle, callbackOptions); +} + + +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateControllerMask(const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_ControllerTypes controllerMask, + WUPSButtonCombo_ComboStatus *outStatus) { + if (__internal_functions.update_controller_mask_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + return __internal_functions.update_controller_mask_function_ptr(__internal_functions.identifier, handle, controllerMask, outStatus); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateButtonCombo(const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboStatus *outStatus) { + if (__internal_functions.update_button_combo_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + return __internal_functions.update_button_combo_function_ptr(__internal_functions.identifier, handle, combo, outStatus); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_UpdateHoldDuration(const WUPSButtonCombo_ComboHandle handle, + const uint32_t holdDurationInFrames) { + if (__internal_functions.update_hold_duration_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + return __internal_functions.update_hold_duration_function_ptr(__internal_functions.identifier, handle, holdDurationInFrames); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_GetButtonComboMeta(const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_MetaOptionsOut *outOptions) { + if (__internal_functions.get_button_combo_meta_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (outOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return __internal_functions.get_button_combo_meta_function_ptr(__internal_functions.identifier, handle, outOptions); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_GetButtonComboCallback(const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_CallbackOptions *outOptions) { + if (__internal_functions.get_button_combo_callback_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (outOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return __internal_functions.get_button_combo_callback_function_ptr(__internal_functions.identifier, handle, outOptions); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_GetButtonComboInfoEx(const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ButtonComboInfoEx *outOptions) { + if (__internal_functions.get_button_combo_info_ex_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (outOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return __internal_functions.get_button_combo_info_ex_function_ptr(__internal_functions.identifier, handle, outOptions); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_CheckComboAvailable(const WUPSButtonCombo_ButtonComboOptions *options, + WUPSButtonCombo_ComboStatus *outStatus) { + if (__internal_functions.check_button_combo_available_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (options == nullptr || outStatus == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return __internal_functions.check_button_combo_available_function_ptr(__internal_functions.identifier, options, outStatus); +} + +WUPSButtonCombo_Error WUPSButtonComboAPI_DetectButtonCombo_Blocking(const WUPSButtonCombo_DetectButtonComboOptions *options, + WUPSButtonCombo_Buttons *outButtons) { + if (__internal_functions.detect_button_combo_blocking_function_ptr == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (__internal_functions.identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_NOT_INITIALIZED; + } + if (options == nullptr || outButtons == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return __internal_functions.detect_button_combo_blocking_function_ptr(__internal_functions.identifier, options, outButtons); +}