mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2026-09-08 11:59:16 -05:00
Implement new ConfigAPI and new Config Menu
This commit is contained in:
@@ -1,762 +0,0 @@
|
||||
#include "ConfigUtils.h"
|
||||
|
||||
#include "../config/WUPSConfig.h"
|
||||
#include "../globals.h"
|
||||
#include "DrawUtils.h"
|
||||
#include "hooks.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <coreinit/screen.h>
|
||||
#include <gx2/display.h>
|
||||
#include <memory/mappedmemory.h>
|
||||
#include <padscore/kpad.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <vpad/input.h>
|
||||
|
||||
#define COLOR_BACKGROUND Color(238, 238, 238, 255)
|
||||
#define COLOR_TEXT Color(51, 51, 51, 255)
|
||||
#define COLOR_TEXT2 Color(72, 72, 72, 255)
|
||||
#define COLOR_DISABLED Color(255, 0, 0, 255)
|
||||
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4FF)
|
||||
#define COLOR_WHITE Color(0xFFFFFFFF)
|
||||
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||
|
||||
struct ConfigDisplayItem {
|
||||
WUPSConfig *config{};
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::string version;
|
||||
};
|
||||
|
||||
#define MAX_BUTTONS_ON_SCREEN 8
|
||||
|
||||
static uint32_t remapWiiMoteButtons(uint32_t buttons) {
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if (buttons & WPAD_BUTTON_LEFT)
|
||||
conv_buttons |= VPAD_BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_RIGHT)
|
||||
conv_buttons |= VPAD_BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_DOWN)
|
||||
conv_buttons |= VPAD_BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_BUTTON_UP)
|
||||
conv_buttons |= VPAD_BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_BUTTON_PLUS)
|
||||
conv_buttons |= VPAD_BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_B)
|
||||
conv_buttons |= VPAD_BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_BUTTON_A)
|
||||
conv_buttons |= VPAD_BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_BUTTON_MINUS)
|
||||
conv_buttons |= VPAD_BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_HOME)
|
||||
conv_buttons |= VPAD_BUTTON_HOME;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
static uint32_t remapClassicButtons(uint32_t buttons) {
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_LEFT)
|
||||
conv_buttons |= VPAD_BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
conv_buttons |= VPAD_BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_DOWN)
|
||||
conv_buttons |= VPAD_BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_UP)
|
||||
conv_buttons |= VPAD_BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_PLUS)
|
||||
conv_buttons |= VPAD_BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_X)
|
||||
conv_buttons |= VPAD_BUTTON_X;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_Y)
|
||||
conv_buttons |= VPAD_BUTTON_Y;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_B)
|
||||
conv_buttons |= VPAD_BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_A)
|
||||
conv_buttons |= VPAD_BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_MINUS)
|
||||
conv_buttons |= VPAD_BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_HOME)
|
||||
conv_buttons |= VPAD_BUTTON_HOME;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZR)
|
||||
conv_buttons |= VPAD_BUTTON_ZR;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZL)
|
||||
conv_buttons |= VPAD_BUTTON_ZL;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_R)
|
||||
conv_buttons |= VPAD_BUTTON_R;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_L)
|
||||
conv_buttons |= VPAD_BUTTON_L;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
void ConfigUtils::displayMenu() {
|
||||
renderBasicScreen("Loading configs...");
|
||||
|
||||
std::vector<ConfigDisplayItem> configs;
|
||||
for (auto &plugin : gLoadedPlugins) {
|
||||
ConfigDisplayItem cfg;
|
||||
cfg.name = plugin->getMetaInformation().getName();
|
||||
cfg.author = plugin->getMetaInformation().getAuthor();
|
||||
cfg.version = plugin->getMetaInformation().getVersion();
|
||||
|
||||
for (const auto &hook : plugin->getPluginInformation().getHookDataList()) {
|
||||
if (hook->getType() == WUPS_LOADER_HOOK_GET_CONFIG /*WUPS_LOADER_HOOK_GET_CONFIG*/) {
|
||||
if (hook->getFunctionPointer() == nullptr) {
|
||||
break;
|
||||
}
|
||||
auto *cur_config = reinterpret_cast<WUPSConfig *>(((WUPSConfigHandle(*)())((uint32_t *) hook->getFunctionPointer()))());
|
||||
if (cur_config == nullptr) {
|
||||
break;
|
||||
}
|
||||
cfg.config = cur_config;
|
||||
configs.push_back(cfg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigDisplayItem *currentConfig = nullptr;
|
||||
WUPSConfigCategory *currentCategory = nullptr;
|
||||
|
||||
uint32_t selectedConfig = 0;
|
||||
uint32_t selectedCat = 0;
|
||||
uint32_t selectedItem = 0;
|
||||
uint32_t start = 0;
|
||||
uint32_t end = MAX_BUTTONS_ON_SCREEN;
|
||||
if (configs.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = configs.size();
|
||||
}
|
||||
|
||||
bool redraw = true;
|
||||
uint32_t buttonsTriggered;
|
||||
uint32_t buttonsReleased;
|
||||
|
||||
VPADStatus vpad_data{};
|
||||
VPADReadError vpad_error;
|
||||
KPADStatus kpad_data{};
|
||||
KPADError kpad_error;
|
||||
|
||||
int32_t prevSelectedItem = -1;
|
||||
bool isItemMovementAllowed = true;
|
||||
|
||||
while (true) {
|
||||
buttonsTriggered = 0;
|
||||
buttonsReleased = 0;
|
||||
|
||||
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &vpad_error);
|
||||
if (vpad_error == VPAD_READ_SUCCESS) {
|
||||
buttonsTriggered = vpad_data.trigger;
|
||||
buttonsReleased = vpad_data.release;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
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) {
|
||||
buttonsTriggered |= remapWiiMoteButtons(kpad_data.trigger);
|
||||
buttonsReleased |= remapWiiMoteButtons(kpad_data.release);
|
||||
} else {
|
||||
buttonsTriggered |= remapClassicButtons(kpad_data.classic.trigger);
|
||||
buttonsReleased |= remapClassicButtons(kpad_data.classic.release);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonsReleased & VPAD_BUTTON_HOME) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (configs.empty()) {
|
||||
renderBasicScreen("No configurable plugins loaded");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!currentConfig || !currentConfig->config) {
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
if (selectedConfig < configs.size() - 1) {
|
||||
selectedCat = 0;
|
||||
selectedConfig++;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
if (selectedConfig > 0) {
|
||||
selectedCat = 0;
|
||||
selectedConfig--;
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_A) {
|
||||
currentConfig = &configs[selectedConfig];
|
||||
if (currentConfig == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
selectedItem = 0;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
|
||||
auto cats = currentConfig->config->getCategories();
|
||||
if (cats.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = cats.size();
|
||||
}
|
||||
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectedConfig >= end) {
|
||||
end = selectedConfig + 1;
|
||||
start = end - MAX_BUTTONS_ON_SCREEN;
|
||||
} else if (selectedConfig < start) {
|
||||
start = selectedConfig;
|
||||
end = start + MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (i == selectedConfig) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16 * 2, index + 8 + 24, configs[i].name.c_str());
|
||||
uint32_t sz = DrawUtils::getTextWidth(configs[i].name.c_str());
|
||||
DrawUtils::setFontSize(12);
|
||||
DrawUtils::print(16 * 2 + sz + 4, index + 8 + 24, configs[i].author.c_str());
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, index + 8 + 24, configs[i].version.c_str(), true);
|
||||
index += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < configs.size()) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!currentCategory) {
|
||||
auto cats = currentConfig->config->getCategories();
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
if (selectedCat < cats.size() - 1) {
|
||||
selectedItem = 0;
|
||||
prevSelectedItem = 0;
|
||||
selectedCat++;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
if (selectedCat > 0) {
|
||||
selectedItem = 0;
|
||||
prevSelectedItem = 0;
|
||||
selectedCat--;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_A) {
|
||||
if (!cats.empty() && selectedCat > cats.size() - 1) {
|
||||
selectedCat = 0;
|
||||
}
|
||||
currentCategory = cats[selectedCat];
|
||||
if (currentCategory == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("currentCategory was NULL");
|
||||
break;
|
||||
}
|
||||
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
prevSelectedItem = -1;
|
||||
|
||||
auto items = currentCategory->getItems();
|
||||
if (items.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = items.size();
|
||||
}
|
||||
|
||||
redraw = true;
|
||||
continue;
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
currentConfig = nullptr;
|
||||
currentCategory = nullptr;
|
||||
start = 0;
|
||||
selectedItem = 0;
|
||||
prevSelectedItem = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
if (configs.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = configs.size();
|
||||
}
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectedCat >= end) {
|
||||
end = selectedCat + 1;
|
||||
start = end - MAX_BUTTONS_ON_SCREEN;
|
||||
} else if (selectedCat < start) {
|
||||
start = selectedCat;
|
||||
end = start + MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (i == selectedCat) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16 * 2, index + 8 + 24, cats[i]->getName().c_str());
|
||||
index += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, StringTools::truncate(currentConfig->config->getName(), 45).c_str());
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, currentConfig->version.c_str(), true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < cats.size()) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue001 Back";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::vector<WUPSConfigItem *> config_items = currentCategory->getItems();
|
||||
if (config_items.empty()) {
|
||||
if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
currentCategory = nullptr;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
auto catSize = currentConfig->config->getCategories().size();
|
||||
if (catSize < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = catSize;
|
||||
}
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
uint32_t sz = DrawUtils::getTextWidth("This category has no items");
|
||||
|
||||
DrawUtils::print((SCREEN_WIDTH / 2) - (sz / 2), (SCREEN_HEIGHT / 2), "This category has no items");
|
||||
|
||||
|
||||
auto headline = string_format("%s - %s", currentConfig->config->getName().c_str(), currentCategory->getName().c_str());
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, StringTools::truncate(headline, 45).c_str());
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, currentConfig->version.c_str(), true);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue001 Back";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isItemMovementAllowed) {
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
if (selectedItem < config_items.size() - 1) {
|
||||
selectedItem++;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
if (selectedItem > 0) {
|
||||
selectedItem--;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
currentCategory = nullptr;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
auto catSize = currentConfig->config->getCategories().size();
|
||||
if (catSize < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = catSize;
|
||||
}
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
WUPSConfigButtons pressedButtons = WUPS_CONFIG_BUTTON_NONE;
|
||||
if (buttonsTriggered & VPAD_BUTTON_A) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_A;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_LEFT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_LEFT;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_RIGHT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_RIGHT;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_L) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_L;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_R) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_R;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_ZL) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZL;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_ZR) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZR;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_X) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_Y;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_Y) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_X;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_STICK_L) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_STICK_L;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_STICK_R) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_STICK_R;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_PLUS) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_PLUS;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_MINUS) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_MINUS;
|
||||
}
|
||||
|
||||
if (!isItemMovementAllowed) {
|
||||
if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_B;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_UP;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_UP;
|
||||
}
|
||||
}
|
||||
|
||||
if (pressedButtons != WUPS_CONFIG_BUTTON_NONE) {
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (selectedItem >= end) {
|
||||
end = selectedItem + 1;
|
||||
start = selectedItem - MAX_BUTTONS_ON_SCREEN;
|
||||
} else if (selectedItem < start) {
|
||||
start = selectedItem;
|
||||
end = start + MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
if (prevSelectedItem != (int32_t) selectedItem) {
|
||||
if (prevSelectedItem >= 0) {
|
||||
config_items[prevSelectedItem]->onSelected(false);
|
||||
}
|
||||
config_items[selectedItem]->onSelected(true);
|
||||
prevSelectedItem = (int32_t) selectedItem;
|
||||
}
|
||||
|
||||
if (pressedButtons != WUPS_CONFIG_BUTTON_NONE) {
|
||||
config_items[selectedItem]->onButtonPressed(pressedButtons);
|
||||
}
|
||||
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (i == selectedItem) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16 * 2, index + 8 + 24, config_items[i]->getDisplayName().c_str());
|
||||
if (i == selectedItem) {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, index + 8 + 24, config_items[i]->getCurrentValueSelectedDisplay().c_str(), true);
|
||||
} else {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, index + 8 + 24, config_items[i]->getCurrentValueDisplay().c_str(), true);
|
||||
}
|
||||
index += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
auto headline = string_format("%s - %s", currentConfig->config->getName().c_str(), currentCategory->getName().c_str());
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, StringTools::truncate(headline, 45).c_str());
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, currentConfig->version.c_str(), true);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 / \ue07e Toggle", true);
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < config_items.size()) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue001 Back";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
redraw = pressedButtons != WUPS_CONFIG_BUTTON_NONE;
|
||||
|
||||
isItemMovementAllowed = config_items[selectedItem]->isMovementAllowed();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &element : configs) {
|
||||
for (const auto &cat : element.config->getCategories()) {
|
||||
for (const auto &item : cat->getItems()) {
|
||||
if (item->isDirty()) {
|
||||
item->callCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_CONFIG_CLOSED);
|
||||
|
||||
for (const auto &element : configs) {
|
||||
delete element.config;
|
||||
}
|
||||
}
|
||||
|
||||
#define __SetDCPitchReg ((void (*)(uint32_t, uint32_t))(0x101C400 + 0x1e714))
|
||||
|
||||
void ConfigUtils::openConfigMenu() {
|
||||
bool wasHomeButtonMenuEnabled = OSIsHomeButtonMenuEnabled();
|
||||
|
||||
OSScreenInit();
|
||||
|
||||
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||
void *screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100);
|
||||
void *screenbuffer1 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf1_size, 0x100);
|
||||
|
||||
// Fix the TV buffer pitch if a 1080p buffer is used.
|
||||
if (screen_buf0_size == 0x00FD2000) {
|
||||
__SetDCPitchReg(SCREEN_TV, 1920);
|
||||
}
|
||||
|
||||
bool skipScreen0Free = false;
|
||||
bool skipScreen1Free = false;
|
||||
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
if (screenbuffer0 == nullptr) {
|
||||
if (gStoredTVBuffer.buffer_size >= screen_buf0_size) {
|
||||
screenbuffer0 = gStoredTVBuffer.buffer;
|
||||
skipScreen0Free = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedTVBuffer");
|
||||
}
|
||||
}
|
||||
if (screenbuffer1 == nullptr) {
|
||||
if (gStoredDRCBuffer.buffer_size >= screen_buf1_size) {
|
||||
screenbuffer1 = gStoredDRCBuffer.buffer;
|
||||
skipScreen1Free = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedDRCBuffer");
|
||||
}
|
||||
}
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffers");
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
OSScreenSetBufferEx(SCREEN_TV, screenbuffer0);
|
||||
OSScreenSetBufferEx(SCREEN_DRC, screenbuffer1);
|
||||
|
||||
OSScreenEnableEx(SCREEN_TV, 1);
|
||||
OSScreenEnableEx(SCREEN_DRC, 1);
|
||||
|
||||
// Clear screens
|
||||
OSScreenClearBufferEx(SCREEN_TV, 0);
|
||||
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
||||
|
||||
// Flip buffers
|
||||
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||
|
||||
DrawUtils::initBuffers(screenbuffer0, screen_buf0_size, screenbuffer1, screen_buf1_size);
|
||||
if (!DrawUtils::initFont()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init Font");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// disable the home button menu to prevent opening it when exiting
|
||||
OSEnableHomeButtonMenu(false);
|
||||
|
||||
displayMenu();
|
||||
|
||||
OSEnableHomeButtonMenu(wasHomeButtonMenuEnabled);
|
||||
|
||||
DrawUtils::deinitFont();
|
||||
|
||||
error_exit:
|
||||
|
||||
if (gStoredTVBuffer.buffer != nullptr) {
|
||||
GX2SetTVBuffer(gStoredTVBuffer.buffer, gStoredTVBuffer.buffer_size, static_cast<GX2TVRenderMode>(gStoredTVBuffer.mode),
|
||||
gStoredTVBuffer.surface_format, gStoredTVBuffer.buffering_mode);
|
||||
}
|
||||
|
||||
if (gStoredDRCBuffer.buffer != nullptr) {
|
||||
GX2SetDRCBuffer(gStoredDRCBuffer.buffer, gStoredDRCBuffer.buffer_size, static_cast<GX2DrcRenderMode>(gStoredDRCBuffer.mode),
|
||||
gStoredDRCBuffer.surface_format, gStoredDRCBuffer.buffering_mode);
|
||||
}
|
||||
if (!skipScreen0Free && screenbuffer0) {
|
||||
MEMFreeToMappedMemory(screenbuffer0);
|
||||
}
|
||||
|
||||
if (!skipScreen1Free && screenbuffer1) {
|
||||
MEMFreeToMappedMemory(screenbuffer1);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigUtils::renderBasicScreen(std::string_view text) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
uint32_t sz = DrawUtils::getTextWidth(text.data());
|
||||
|
||||
DrawUtils::print((SCREEN_WIDTH / 2) - (sz / 2), (SCREEN_HEIGHT / 2), text.data());
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gx2/enum.h>
|
||||
#include <string>
|
||||
|
||||
struct StoredBuffer {
|
||||
void *buffer;
|
||||
uint32_t buffer_size;
|
||||
uint32_t mode;
|
||||
GX2SurfaceFormat surface_format;
|
||||
GX2BufferingMode buffering_mode;
|
||||
};
|
||||
|
||||
class ConfigUtils {
|
||||
public:
|
||||
static void openConfigMenu();
|
||||
|
||||
private:
|
||||
static void displayMenu();
|
||||
static void renderBasicScreen(std::string_view text);
|
||||
};
|
||||
221
source/utils/config/CategoryRenderer.cpp
Normal file
221
source/utils/config/CategoryRenderer.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
#include "CategoryRenderer.h"
|
||||
#include "ConfigDefines.h"
|
||||
#include "config/WUPSConfigCategory.h"
|
||||
#include "utils/input/Input.h"
|
||||
#include "utils/utils.h"
|
||||
#include <vector>
|
||||
#include <wups/config.h>
|
||||
|
||||
CategoryRenderer::CategoryRenderer(const GeneralConfigInformation *info, const WUPSConfigAPIBackend::WUPSConfigCategory *cat, bool isRoot)
|
||||
: mInfo(info), mCat(cat), mIsRoot(isRoot) {
|
||||
for (uint32_t i = 0; i < cat->getCategories().size() + cat->getItems().size(); i++) {
|
||||
if (i < cat->getCategories().size()) {
|
||||
auto item = make_unique_nothrow<ConfigRendererItemCategory>(cat->getCategories()[i].get());
|
||||
if (!item) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc ConfigRendererItemCategory");
|
||||
OSFatal("WiiUPluginBackend::CategoryRenderer::CategoryRenderer() Failed to alloc ConfigRendererItemCategory");
|
||||
}
|
||||
mItemRenderer.push_back(std::move(item));
|
||||
} else {
|
||||
auto itemIndex = (int32_t) (i - cat->getCategories().size());
|
||||
if (itemIndex < 0 || itemIndex >= (int32_t) cat->getItems().size()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("unexpected index");
|
||||
OSFatal("WiiUPluginBackend::CategoryRenderer::CategoryRenderer() unexpected index");
|
||||
}
|
||||
auto item = make_unique_nothrow<ConfigRendererItem>(cat->getItems()[itemIndex].get());
|
||||
if (!item) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc ConfigRendererItemCategory");
|
||||
OSFatal("WiiUPluginBackend::CategoryRenderer::CategoryRenderer() Failed to alloc ConfigRendererItem");
|
||||
}
|
||||
mItemRenderer.push_back(std::move(item));
|
||||
}
|
||||
}
|
||||
|
||||
mCursorPos = 0;
|
||||
if (!mItemRenderer.empty()) {
|
||||
mItemRenderer[mCursorPos]->SetIsSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
CategoryRenderer::~CategoryRenderer() {
|
||||
if (mCursorPos < (int32_t) mItemRenderer.size()) {
|
||||
mItemRenderer[mCursorPos]->SetIsSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigSubState CategoryRenderer::Update(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData) {
|
||||
switch (mState) {
|
||||
case STATE_MAIN: {
|
||||
auto res = UpdateStateMain(input, simpleInputData, complexInputData);
|
||||
mFirstFrame = false;
|
||||
return res;
|
||||
}
|
||||
case STATE_SUB: {
|
||||
if (mSubCategoryRenderer) {
|
||||
auto subResult = mSubCategoryRenderer->Update(input, simpleInputData, complexInputData);
|
||||
if (subResult != SUB_STATE_RUNNING) {
|
||||
mState = STATE_MAIN;
|
||||
mFirstFrame = true;
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
return SUB_STATE_RUNNING;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("State is RENDERER_STATE_CAT but mCategoryRenderer is null. Resetting state.");
|
||||
mState = STATE_MAIN;
|
||||
mCursorPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SUB_STATE_ERROR;
|
||||
}
|
||||
|
||||
ConfigSubState CategoryRenderer::UpdateStateMain(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData) {
|
||||
if (mIsItemMovementAllowed && input.data.buttons_d & Input::eButtons::BUTTON_B) {
|
||||
return SUB_STATE_RETURN;
|
||||
}
|
||||
if (mItemRenderer.empty()) {
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
|
||||
auto totalElementSize = mItemRenderer.size();
|
||||
int32_t prevSelectedItem = mCursorPos;
|
||||
|
||||
if (mIsItemMovementAllowed) {
|
||||
if (input.data.buttons_d & Input::eButtons::BUTTON_DOWN) {
|
||||
mCursorPos++;
|
||||
} else if (input.data.buttons_d & Input::eButtons::BUTTON_UP) {
|
||||
mCursorPos--;
|
||||
} else if (input.data.buttons_d & Input::eButtons::BUTTON_A) {
|
||||
if (mCursorPos < (int32_t) mCat->getCategories().size()) {
|
||||
if (mCurrentOpen != mCursorPos) {
|
||||
mSubCategoryRenderer.reset();
|
||||
mSubCategoryRenderer = make_unique_nothrow<CategoryRenderer>(mInfo, mCat->getCategories()[mCursorPos].get(), false);
|
||||
}
|
||||
mCurrentOpen = mCursorPos;
|
||||
mState = STATE_SUB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mCursorPos < 0) {
|
||||
mCursorPos = (int32_t) totalElementSize - 1;
|
||||
} else if (mCursorPos > (int32_t) (totalElementSize - 1)) {
|
||||
mCursorPos = 0;
|
||||
}
|
||||
|
||||
// Adjust the render offset when reaching the boundaries
|
||||
if (mCursorPos < mRenderOffset) {
|
||||
mRenderOffset = mCursorPos;
|
||||
} else if (mCursorPos >= mRenderOffset + MAX_BUTTONS_ON_SCREEN - 1) {
|
||||
mRenderOffset = mCursorPos - MAX_BUTTONS_ON_SCREEN + 1;
|
||||
}
|
||||
|
||||
bool posJustChanged = false;
|
||||
if (prevSelectedItem != mCursorPos) {
|
||||
mItemRenderer[prevSelectedItem]->SetIsSelected(false);
|
||||
mItemRenderer[mCursorPos]->SetIsSelected(true);
|
||||
posJustChanged = true;
|
||||
}
|
||||
|
||||
if (!posJustChanged && !mFirstFrame) {
|
||||
// WUPSConfigItemV2
|
||||
mItemRenderer[mCursorPos]->OnInput(simpleInputData);
|
||||
mItemRenderer[mCursorPos]->OnInputEx(complexInputData);
|
||||
|
||||
// WUPSConfigItemV1
|
||||
if (input.data.buttons_d != 0) {
|
||||
WUPSConfigButtons buttons = input.data.buttons_d;
|
||||
buttons = ConfigUtils::convertInputs(buttons);
|
||||
if (!mIsItemMovementAllowed) {
|
||||
buttons &= ~MOVE_ITEM_INPUT_MASK;
|
||||
}
|
||||
mItemRenderer[mCursorPos]->OnButtonPressed(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
mIsItemMovementAllowed = mItemRenderer[mCursorPos]->IsMovementAllowed();
|
||||
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
|
||||
void CategoryRenderer::Render() const {
|
||||
switch (mState) {
|
||||
case STATE_MAIN:
|
||||
RenderStateMain();
|
||||
break;
|
||||
case STATE_SUB: {
|
||||
if (mSubCategoryRenderer) {
|
||||
mSubCategoryRenderer->Render();
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("STATE_SUB but mSubCategoryRenderer is NULL");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CategoryRenderer::RenderStateMain() const {
|
||||
if (mItemRenderer.empty()) {
|
||||
DrawUtils::beginDraw();
|
||||
RenderMainLayout();
|
||||
|
||||
std::string text(mIsRoot ? "This plugin can not be configured" : "This category is empty");
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
uint32_t sz = DrawUtils::getTextWidth(text.c_str());
|
||||
DrawUtils::print((SCREEN_WIDTH / 2) - (sz / 2), (SCREEN_HEIGHT / 2), text.c_str());
|
||||
|
||||
DrawUtils::endDraw();
|
||||
return;
|
||||
}
|
||||
auto totalElementSize = static_cast<int>(mItemRenderer.size());
|
||||
|
||||
// Calculate the range of items to display
|
||||
int start = std::max(0, mRenderOffset);
|
||||
int end = std::min(start + MAX_BUTTONS_ON_SCREEN, totalElementSize);
|
||||
|
||||
DrawUtils::beginDraw();
|
||||
|
||||
RenderMainLayout();
|
||||
|
||||
uint32_t yOffset = 8 + 24 + 8 + 4;
|
||||
for (int32_t i = start; i < end; i++) {
|
||||
bool isHighlighted = (i == mCursorPos);
|
||||
mItemRenderer[i]->Draw(yOffset, isHighlighted);
|
||||
yOffset += 42 + 8;
|
||||
}
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < totalElementSize) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
||||
|
||||
void CategoryRenderer::RenderMainLayout() const {
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, StringTools::truncate(mInfo->name, 45).c_str());
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, mInfo->version.c_str(), true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue001 Back";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
}
|
||||
46
source/utils/config/CategoryRenderer.h
Normal file
46
source/utils/config/CategoryRenderer.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include "../DrawUtils.h"
|
||||
#include "ConfigRendererItem.h"
|
||||
#include "ConfigRendererItemCategory.h"
|
||||
#include "ConfigRendererItemGeneric.h"
|
||||
#include "ConfigUtils.h"
|
||||
#include "config/WUPSConfigCategory.h"
|
||||
#include "utils/input/Input.h"
|
||||
#include <memory>
|
||||
|
||||
class CategoryRenderer {
|
||||
|
||||
public:
|
||||
explicit CategoryRenderer(const GeneralConfigInformation *info, const WUPSConfigAPIBackend::WUPSConfigCategory *cat, bool isRoot);
|
||||
|
||||
~CategoryRenderer();
|
||||
|
||||
ConfigSubState Update(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData);
|
||||
|
||||
void Render() const;
|
||||
|
||||
private:
|
||||
ConfigSubState UpdateStateMain(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData);
|
||||
|
||||
void RenderStateMain() const;
|
||||
|
||||
void RenderMainLayout() const;
|
||||
|
||||
enum State {
|
||||
STATE_MAIN = 0,
|
||||
STATE_SUB = 1,
|
||||
};
|
||||
|
||||
State mState = STATE_MAIN;
|
||||
int32_t mCurrentOpen = -1;
|
||||
int32_t mCursorPos = 0;
|
||||
int32_t mRenderOffset = 0;
|
||||
std::unique_ptr<CategoryRenderer> mSubCategoryRenderer = {};
|
||||
const GeneralConfigInformation *mInfo = {};
|
||||
const WUPSConfigAPIBackend::WUPSConfigCategory *mCat = {};
|
||||
|
||||
std::vector<std::unique_ptr<ConfigRendererItemGeneric>> mItemRenderer = {};
|
||||
bool mIsItemMovementAllowed = true;
|
||||
bool mFirstFrame = true;
|
||||
bool mIsRoot = false;
|
||||
};
|
||||
31
source/utils/config/ConfigDefines.h
Normal file
31
source/utils/config/ConfigDefines.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <gx2/surface.h>
|
||||
#include <string>
|
||||
|
||||
#define COLOR_BACKGROUND Color(238, 238, 238, 255)
|
||||
#define COLOR_TEXT Color(51, 51, 51, 255)
|
||||
#define COLOR_TEXT2 Color(72, 72, 72, 255)
|
||||
#define COLOR_DISABLED Color(255, 0, 0, 255)
|
||||
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4FF)
|
||||
#define COLOR_WHITE Color(0xFFFFFFFF)
|
||||
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||
|
||||
#define MAX_BUTTONS_ON_SCREEN 8
|
||||
|
||||
struct StoredBuffer {
|
||||
void *buffer;
|
||||
uint32_t buffer_size;
|
||||
uint32_t mode;
|
||||
GX2SurfaceFormat surface_format;
|
||||
GX2BufferingMode buffering_mode;
|
||||
};
|
||||
|
||||
|
||||
enum ConfigSubState {
|
||||
SUB_STATE_RUNNING = 0,
|
||||
SUB_STATE_RETURN = 1,
|
||||
SUB_STATE_ERROR = 2,
|
||||
};
|
||||
26
source/utils/config/ConfigDisplayItem.h
Normal file
26
source/utils/config/ConfigDisplayItem.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "config/WUPSConfig.h"
|
||||
#include <memory>
|
||||
|
||||
struct GeneralConfigInformation {
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::string version;
|
||||
};
|
||||
|
||||
class ConfigDisplayItem {
|
||||
public:
|
||||
ConfigDisplayItem(GeneralConfigInformation &info, std::unique_ptr<WUPSConfigAPIBackend::WUPSConfig> config) : mConfig(std::move(config)), mInfo(std::move(info)) {
|
||||
assert(mConfig);
|
||||
}
|
||||
[[nodiscard]] const GeneralConfigInformation &getConfigInformation() const {
|
||||
return mInfo;
|
||||
}
|
||||
[[nodiscard]] const WUPSConfigAPIBackend::WUPSConfig &getConfig() const {
|
||||
return *mConfig;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<WUPSConfigAPIBackend::WUPSConfig> mConfig;
|
||||
GeneralConfigInformation mInfo;
|
||||
};
|
||||
154
source/utils/config/ConfigRenderer.cpp
Normal file
154
source/utils/config/ConfigRenderer.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "ConfigRenderer.h"
|
||||
|
||||
void ConfigRenderer::RenderStateMain() const {
|
||||
auto totalElementSize = (int32_t) mConfigs.size();
|
||||
// Calculate the range of items to display
|
||||
int start = std::max(0, mRenderOffset);
|
||||
int end = std::min(start + MAX_BUTTONS_ON_SCREEN, totalElementSize);
|
||||
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
uint32_t yOffset = 8 + 24 + 8 + 4;
|
||||
for (int32_t i = start; i < end; i++) {
|
||||
drawConfigEntry(yOffset, mConfigs[i].getConfigInformation(), i == mCursorPos);
|
||||
yOffset += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < totalElementSize) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
||||
|
||||
void ConfigRenderer::drawConfigEntry(uint32_t yOffset, const GeneralConfigInformation &configInformation, bool isHighlighted) const {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (isHighlighted) {
|
||||
DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16 * 2, yOffset + 8 + 24, configInformation.name.c_str());
|
||||
uint32_t sz = DrawUtils::getTextWidth(configInformation.name.c_str());
|
||||
DrawUtils::setFontSize(12);
|
||||
DrawUtils::print(16 * 2 + sz + 4, yOffset + 8 + 24, configInformation.author.c_str());
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, yOffset + 8 + 24, configInformation.version.c_str(), true);
|
||||
}
|
||||
|
||||
ConfigSubState ConfigRenderer::UpdateStateMain(const Input &input) {
|
||||
if (mConfigs.empty()) {
|
||||
return SUB_STATE_ERROR;
|
||||
}
|
||||
auto totalElementSize = mConfigs.size();
|
||||
if (input.data.buttons_d & Input::eButtons::BUTTON_DOWN) {
|
||||
mCursorPos++;
|
||||
} else if (input.data.buttons_d & Input::eButtons::BUTTON_UP) {
|
||||
mCursorPos--;
|
||||
} else if (input.data.buttons_d & Input::eButtons::BUTTON_A) {
|
||||
if (mCursorPos != mCurrentOpen) {
|
||||
mCategoryRenderer.reset();
|
||||
mCategoryRenderer = make_unique_nothrow<CategoryRenderer>(&(mConfigs[mCursorPos].getConfigInformation()), &(mConfigs[mCursorPos].getConfig()), true);
|
||||
}
|
||||
mCurrentOpen = mCursorPos;
|
||||
mState = STATE_SUB;
|
||||
return SUB_STATE_RUNNING;
|
||||
} else if (input.data.buttons_d & (Input::eButtons::BUTTON_B | Input::eButtons::BUTTON_HOME)) {
|
||||
mCategoryRenderer.reset();
|
||||
for (const auto &element : mConfigs) {
|
||||
CallOnCloseCallback(element.getConfigInformation(), element.getConfig().getCategories());
|
||||
}
|
||||
return SUB_STATE_RETURN;
|
||||
}
|
||||
|
||||
if (mCursorPos < 0) {
|
||||
mCursorPos = (int32_t) totalElementSize - 1;
|
||||
} else if (mCursorPos > (int32_t) (totalElementSize - 1)) {
|
||||
mCursorPos = 0;
|
||||
}
|
||||
|
||||
// Adjust the render offset when reaching the boundaries
|
||||
if (mCursorPos < mRenderOffset) {
|
||||
mRenderOffset = mCursorPos;
|
||||
} else if (mCursorPos >= mRenderOffset + MAX_BUTTONS_ON_SCREEN - 1) {
|
||||
mRenderOffset = mCursorPos - MAX_BUTTONS_ON_SCREEN + 1;
|
||||
}
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
|
||||
void ConfigRenderer::Render() const {
|
||||
switch (mState) {
|
||||
case STATE_MAIN:
|
||||
RenderStateMain();
|
||||
break;
|
||||
case STATE_SUB: {
|
||||
if (mCategoryRenderer) {
|
||||
mCategoryRenderer->Render();
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("render failed: state was RENDERER_STATE_CAT but mCategoryRenderer is NULL");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigSubState ConfigRenderer::Update(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData) {
|
||||
switch (mState) {
|
||||
case STATE_MAIN:
|
||||
return UpdateStateMain(input);
|
||||
case STATE_SUB: {
|
||||
if (mCategoryRenderer) {
|
||||
auto subResult = mCategoryRenderer->Update(input, simpleInputData, complexInputData);
|
||||
if (subResult != SUB_STATE_RUNNING) {
|
||||
mState = STATE_MAIN;
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
return SUB_STATE_RUNNING;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("State is RENDERER_STATE_CAT but mCategoryRenderer is null. Resetting state.");
|
||||
mState = STATE_MAIN;
|
||||
mCursorPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SUB_STATE_ERROR;
|
||||
}
|
||||
|
||||
void ConfigRenderer::CallOnCloseCallback(const GeneralConfigInformation &info, const std::vector<std::unique_ptr<WUPSConfigAPIBackend::WUPSConfigCategory>> &categories) {
|
||||
for (const auto &cat : categories) {
|
||||
if (!cat->getCategories().empty()) {
|
||||
CallOnCloseCallback(info, cat->getCategories());
|
||||
}
|
||||
for (const auto &item : cat->getItems()) {
|
||||
item->onCloseCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
source/utils/config/ConfigRenderer.h
Normal file
42
source/utils/config/ConfigRenderer.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include "../DrawUtils.h"
|
||||
#include "../input/Input.h"
|
||||
#include "../logger.h"
|
||||
#include "CategoryRenderer.h"
|
||||
#include "globals.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class ConfigRenderer {
|
||||
|
||||
public:
|
||||
explicit ConfigRenderer(std::vector<ConfigDisplayItem> &&vec) : mConfigs(std::move(vec)) {
|
||||
}
|
||||
~ConfigRenderer() = default;
|
||||
|
||||
ConfigSubState Update(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData);
|
||||
|
||||
void Render() const;
|
||||
|
||||
private:
|
||||
ConfigSubState UpdateStateMain(const Input &input);
|
||||
|
||||
void RenderStateMain() const;
|
||||
|
||||
void drawConfigEntry(uint32_t yOffset, const GeneralConfigInformation &configInformation, bool isHighlighted) const;
|
||||
|
||||
enum State {
|
||||
STATE_MAIN = 0,
|
||||
STATE_SUB = 1,
|
||||
};
|
||||
|
||||
std::vector<ConfigDisplayItem> mConfigs;
|
||||
std::unique_ptr<CategoryRenderer> mCategoryRenderer = {};
|
||||
|
||||
State mState = STATE_MAIN;
|
||||
|
||||
int32_t mCursorPos = 0;
|
||||
int32_t mRenderOffset = 0;
|
||||
int32_t mCurrentOpen = -1;
|
||||
void CallOnCloseCallback(const GeneralConfigInformation &info, const std::vector<std::unique_ptr<WUPSConfigAPIBackend::WUPSConfigCategory>> &categories);
|
||||
};
|
||||
43
source/utils/config/ConfigRendererItem.h
Normal file
43
source/utils/config/ConfigRendererItem.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "ConfigRendererItemGeneric.h"
|
||||
#include "config/WUPSConfigItem.h"
|
||||
|
||||
class ConfigRendererItem : public ConfigRendererItemGeneric {
|
||||
public:
|
||||
explicit ConfigRendererItem(const WUPSConfigAPIBackend::WUPSConfigItem *item) : mItem(item) {
|
||||
assert(item);
|
||||
}
|
||||
|
||||
void Draw(uint32_t yOffset, bool isHighlighted) const override {
|
||||
assert(mItem);
|
||||
drawGenericBoxAndText(yOffset, mItem->getDisplayName(), isHighlighted);
|
||||
DrawUtils::setFontSize(24);
|
||||
if (isHighlighted) {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, yOffset + 8 + 24, mItem->getCurrentValueSelectedDisplay().c_str(), true);
|
||||
} else {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, yOffset + 8 + 24, mItem->getCurrentValueDisplay().c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void SetIsSelected(bool isSelected) override {
|
||||
mItem->onSelected(isSelected);
|
||||
}
|
||||
|
||||
void OnButtonPressed(WUPSConfigButtons buttons) override {
|
||||
mItem->onButtonPressed(buttons);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsMovementAllowed() const override {
|
||||
return mItem->isMovementAllowed();
|
||||
}
|
||||
|
||||
void OnInput(WUPSConfigSimplePadData input) override {
|
||||
mItem->onInput(input);
|
||||
}
|
||||
void OnInputEx(WUPSConfigComplexPadData input) override {
|
||||
mItem->onInputEx(input);
|
||||
}
|
||||
|
||||
private:
|
||||
const WUPSConfigAPIBackend::WUPSConfigItem *mItem;
|
||||
};
|
||||
17
source/utils/config/ConfigRendererItemCategory.h
Normal file
17
source/utils/config/ConfigRendererItemCategory.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "ConfigRendererItemGeneric.h"
|
||||
#include "config/WUPSConfigCategory.h"
|
||||
|
||||
class ConfigRendererItemCategory : public ConfigRendererItemGeneric {
|
||||
public:
|
||||
explicit ConfigRendererItemCategory(const WUPSConfigAPIBackend::WUPSConfigCategory *category) : mCategory(category) {
|
||||
assert(category);
|
||||
}
|
||||
|
||||
void Draw(uint32_t yOffset, bool isHighlighted) const override {
|
||||
drawGenericBoxAndText(yOffset, mCategory->getName(), isHighlighted);
|
||||
}
|
||||
|
||||
private:
|
||||
const WUPSConfigAPIBackend::WUPSConfigCategory *mCategory;
|
||||
};
|
||||
36
source/utils/config/ConfigRendererItemGeneric.h
Normal file
36
source/utils/config/ConfigRendererItemGeneric.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "../DrawUtils.h"
|
||||
#include "ConfigDefines.h"
|
||||
#include <wups/config.h>
|
||||
|
||||
class ConfigRendererItemGeneric {
|
||||
public:
|
||||
virtual ~ConfigRendererItemGeneric() = default;
|
||||
virtual void drawGenericBoxAndText(uint32_t yOffset, const std::string &displayName, bool isHighlighted) const {
|
||||
if (isHighlighted) {
|
||||
DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
DrawUtils::print(16 * 2, yOffset + 8 + 24, displayName.c_str());
|
||||
}
|
||||
|
||||
virtual void Draw(uint32_t yOffset, bool isHighlighted) const = 0;
|
||||
|
||||
virtual void SetIsSelected(bool) {
|
||||
}
|
||||
|
||||
virtual void OnButtonPressed(WUPSConfigButtons) {
|
||||
}
|
||||
virtual void OnInput(WUPSConfigSimplePadData) {
|
||||
}
|
||||
virtual void OnInputEx(WUPSConfigComplexPadData) {
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool IsMovementAllowed() const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
308
source/utils/config/ConfigUtils.cpp
Normal file
308
source/utils/config/ConfigUtils.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
#include "ConfigUtils.h"
|
||||
#include "../../globals.h"
|
||||
#include "../DrawUtils.h"
|
||||
#include "../logger.h"
|
||||
#include "ConfigRenderer.h"
|
||||
#include "config/WUPSConfigAPI.h"
|
||||
#include "hooks.h"
|
||||
#include "utils/input/CombinedInput.h"
|
||||
#include "utils/input/VPADInput.h"
|
||||
#include "utils/input/WPADInput.h"
|
||||
|
||||
#include <coreinit/screen.h>
|
||||
#include <gx2/display.h>
|
||||
#include <memory/mappedmemory.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
WUPS_CONFIG_SIMPLE_INPUT ConfigUtils::convertInputs(uint32_t buttons) {
|
||||
WUPSConfigButtons pressedButtons = WUPS_CONFIG_BUTTON_NONE;
|
||||
if (buttons & Input::eButtons::BUTTON_A) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_A;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_LEFT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_LEFT;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_RIGHT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_RIGHT;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_L) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_L;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_R) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_R;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_ZL) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZL;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_ZR) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZR;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_X) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_X;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_Y) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_Y;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_STICK_L) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_STICK_L;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_STICK_R) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_STICK_R;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_PLUS) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_PLUS;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_MINUS) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_MINUS;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_B) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_B;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_UP) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_UP;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_DOWN) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_DOWN;
|
||||
}
|
||||
return (WUPS_CONFIG_SIMPLE_INPUT) pressedButtons;
|
||||
}
|
||||
|
||||
void ConfigUtils::displayMenu() {
|
||||
renderBasicScreen("Loading configs...");
|
||||
|
||||
std::vector<ConfigDisplayItem> configs;
|
||||
for (auto &plugin : gLoadedPlugins) {
|
||||
GeneralConfigInformation info;
|
||||
info.name = plugin->getMetaInformation().getName();
|
||||
info.author = plugin->getMetaInformation().getAuthor();
|
||||
info.version = plugin->getMetaInformation().getVersion();
|
||||
|
||||
std::unique_ptr<WUPSConfigAPIBackend::WUPSConfig> config;
|
||||
auto configData = plugin->getConfigData();
|
||||
if (configData) {
|
||||
auto configHandleOpt = configData->createConfig();
|
||||
if (configHandleOpt) {
|
||||
WUPSConfigAPIStatus callbackResult = configData->CallMenuOpenendCallback(configHandleOpt.value());
|
||||
config = WUPSConfigAPIBackend::Intern::PopConfigByHandle(configHandleOpt.value());
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get config for handle: %08X", configHandleOpt.value().handle);
|
||||
} else if (callbackResult != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Callback failed for %s: %s", info.name.c_str(), WUPSConfigAPI_GetStatusStr(callbackResult));
|
||||
config.reset();
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create config for plugin: \"%s\"", info.name.c_str());
|
||||
}
|
||||
} else {
|
||||
for (const auto &hook : plugin->getPluginInformation().getHookDataList()) {
|
||||
if (hook->getType() == WUPS_LOADER_HOOK_GET_CONFIG_DEPRECATED) {
|
||||
if (hook->getFunctionPointer() == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Hook had invalid ptr");
|
||||
break;
|
||||
}
|
||||
auto cur_config_handle = ((void *(*) ())((uint32_t *) hook->getFunctionPointer()))();
|
||||
if (cur_config_handle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Hook returned empty handle");
|
||||
break;
|
||||
}
|
||||
config = WUPSConfigAPIBackend::Intern::PopConfigByHandle(WUPSConfigHandle(cur_config_handle));
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find config for handle: %08X", cur_config_handle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!config) {
|
||||
config = make_unique_nothrow<WUPSConfigAPIBackend::WUPSConfig>("DUMMY");
|
||||
}
|
||||
|
||||
configs.emplace_back(info, std::move(config));
|
||||
}
|
||||
|
||||
ConfigRenderer renderer(std::move(configs));
|
||||
configs.clear();
|
||||
|
||||
CombinedInput baseInput;
|
||||
VPadInput vpadInput;
|
||||
WPADInput wpadInputs[4] = {
|
||||
WPAD_CHAN_0,
|
||||
WPAD_CHAN_1,
|
||||
WPAD_CHAN_2,
|
||||
WPAD_CHAN_3};
|
||||
|
||||
auto startTime = OSGetTime();
|
||||
while (true) {
|
||||
baseInput.reset();
|
||||
if (vpadInput.update(1280, 720)) {
|
||||
baseInput.combine(vpadInput);
|
||||
}
|
||||
for (auto &wpadInput : wpadInputs) {
|
||||
if (wpadInput.update(1280, 720)) {
|
||||
baseInput.combine(wpadInput);
|
||||
}
|
||||
}
|
||||
baseInput.process();
|
||||
|
||||
WUPSConfigSimplePadData simpleData;
|
||||
simpleData.buttons_d = convertInputs(baseInput.data.buttons_d);
|
||||
simpleData.buttons_r = convertInputs(baseInput.data.buttons_r);
|
||||
simpleData.buttons_h = convertInputs(baseInput.data.buttons_h);
|
||||
simpleData.x = baseInput.data.x;
|
||||
simpleData.y = baseInput.data.y;
|
||||
simpleData.touched = baseInput.data.touched;
|
||||
simpleData.validPointer = baseInput.data.validPointer;
|
||||
|
||||
WUPSConfigComplexPadData complexData;
|
||||
complexData.vpad.data = vpadInput.vpad;
|
||||
complexData.vpad.tpCalib = vpadInput.tpCalib;
|
||||
complexData.vpad.vpadError = vpadInput.vpadError;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
complexData.kpad.kpadError[i] = wpadInputs[i].kpadError;
|
||||
complexData.kpad.data[i] = wpadInputs[i].kpad;
|
||||
}
|
||||
|
||||
auto subState = renderer.Update(baseInput, simpleData, complexData);
|
||||
if (subState != SUB_STATE_RUNNING) {
|
||||
break;
|
||||
}
|
||||
renderer.Render();
|
||||
auto diffTime = OSTicksToMicroseconds(OSGetTime() - startTime);
|
||||
if (diffTime < 16000) {
|
||||
OSSleepTicks(OSMicrosecondsToTicks(16000 - diffTime));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &plugin : gLoadedPlugins) {
|
||||
auto configData = plugin->getConfigData();
|
||||
if (configData) {
|
||||
configData->CallMenuClosedCallback();
|
||||
} else {
|
||||
CallHook(*plugin, WUPS_LOADER_HOOK_CONFIG_CLOSED_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
WUPSConfigAPIBackend::Intern::CleanAllHandles();
|
||||
}
|
||||
|
||||
#define __SetDCPitchReg ((void (*)(uint32_t, uint32_t))(0x101C400 + 0x1e714))
|
||||
|
||||
void ConfigUtils::openConfigMenu() {
|
||||
bool wasHomeButtonMenuEnabled = OSIsHomeButtonMenuEnabled();
|
||||
|
||||
OSScreenInit();
|
||||
|
||||
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||
void *screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100);
|
||||
void *screenbuffer1 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf1_size, 0x100);
|
||||
|
||||
// Fix the TV buffer pitch if a 1080p buffer is used.
|
||||
if (screen_buf0_size == 0x00FD2000) {
|
||||
__SetDCPitchReg(SCREEN_TV, 1920);
|
||||
}
|
||||
|
||||
bool skipScreen0Free = false;
|
||||
bool skipScreen1Free = false;
|
||||
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
if (screenbuffer0 == nullptr) {
|
||||
if (gStoredTVBuffer.buffer_size >= screen_buf0_size) {
|
||||
screenbuffer0 = gStoredTVBuffer.buffer;
|
||||
skipScreen0Free = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedTVBuffer");
|
||||
}
|
||||
}
|
||||
if (screenbuffer1 == nullptr) {
|
||||
if (gStoredDRCBuffer.buffer_size >= screen_buf1_size) {
|
||||
screenbuffer1 = gStoredDRCBuffer.buffer;
|
||||
skipScreen1Free = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedDRCBuffer");
|
||||
}
|
||||
}
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffers");
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
OSScreenSetBufferEx(SCREEN_TV, screenbuffer0);
|
||||
OSScreenSetBufferEx(SCREEN_DRC, screenbuffer1);
|
||||
|
||||
OSScreenEnableEx(SCREEN_TV, 1);
|
||||
OSScreenEnableEx(SCREEN_DRC, 1);
|
||||
|
||||
// Clear screens
|
||||
OSScreenClearBufferEx(SCREEN_TV, 0);
|
||||
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
||||
|
||||
// Flip buffers
|
||||
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||
|
||||
DrawUtils::initBuffers(screenbuffer0, screen_buf0_size, screenbuffer1, screen_buf1_size);
|
||||
if (!DrawUtils::initFont()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init Font");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// disable the home button menu to prevent opening it when exiting
|
||||
OSEnableHomeButtonMenu(false);
|
||||
|
||||
displayMenu();
|
||||
|
||||
OSEnableHomeButtonMenu(wasHomeButtonMenuEnabled);
|
||||
|
||||
DrawUtils::deinitFont();
|
||||
|
||||
error_exit:
|
||||
|
||||
if (gStoredTVBuffer.buffer != nullptr) {
|
||||
GX2SetTVBuffer(gStoredTVBuffer.buffer, gStoredTVBuffer.buffer_size, static_cast<GX2TVRenderMode>(gStoredTVBuffer.mode),
|
||||
gStoredTVBuffer.surface_format, gStoredTVBuffer.buffering_mode);
|
||||
}
|
||||
|
||||
if (gStoredDRCBuffer.buffer != nullptr) {
|
||||
GX2SetDRCBuffer(gStoredDRCBuffer.buffer, gStoredDRCBuffer.buffer_size, static_cast<GX2DrcRenderMode>(gStoredDRCBuffer.mode),
|
||||
gStoredDRCBuffer.surface_format, gStoredDRCBuffer.buffering_mode);
|
||||
}
|
||||
if (!skipScreen0Free && screenbuffer0) {
|
||||
MEMFreeToMappedMemory(screenbuffer0);
|
||||
}
|
||||
|
||||
if (!skipScreen1Free && screenbuffer1) {
|
||||
MEMFreeToMappedMemory(screenbuffer1);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigUtils::renderBasicScreen(std::string_view text) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
uint32_t sz = DrawUtils::getTextWidth(text.data());
|
||||
|
||||
DrawUtils::print((SCREEN_WIDTH / 2) - (sz / 2), (SCREEN_HEIGHT / 2), text.data());
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
||||
23
source/utils/config/ConfigUtils.h
Normal file
23
source/utils/config/ConfigUtils.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "ConfigDefines.h"
|
||||
#include "ConfigDisplayItem.h"
|
||||
#include "config/WUPSConfig.h"
|
||||
|
||||
#include "utils/input/Input.h"
|
||||
#include <gx2/enum.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#define MOVE_ITEM_INPUT_MASK (WUPS_CONFIG_BUTTON_B | WUPS_CONFIG_BUTTON_DOWN | WUPS_CONFIG_BUTTON_UP)
|
||||
|
||||
class ConfigUtils {
|
||||
public:
|
||||
static void openConfigMenu();
|
||||
|
||||
static WUPS_CONFIG_SIMPLE_INPUT convertInputs(uint32_t buttons);
|
||||
|
||||
private:
|
||||
static void displayMenu();
|
||||
static void renderBasicScreen(std::string_view text);
|
||||
};
|
||||
27
source/utils/input/CombinedInput.h
Normal file
27
source/utils/input/CombinedInput.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "Input.h"
|
||||
class CombinedInput : public Input {
|
||||
public:
|
||||
void combine(const Input &b) {
|
||||
data.buttons_h |= b.data.buttons_h;
|
||||
if (!data.touched) {
|
||||
data.touched = b.data.touched;
|
||||
}
|
||||
if (!data.validPointer) {
|
||||
data.validPointer = b.data.validPointer;
|
||||
data.pointerAngle = b.data.pointerAngle;
|
||||
data.x = b.data.x;
|
||||
data.y = b.data.y;
|
||||
}
|
||||
}
|
||||
|
||||
void process() {
|
||||
data.buttons_d |= (data.buttons_h & (~lastData.buttons_h));
|
||||
data.buttons_r |= (lastData.buttons_h & (~data.buttons_h));
|
||||
lastData.buttons_h = data.buttons_h;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
data = {};
|
||||
}
|
||||
};
|
||||
62
source/utils/input/Input.h
Normal file
62
source/utils/input/Input.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
class Input {
|
||||
public:
|
||||
//!Constructor
|
||||
Input() = default;
|
||||
|
||||
//!Destructor
|
||||
virtual ~Input() = default;
|
||||
|
||||
enum eButtons {
|
||||
BUTTON_NONE = 0x0000,
|
||||
VPAD_TOUCH = 0x80000000,
|
||||
BUTTON_STICK_L = 0x80000,
|
||||
BUTTON_STICK_R = 0x40000,
|
||||
BUTTON_Z = 0x20000,
|
||||
BUTTON_C = 0x10000,
|
||||
BUTTON_A = 0x8000,
|
||||
BUTTON_B = 0x4000,
|
||||
BUTTON_X = 0x2000,
|
||||
BUTTON_Y = 0x1000,
|
||||
BUTTON_1 = BUTTON_Y,
|
||||
BUTTON_2 = BUTTON_X,
|
||||
BUTTON_LEFT = 0x0800,
|
||||
BUTTON_RIGHT = 0x0400,
|
||||
BUTTON_UP = 0x0200,
|
||||
BUTTON_DOWN = 0x0100,
|
||||
BUTTON_ZL = 0x0080,
|
||||
BUTTON_ZR = 0x0040,
|
||||
BUTTON_L = 0x0020,
|
||||
BUTTON_R = 0x0010,
|
||||
BUTTON_PLUS = 0x0008,
|
||||
BUTTON_MINUS = 0x0004,
|
||||
BUTTON_HOME = 0x0002,
|
||||
BUTTON_SYNC = 0x0001,
|
||||
STICK_R_LEFT = 0x04000000,
|
||||
STICK_R_RIGHT = 0x02000000,
|
||||
STICK_R_UP = 0x01000000,
|
||||
STICK_R_DOWN = 0x00800000,
|
||||
STICK_L_LEFT = 0x40000000,
|
||||
STICK_L_RIGHT = 0x20000000,
|
||||
STICK_L_UP = 0x10000000,
|
||||
STICK_L_DOWN = 0x08000000
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t buttons_h;
|
||||
uint32_t buttons_d;
|
||||
uint32_t buttons_r;
|
||||
bool validPointer;
|
||||
bool touched;
|
||||
float pointerAngle;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} PadData;
|
||||
|
||||
PadData data{};
|
||||
PadData lastData{};
|
||||
};
|
||||
57
source/utils/input/VPADInput.h
Normal file
57
source/utils/input/VPADInput.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#include "Input.h"
|
||||
#include <vpad/input.h>
|
||||
|
||||
class VPadInput : public Input {
|
||||
public:
|
||||
//!Constructor
|
||||
VPadInput() = default;
|
||||
|
||||
//!Destructor
|
||||
~VPadInput() override = default;
|
||||
|
||||
bool update(int32_t width, int32_t height) {
|
||||
lastData = data;
|
||||
|
||||
data = {};
|
||||
vpadError = VPAD_READ_NO_SAMPLES;
|
||||
|
||||
if (VPADRead(VPAD_CHAN_0, &vpad, 1, &vpadError) > 0 && vpadError == VPAD_READ_SUCCESS) {
|
||||
data.buttons_r = vpad.release;
|
||||
data.buttons_h = vpad.hold;
|
||||
data.buttons_d = vpad.trigger;
|
||||
data.validPointer = !vpad.tpNormal.validity;
|
||||
data.touched = vpad.tpNormal.touched;
|
||||
|
||||
VPADGetTPCalibratedPoint(VPAD_CHAN_0, &tpCalib, &vpad.tpFiltered1);
|
||||
|
||||
//! calculate the screen offsets
|
||||
data.x = -(width >> 1) + (int32_t) (((float) tpCalib.x / 1280.0f) * (float) width);
|
||||
data.y = -(height >> 1) + (int32_t) (float) height - (((float) tpCalib.y / 720.0f) * (float) height);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VPADStatus vpad = {};
|
||||
VPADReadError vpadError = {};
|
||||
VPADTouchData tpCalib = {};
|
||||
};
|
||||
187
source/utils/input/WPADInput.h
Normal file
187
source/utils/input/WPADInput.h
Normal file
@@ -0,0 +1,187 @@
|
||||
#pragma once
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#include "Input.h"
|
||||
#include <padscore/kpad.h>
|
||||
#include <padscore/wpad.h>
|
||||
|
||||
class WPADInput : public Input {
|
||||
public:
|
||||
WPADInput(KPADChan channel) {
|
||||
this->channel = channel;
|
||||
}
|
||||
|
||||
~WPADInput() override {}
|
||||
|
||||
uint32_t remapWiiMoteButtons(uint32_t buttons) {
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if (buttons & WPAD_BUTTON_LEFT)
|
||||
conv_buttons |= Input::BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_RIGHT)
|
||||
conv_buttons |= Input::BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_DOWN)
|
||||
conv_buttons |= Input::BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_BUTTON_UP)
|
||||
conv_buttons |= Input::BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_BUTTON_PLUS)
|
||||
conv_buttons |= Input::BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_2)
|
||||
conv_buttons |= Input::BUTTON_2;
|
||||
|
||||
if (buttons & WPAD_BUTTON_1)
|
||||
conv_buttons |= Input::BUTTON_1;
|
||||
|
||||
if (buttons & WPAD_BUTTON_B)
|
||||
conv_buttons |= Input::BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_BUTTON_A)
|
||||
conv_buttons |= Input::BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_BUTTON_MINUS)
|
||||
conv_buttons |= Input::BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_Z)
|
||||
conv_buttons |= Input::BUTTON_Z;
|
||||
|
||||
if (buttons & WPAD_BUTTON_C)
|
||||
conv_buttons |= Input::BUTTON_C;
|
||||
|
||||
if (buttons & WPAD_BUTTON_HOME)
|
||||
conv_buttons |= Input::BUTTON_HOME;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
uint32_t remapClassicButtons(uint32_t buttons) {
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_LEFT)
|
||||
conv_buttons |= Input::BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
conv_buttons |= Input::BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_DOWN)
|
||||
conv_buttons |= Input::BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_UP)
|
||||
conv_buttons |= Input::BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_PLUS)
|
||||
conv_buttons |= Input::BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_X)
|
||||
conv_buttons |= Input::BUTTON_X;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_Y)
|
||||
conv_buttons |= Input::BUTTON_Y;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_B)
|
||||
conv_buttons |= Input::BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_A)
|
||||
conv_buttons |= Input::BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_MINUS)
|
||||
conv_buttons |= Input::BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_HOME)
|
||||
conv_buttons |= Input::BUTTON_HOME;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZR)
|
||||
conv_buttons |= Input::BUTTON_ZR;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZL)
|
||||
conv_buttons |= Input::BUTTON_ZL;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_R)
|
||||
conv_buttons |= Input::BUTTON_R;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_L)
|
||||
conv_buttons |= Input::BUTTON_L;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
bool update(int32_t width, int32_t height) {
|
||||
lastData = data;
|
||||
|
||||
kpadError = KPAD_ERROR_UNINITIALIZED;
|
||||
data = {};
|
||||
|
||||
WPADExtensionType type;
|
||||
if (WPADProbe(channel, &type) != 0) {
|
||||
data.buttons_h = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (KPADReadEx(channel, &kpad, 1, &kpadError) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kpadError != KPAD_ERROR_OK || kpad.extensionType == 0xFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kpad.extensionType == WPAD_EXT_CORE || kpad.extensionType == WPAD_EXT_NUNCHUK) {
|
||||
data.buttons_r = remapWiiMoteButtons(kpad.release);
|
||||
data.buttons_h = remapWiiMoteButtons(kpad.hold);
|
||||
data.buttons_d = remapWiiMoteButtons(kpad.trigger);
|
||||
} else {
|
||||
data.buttons_r = remapClassicButtons(kpad.classic.release);
|
||||
data.buttons_h = remapClassicButtons(kpad.classic.hold);
|
||||
data.buttons_d = remapClassicButtons(kpad.classic.trigger);
|
||||
}
|
||||
|
||||
data.validPointer = (kpad.posValid == 1 || kpad.posValid == 2) &&
|
||||
(kpad.pos.x >= -1.0f && kpad.pos.x <= 1.0f) &&
|
||||
(kpad.pos.y >= -1.0f && kpad.pos.y <= 1.0f);
|
||||
|
||||
//! calculate the screen offsets if pointer is valid else leave old value
|
||||
if (data.validPointer) {
|
||||
data.x = (width >> 1) * kpad.pos.x;
|
||||
data.y = (height >> 1) * (-kpad.pos.y);
|
||||
|
||||
if (kpad.angle.y > 0.0f) {
|
||||
data.pointerAngle = (-kpad.angle.x + 1.0f) * 0.5f * 180.0f;
|
||||
} else {
|
||||
data.pointerAngle = (kpad.angle.x + 1.0f) * 0.5f * 180.0f - 180.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void init() {
|
||||
KPADInit();
|
||||
WPADEnableURCC(1);
|
||||
}
|
||||
|
||||
static void close() {
|
||||
}
|
||||
|
||||
KPADStatus kpad = {};
|
||||
KPADError kpadError = KPAD_ERROR_UNINITIALIZED;
|
||||
KPADChan channel;
|
||||
};
|
||||
@@ -55,7 +55,7 @@ extern "C" {
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) while (0)
|
||||
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##INFO ## ", "\n", FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -91,12 +92,44 @@ remove_first_if(Container &container, Predicate pred) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Container, typename Predicate>
|
||||
typename std::enable_if<std::is_same<Container, std::vector<typename Container::value_type>>::value, bool>::type
|
||||
remove_first_if(Container &container, Predicate pred) {
|
||||
auto it = container.begin();
|
||||
while (it != container.end()) {
|
||||
if (pred(*it)) {
|
||||
container.erase(it);
|
||||
return true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Container, typename Predicate>
|
||||
bool remove_locked_first_if(std::mutex &mutex, Container &container, Predicate pred) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
return remove_first_if(container, pred);
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate>
|
||||
T pop_locked_first_if(std::mutex &mutex, std::vector<T> &container, Predicate pred) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
T result;
|
||||
auto it = container.begin();
|
||||
while (it != container.end()) {
|
||||
if (pred(*it)) {
|
||||
result = std::move(*it);
|
||||
container.erase(it);
|
||||
return result;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string getPluginPath();
|
||||
|
||||
OSDynLoad_Error CustomDynLoadAlloc(int32_t size, int32_t align, void **outAddr);
|
||||
|
||||
Reference in New Issue
Block a user