SwipSwapMe/src/utils/WUPSConfigItemButtonCombo.cpp

265 lines
9.1 KiB
C++

#include "WUPSConfigItemButtonCombo.h"
#include "utils/input.h"
#include <coreinit/debug.h>
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vpad/input.h>
#include <wups.h>
const char *getButtonChar(VPADButtons value) {
std::string combo;
if (value & VPAD_BUTTON_A) {
return "\ue000";
}
if (value & VPAD_BUTTON_B) {
return "\ue001";
}
if (value & VPAD_BUTTON_X) {
return "\ue002";
}
if (value & VPAD_BUTTON_Y) {
return "\ue003";
}
if (value & VPAD_BUTTON_L) {
return "\ue083";
}
if (value & VPAD_BUTTON_R) {
return "\ue084";
}
if (value & VPAD_BUTTON_ZL) {
return "\ue085";
}
if (value & VPAD_BUTTON_ZR) {
return "\ue086";
}
if (value & VPAD_BUTTON_UP) {
return "\ue079";
}
if (value & VPAD_BUTTON_DOWN) {
return "\ue07A";
}
if (value & VPAD_BUTTON_LEFT) {
return "\ue07B";
}
if (value & VPAD_BUTTON_RIGHT) {
return "\ue07C";
}
if (value & VPAD_BUTTON_STICK_L) {
return "\ue081";
}
if (value & VPAD_BUTTON_STICK_R) {
return "\ue082";
}
if (value & VPAD_BUTTON_PLUS) {
return "\ue045";
}
if (value & VPAD_BUTTON_MINUS) {
return "\ue046";
}
if (value & VPAD_BUTTON_TV) {
return "\ue089";
}
if (value & VPAD_BUTTON_RESERVED_BIT) {
return "\ue01E";
}
return "";
}
std::string getComboAsString(uint32_t value) {
char comboString[60];
memset(comboString, 0, sizeof(comboString));
for (uint32_t i = 0; i < 32; i++) {
uint32_t bitMask = 1 << i;
if (value & bitMask) {
auto val = getButtonChar(static_cast<VPADButtons>(bitMask));
if (val[0] != '\0') {
strcat(comboString, val);
strcat(comboString, "+");
}
}
}
std::string res(comboString);
if (res.ends_with("+")) {
res.pop_back();
}
return res;
}
int32_t WUPSConfigItemButtonCombo_getCurrentValueDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemButtonCombo *) context;
snprintf(out_buf, out_size, "%s", getComboAsString(item->value).c_str());
return 0;
}
bool WUPSConfigItemButtonCombo_callCallback(void *context) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->callback != nullptr) {
((ButtonComboValueChangedCallback) (item->callback))(item, item->value);
return true;
}
return false;
}
void checkForHold(ConfigItemButtonCombo *item) {
uint32_t lastHold = 0;
uint32_t holdFor = 0;
uint32_t holdForTarget = item->holdDurationInMs >> 4;
uint32_t holdAbortTarget = item->abortButtonHoldDurationInMs >> 4;
auto mask = VPAD_BUTTON_A | VPAD_BUTTON_B | VPAD_BUTTON_X | VPAD_BUTTON_Y | VPAD_BUTTON_L | VPAD_BUTTON_R |
VPAD_BUTTON_ZL | VPAD_BUTTON_ZR | VPAD_BUTTON_UP | VPAD_BUTTON_DOWN | VPAD_BUTTON_LEFT | VPAD_BUTTON_RIGHT |
VPAD_BUTTON_STICK_L | VPAD_BUTTON_STICK_R | VPAD_BUTTON_PLUS | VPAD_BUTTON_MINUS | VPAD_BUTTON_TV | VPAD_BUTTON_RESERVED_BIT;
KPADStatus kpad_data{};
KPADError kpad_error;
while (true) {
uint32_t buttonsHold = 0;
VPADReadError vpad_error = VPAD_READ_UNINITIALIZED;
VPADStatus vpad_data;
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &vpad_error);
if (vpad_error == VPAD_READ_SUCCESS) {
buttonsHold = vpad_data.hold;
}
for (int i = 0; i < 4; i++) {
memset(&kpad_data, 0, sizeof(kpad_data));
if (KPADReadEx((KPADChan) i, &kpad_data, 1, &kpad_error) > 0) {
if (kpad_error == KPAD_ERROR_OK && kpad_data.extensionType != 0xFF) {
if (kpad_data.extensionType == WPAD_EXT_CORE || kpad_data.extensionType == WPAD_EXT_NUNCHUK) {
buttonsHold |= remapWiiMoteButtons(kpad_data.hold);
} else if (kpad_data.extensionType == WPAD_EXT_PRO_CONTROLLER) {
buttonsHold |= remapProButtons(kpad_data.pro.hold);
} else {
buttonsHold |= remapClassicButtons(kpad_data.classic.hold);
}
}
}
}
buttonsHold &= mask;
if (buttonsHold == lastHold) {
if (buttonsHold != 0) {
holdFor++;
}
} else {
holdFor = 0;
}
lastHold = buttonsHold;
if (holdFor >= holdAbortTarget && lastHold == item->abortButton) {
break;
}
if (holdFor >= holdForTarget) {
item->value = lastHold;
break;
}
OSSleepTicks(OSMillisecondsToTicks(16));
}
}
void WUPSConfigItemButtonCombo_onButtonPressed(void *context, WUPSConfigButtons buttons) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->state == BUTTON_COMBO_STATE_NONE) {
if ((buttons & WUPS_CONFIG_BUTTON_A) == WUPS_CONFIG_BUTTON_A) {
item->state = BUTTON_COMBO_STATE_PREPARE_FOR_HOLD;
}
}
}
bool WUPSConfigItemButtonCombo_isMovementAllowed(void *context) {
return true;
}
int32_t WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->state == BUTTON_COMBO_STATE_PREPARE_FOR_HOLD || item->state == BUTTON_COMBO_STATE_WAIT_FOR_HOLD) {
if (item->state == BUTTON_COMBO_STATE_PREPARE_FOR_HOLD) {
item->state = BUTTON_COMBO_STATE_WAIT_FOR_HOLD;
snprintf(out_buf, out_size, "<Hold new combo for %dms; hold %s to abort>", item->holdDurationInMs, getButtonChar(item->abortButton));
return 0;
} else {
checkForHold(item);
item->state = BUTTON_COMBO_STATE_NONE;
}
}
snprintf(out_buf, out_size, "(Press \ue000 to change) %s", getComboAsString(item->value).c_str());
return 0;
}
void WUPSConfigItemButtonCombo_restoreDefault(void *context) {
auto *item = (ConfigItemButtonCombo *) context;
item->value = item->defaultValue;
}
void WUPSConfigItemButtonCombo_onSelected(void *context, bool isSelected) {
}
void WUPSConfigItemButtonCombo_onDelete(void *context) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->configId) {
free(item->configId);
}
free(item);
}
extern "C" bool
WUPSConfigItemButtonComboAddToCategoryEx(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, uint32_t defaultComboInVPADButtons, uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs, ButtonComboValueChangedCallback callback) {
if (cat == 0) {
return false;
}
auto *item = (ConfigItemButtonCombo *) malloc(sizeof(ConfigItemButtonCombo));
if (item == nullptr) {
OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to allocate memory for item data.\n");
return false;
}
if (configID != nullptr) {
item->configId = strdup(configID);
} else {
item->configId = nullptr;
}
item->abortButton = abortButton;
item->abortButtonHoldDurationInMs = abortButtonHoldDurationInMs;
item->holdDurationInMs = holdDurationInMs;
item->defaultValue = defaultComboInVPADButtons;
item->value = defaultComboInVPADButtons;
item->callback = (void *) callback;
item->state = BUTTON_COMBO_STATE_NONE;
WUPSConfigCallbacks_t callbacks = {
.getCurrentValueDisplay = &WUPSConfigItemButtonCombo_getCurrentValueDisplay,
.getCurrentValueSelectedDisplay = &WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay,
.onSelected = &WUPSConfigItemButtonCombo_onSelected,
.restoreDefault = &WUPSConfigItemButtonCombo_restoreDefault,
.isMovementAllowed = &WUPSConfigItemButtonCombo_isMovementAllowed,
.callCallback = &WUPSConfigItemButtonCombo_callCallback,
.onButtonPressed = &WUPSConfigItemButtonCombo_onButtonPressed,
.onDelete = &WUPSConfigItemButtonCombo_onDelete};
if (WUPSConfigItem_Create(&item->handle, configID, displayName, callbacks, item) < 0) {
OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to create config item.\n");
free(item);
return false;
}
if (WUPSConfigCategory_AddItem(cat, item->handle) < 0) {
OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to add item to category.\n");
WUPSConfigItem_Destroy(item->handle);
return false;
}
return true;
}
extern "C" bool
WUPSConfigItemButtonComboAddToCategory(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, uint32_t defaultComboInVPADButtons, ButtonComboValueChangedCallback callback) {
return WUPSConfigItemButtonComboAddToCategoryEx(cat, configID, displayName, defaultComboInVPADButtons, 2000, VPAD_BUTTON_B, 250, callback);
}