mirror of
https://github.com/wiiu-env/EnvironmentLoader.git
synced 2024-11-23 14:39:15 +01:00
Implement support for pairing controller and GamePads
This commit is contained in:
parent
f57dc4c163
commit
b3a7150c5d
@ -30,6 +30,8 @@
|
||||
#include "kernel.h"
|
||||
#include "module/ModuleDataFactory.h"
|
||||
#include "utils/DrawUtils.h"
|
||||
#include "utils/InputUtils.h"
|
||||
#include "utils/PairUtils.h"
|
||||
|
||||
// clang-format off
|
||||
#define MEMORY_REGION_START 0x00A00000
|
||||
@ -157,16 +159,11 @@ int main(int argc, char **argv) {
|
||||
DEBUG_FUNCTION_LINE_ERR("No config found");
|
||||
}
|
||||
|
||||
VPADReadError err;
|
||||
VPADStatus vpad_data;
|
||||
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &err);
|
||||
InputUtils::Init();
|
||||
|
||||
uint32_t btn = 0;
|
||||
if (err == VPAD_READ_SUCCESS) {
|
||||
btn = vpad_data.hold | vpad_data.trigger;
|
||||
}
|
||||
InputUtils::InputData input = InputUtils::getControllerInput();
|
||||
|
||||
if (forceMenu || (btn & VPAD_BUTTON_X) == VPAD_BUTTON_X) {
|
||||
if (forceMenu || ((input.trigger | input.hold) & VPAD_BUTTON_X) == VPAD_BUTTON_X) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Open menu!");
|
||||
environment_path = EnvironmentSelectionScreen(environmentPaths, autobootIndex);
|
||||
if (environmentPaths.empty()) {
|
||||
@ -175,6 +172,7 @@ int main(int argc, char **argv) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Selected %s", environment_path.c_str());
|
||||
}
|
||||
}
|
||||
InputUtils::DeInit();
|
||||
}
|
||||
RevertMainHook();
|
||||
|
||||
@ -258,16 +256,6 @@ int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define COLOR_WHITE Color(0xffffffff)
|
||||
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||
#define COLOR_RED Color(237, 28, 36, 255)
|
||||
#define COLOR_BACKGROUND Color(0, 40, 100, 255)
|
||||
#define COLOR_TEXT COLOR_WHITE
|
||||
#define COLOR_TEXT2 Color(0xB3ffffff)
|
||||
#define COLOR_AUTOBOOT Color(0xaeea00ff)
|
||||
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4ff)
|
||||
|
||||
std::string EnvironmentSelectionScreen(const std::map<std::string, std::string> &payloads, int32_t autobootIndex) {
|
||||
OSScreenInit();
|
||||
|
||||
@ -295,32 +283,32 @@ std::string EnvironmentSelectionScreen(const std::map<std::string, std::string>
|
||||
uint32_t selected = autobootIndex > 0 ? autobootIndex : 0;
|
||||
int autoBoot = autobootIndex;
|
||||
|
||||
bool redraw = true;
|
||||
{
|
||||
PairMenu pairMenu;
|
||||
while (true) {
|
||||
VPADStatus vpad{};
|
||||
VPADRead(VPAD_CHAN_0, &vpad, 1, nullptr);
|
||||
if (pairMenu.ProcessPairScreen()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vpad.trigger & VPAD_BUTTON_UP) {
|
||||
InputUtils::InputData input = InputUtils::getControllerInput();
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_UP) {
|
||||
if (selected > 0) {
|
||||
selected--;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (vpad.trigger & VPAD_BUTTON_DOWN) {
|
||||
} else if (input.trigger & VPAD_BUTTON_DOWN) {
|
||||
if (selected < payloads.size() - 1) {
|
||||
selected++;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (vpad.trigger & VPAD_BUTTON_A) {
|
||||
} else if (input.trigger & VPAD_BUTTON_A) {
|
||||
break;
|
||||
} else if (vpad.trigger & VPAD_BUTTON_X) {
|
||||
} else if (input.trigger & VPAD_BUTTON_X) {
|
||||
autoBoot = -1;
|
||||
redraw = true;
|
||||
} else if (vpad.trigger & VPAD_BUTTON_Y) {
|
||||
} else if (input.trigger & VPAD_BUTTON_Y) {
|
||||
autoBoot = selected;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
@ -368,8 +356,6 @@ std::string EnvironmentSelectionScreen(const std::map<std::string, std::string>
|
||||
}
|
||||
|
||||
DrawUtils::endDraw();
|
||||
|
||||
redraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,16 @@
|
||||
#include "schrift.h"
|
||||
#include <cstdint>
|
||||
|
||||
#define COLOR_WHITE Color(0xffffffff)
|
||||
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||
#define COLOR_RED Color(237, 28, 36, 255)
|
||||
#define COLOR_BACKGROUND Color(0, 40, 100, 255)
|
||||
#define COLOR_TEXT COLOR_WHITE
|
||||
#define COLOR_TEXT2 Color(0xB3ffffff)
|
||||
#define COLOR_AUTOBOOT Color(0xaeea00ff)
|
||||
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4ff)
|
||||
|
||||
// visible screen sizes
|
||||
#define SCREEN_WIDTH 854
|
||||
#define SCREEN_HEIGHT 480
|
||||
|
134
source/utils/InputUtils.cpp
Normal file
134
source/utils/InputUtils.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "InputUtils.h"
|
||||
#include <padscore/kpad.h>
|
||||
#include <padscore/wpad.h>
|
||||
#include <vpad/input.h>
|
||||
|
||||
uint32_t remapWiiMoteButtons(uint32_t buttons) {
|
||||
uint32_t convButtons = 0;
|
||||
|
||||
if (buttons & WPAD_BUTTON_LEFT)
|
||||
convButtons |= VPAD_BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_RIGHT)
|
||||
convButtons |= VPAD_BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_DOWN)
|
||||
convButtons |= VPAD_BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_BUTTON_UP)
|
||||
convButtons |= VPAD_BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_BUTTON_PLUS)
|
||||
convButtons |= VPAD_BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_2)
|
||||
convButtons |= VPAD_BUTTON_Y;
|
||||
|
||||
if (buttons & WPAD_BUTTON_1)
|
||||
convButtons |= VPAD_BUTTON_X;
|
||||
|
||||
if (buttons & WPAD_BUTTON_B)
|
||||
convButtons |= VPAD_BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_BUTTON_A)
|
||||
convButtons |= VPAD_BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_BUTTON_MINUS)
|
||||
convButtons |= VPAD_BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_HOME)
|
||||
convButtons |= VPAD_BUTTON_HOME;
|
||||
|
||||
return convButtons;
|
||||
}
|
||||
|
||||
uint32_t remapClassicButtons(uint32_t buttons) {
|
||||
uint32_t convButtons = 0;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_LEFT)
|
||||
convButtons |= VPAD_BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
convButtons |= VPAD_BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_DOWN)
|
||||
convButtons |= VPAD_BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_UP)
|
||||
convButtons |= VPAD_BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_PLUS)
|
||||
convButtons |= VPAD_BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_X)
|
||||
convButtons |= VPAD_BUTTON_X;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_Y)
|
||||
convButtons |= VPAD_BUTTON_Y;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_B)
|
||||
convButtons |= VPAD_BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_A)
|
||||
convButtons |= VPAD_BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_MINUS)
|
||||
convButtons |= VPAD_BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_HOME)
|
||||
convButtons |= VPAD_BUTTON_HOME;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZR)
|
||||
convButtons |= VPAD_BUTTON_ZR;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZL)
|
||||
convButtons |= VPAD_BUTTON_ZL;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_R)
|
||||
convButtons |= VPAD_BUTTON_R;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_L)
|
||||
convButtons |= VPAD_BUTTON_L;
|
||||
|
||||
return convButtons;
|
||||
}
|
||||
|
||||
InputUtils::InputData InputUtils::getControllerInput() {
|
||||
InputData inputData{};
|
||||
VPADStatus vpadStatus{};
|
||||
VPADReadError vpadError = VPAD_READ_UNINITIALIZED;
|
||||
if (VPADRead(VPAD_CHAN_0, &vpadStatus, 1, &vpadError) > 0 && vpadError == VPAD_READ_SUCCESS) {
|
||||
inputData.trigger = vpadStatus.trigger;
|
||||
inputData.hold = vpadStatus.hold;
|
||||
inputData.release = vpadStatus.release;
|
||||
}
|
||||
|
||||
KPADStatus kpadStatus{};
|
||||
KPADError kpadError = KPAD_ERROR_UNINITIALIZED;
|
||||
for (int32_t i = 0; i < 4; i++) {
|
||||
if (KPADReadEx((KPADChan) i, &kpadStatus, 1, &kpadError) > 0) {
|
||||
if (kpadError == KPAD_ERROR_OK && kpadStatus.extensionType != 0xFF) {
|
||||
if (kpadStatus.extensionType == WPAD_EXT_CORE || kpadStatus.extensionType == WPAD_EXT_NUNCHUK) {
|
||||
inputData.trigger |= remapWiiMoteButtons(kpadStatus.trigger);
|
||||
inputData.hold |= remapWiiMoteButtons(kpadStatus.hold);
|
||||
inputData.release |= remapWiiMoteButtons(kpadStatus.release);
|
||||
} else {
|
||||
inputData.trigger |= remapClassicButtons(kpadStatus.classic.trigger);
|
||||
inputData.hold |= remapClassicButtons(kpadStatus.classic.hold);
|
||||
inputData.release |= remapClassicButtons(kpadStatus.classic.release);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inputData;
|
||||
}
|
||||
|
||||
void InputUtils::Init() {
|
||||
KPADInit();
|
||||
WPADEnableURCC(1);
|
||||
}
|
||||
|
||||
void InputUtils::DeInit() {
|
||||
KPADShutdown();
|
||||
}
|
17
source/utils/InputUtils.h
Normal file
17
source/utils/InputUtils.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <vpad/input.h>
|
||||
|
||||
class InputUtils {
|
||||
public:
|
||||
typedef struct InputData {
|
||||
uint32_t trigger = 0;
|
||||
uint32_t hold = 0;
|
||||
uint32_t release = 0;
|
||||
} InputData;
|
||||
|
||||
static void Init();
|
||||
static void DeInit();
|
||||
|
||||
static InputData getControllerInput();
|
||||
};
|
241
source/utils/PairUtils.cpp
Normal file
241
source/utils/PairUtils.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
#include "PairUtils.h"
|
||||
#include "DrawUtils.h"
|
||||
#include "InputUtils.h"
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <malloc.h>
|
||||
#include <nn/ccr/sys.h>
|
||||
#include <padscore/kpad.h>
|
||||
#include <padscore/wpad.h>
|
||||
#include <vpad/input.h>
|
||||
|
||||
void PairMenu::drawPairKPADScreen() const {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
DrawUtils::setFontSize(26);
|
||||
|
||||
std::string textLine1 = "Press the SYNC Button on the controller you want to pair.";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine1.c_str()) / 2, 40, textLine1.c_str(), true);
|
||||
|
||||
|
||||
WPADExtensionType ext{};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bool isConnected = WPADProbe((WPADChan) i, &ext) == 0;
|
||||
std::string textLine = string_format("Slot %d: ", i + 1);
|
||||
if (isConnected) {
|
||||
textLine += ext == WPAD_EXT_PRO_CONTROLLER ? "Pro Controller" : "Wiimote";
|
||||
} else {
|
||||
textLine += "No controller";
|
||||
}
|
||||
|
||||
DrawUtils::print(300, 140 + (i * 30), textLine.c_str());
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(26);
|
||||
|
||||
std::string gamepadSyncText1 = "If you are pairing a Wii U GamePad, press the SYNC Button";
|
||||
std::string gamepadSyncText2 = "on your Wii U console one more time";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(gamepadSyncText1.c_str()) / 2, SCREEN_HEIGHT - 100, gamepadSyncText1.c_str(), true);
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(gamepadSyncText2.c_str()) / 2, SCREEN_HEIGHT - 70, gamepadSyncText2.c_str(), true);
|
||||
|
||||
DrawUtils::setFontSize(16);
|
||||
|
||||
const char *exitHints = "Press \ue001 to return";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHints) / 2, SCREEN_HEIGHT - 8, exitHints, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
||||
|
||||
void PairMenu::drawPairScreen() const {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// Convert the pin to symbols and set the text
|
||||
static char pinSymbols[][4] = {
|
||||
"\u2660",
|
||||
"\u2665",
|
||||
"\u2666",
|
||||
"\u2663"};
|
||||
|
||||
uint32_t pincode = mGamePadPincode;
|
||||
|
||||
std::string pin = std::string(pinSymbols[(pincode / 1000) % 10]) +
|
||||
pinSymbols[(pincode / 100) % 10] +
|
||||
pinSymbols[(pincode / 10) % 10] +
|
||||
pinSymbols[pincode % 10];
|
||||
|
||||
std::string textLine1 = "Press the SYNC Button on the Wii U GamePad,";
|
||||
std::string textLine2 = "and enter the four symbols shown below.";
|
||||
|
||||
DrawUtils::setFontSize(26);
|
||||
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine1.c_str()) / 2, 60, textLine1.c_str(), true);
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine2.c_str()) / 2, 100, textLine2.c_str(), true);
|
||||
|
||||
DrawUtils::setFontSize(100);
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(pin.c_str()) / 2, (SCREEN_HEIGHT / 2) + 40, pin.c_str(), true);
|
||||
|
||||
DrawUtils::setFontSize(20);
|
||||
|
||||
std::string textLine3 = string_format("(%d seconds remaining) ", mGamePadSyncTimeout - (uint32_t) (OSTicksToSeconds(OSGetTime() - mSyncGamePadStartTime)));
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine3.c_str()) / 2, SCREEN_HEIGHT - 80, textLine3.c_str(), true);
|
||||
|
||||
DrawUtils::setFontSize(26);
|
||||
|
||||
std::string textLine4 = "Press the SYNC Button on the Wii U console to exit.";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine4.c_str()) / 2, SCREEN_HEIGHT - 40, textLine4.c_str(), true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
||||
|
||||
PairMenu::PairMenu() {
|
||||
CCRSysInit();
|
||||
|
||||
mState = STATE_WAIT;
|
||||
mGamePadSyncTimeout = 120;
|
||||
|
||||
// Initialize IM
|
||||
mIMHandle = IM_Open();
|
||||
if (mIMHandle < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("PairMenu: IM_Open failed");
|
||||
OSFatal("PairMenu: IM_Open failed");
|
||||
}
|
||||
mIMRequest = (IMRequest *) memalign(0x40, sizeof(IMRequest));
|
||||
|
||||
// Allocate a separate request for IM_CancelGetEventNotify to avoid conflict with the pending IM_GetEventNotify request
|
||||
mIMCancelRequest = (IMRequest *) memalign(0x40, sizeof(IMRequest));
|
||||
|
||||
if (!mIMRequest || !mIMCancelRequest) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate im request");
|
||||
OSFatal("PairMenu: Failed to allocate im request");
|
||||
}
|
||||
|
||||
mIMEventMask = IM_EVENT_SYNC;
|
||||
|
||||
// Notify about sync button events
|
||||
IM_GetEventNotify(mIMHandle, mIMRequest, &mIMEventMask, PairMenu::SyncButtonCallback, this);
|
||||
}
|
||||
|
||||
PairMenu::~PairMenu() {
|
||||
// Close IM
|
||||
IM_CancelGetEventNotify(mIMHandle, mIMCancelRequest, nullptr, nullptr);
|
||||
IM_Close(mIMHandle);
|
||||
if (mIMCancelRequest) {
|
||||
free(mIMCancelRequest);
|
||||
mIMCancelRequest = {};
|
||||
}
|
||||
if (mIMRequest) {
|
||||
free(mIMRequest);
|
||||
mIMRequest = {};
|
||||
}
|
||||
|
||||
// Deinit CCRSys
|
||||
CCRSysExit();
|
||||
}
|
||||
|
||||
extern "C" bool WPADStartSyncDevice();
|
||||
|
||||
bool PairMenu::ProcessPairScreen() {
|
||||
switch (mState) {
|
||||
case STATE_SYNC_WPAD: {
|
||||
// WPAD syncing stops after ~18 seconds, make sure to restart it.
|
||||
if ((uint32_t) OSTicksToSeconds(OSGetTime() - mSyncWPADStartTime) >= 18) {
|
||||
WPADStartSyncDevice();
|
||||
mSyncWPADStartTime = OSGetTime();
|
||||
}
|
||||
|
||||
InputUtils::InputData input = InputUtils::getControllerInput();
|
||||
|
||||
// Stop syncing when pressing A or B.
|
||||
if (input.trigger & (VPAD_BUTTON_A | VPAD_BUTTON_B)) {
|
||||
mState = STATE_WAIT;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case STATE_SYNC_GAMEPAD: {
|
||||
if (CCRSysGetPincode(&mGamePadPincode) != 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("CCRSysGetPincode failed");
|
||||
mState = STATE_WAIT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Start pairing to slot 0
|
||||
if (CCRSysStartPairing(0, mGamePadSyncTimeout) != 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("CCRSysStartPairing failed.");
|
||||
mState = STATE_WAIT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Pairing has started, save start time
|
||||
mSyncGamePadStartTime = OSGetTime();
|
||||
mState = STATE_PAIRING;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Started GamePad syncing.");
|
||||
|
||||
break;
|
||||
}
|
||||
case STATE_PAIRING: {
|
||||
// Get the current pairing state
|
||||
CCRSysPairingState pairingState = CCRSysGetPairingState();
|
||||
if (pairingState == CCR_SYS_PAIRING_TIMED_OUT) {
|
||||
DEBUG_FUNCTION_LINE("GamePad SYNC timed out.");
|
||||
// Pairing has timed out or was cancelled
|
||||
CCRSysStopPairing();
|
||||
mState = STATE_WAIT;
|
||||
} else if (pairingState == CCR_SYS_PAIRING_FINISHED) {
|
||||
DEBUG_FUNCTION_LINE("GamePad paired.");
|
||||
mState = STATE_WAIT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_CANCEL: {
|
||||
CCRSysStopPairing();
|
||||
mState = STATE_WAIT;
|
||||
break;
|
||||
}
|
||||
case STATE_WAIT:
|
||||
break;
|
||||
}
|
||||
switch (mState) {
|
||||
case STATE_WAIT: {
|
||||
return false;
|
||||
}
|
||||
case STATE_SYNC_WPAD:
|
||||
drawPairKPADScreen();
|
||||
break;
|
||||
case STATE_SYNC_GAMEPAD:
|
||||
case STATE_PAIRING:
|
||||
case STATE_CANCEL: {
|
||||
drawPairScreen();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PairMenu::SyncButtonCallback(IOSError error, void *arg) {
|
||||
auto *pairMenu = (PairMenu *) arg;
|
||||
|
||||
if (error == IOS_ERROR_OK && pairMenu && (pairMenu->mIMEventMask & IM_EVENT_SYNC)) {
|
||||
if (pairMenu->mState == STATE_WAIT) {
|
||||
pairMenu->mState = STATE_SYNC_WPAD;
|
||||
// We need to restart the WPAD pairing every 18 seconds. For the timing we need to save the current time.
|
||||
pairMenu->mSyncWPADStartTime = OSGetTime();
|
||||
} else if (pairMenu->mState == STATE_SYNC_WPAD) {
|
||||
pairMenu->mState = STATE_SYNC_GAMEPAD;
|
||||
} else if (pairMenu->mState == STATE_SYNC_GAMEPAD || pairMenu->mState == STATE_PAIRING) {
|
||||
pairMenu->mState = STATE_CANCEL;
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
IM_GetEventNotify(pairMenu->mIMHandle, pairMenu->mIMRequest, &pairMenu->mIMEventMask, PairMenu::SyncButtonCallback, pairMenu);
|
||||
}
|
||||
}
|
43
source/utils/PairUtils.h
Normal file
43
source/utils/PairUtils.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/im.h>
|
||||
#include <coreinit/ios.h>
|
||||
#include <coreinit/time.h>
|
||||
#include <malloc.h>
|
||||
#include <nn/ccr/sys.h>
|
||||
|
||||
class PairMenu {
|
||||
public:
|
||||
PairMenu();
|
||||
|
||||
~PairMenu();
|
||||
|
||||
bool ProcessPairScreen();
|
||||
|
||||
static void SyncButtonCallback(IOSError error, void *arg);
|
||||
|
||||
void drawPairScreen() const;
|
||||
|
||||
void drawPairKPADScreen() const;
|
||||
|
||||
private:
|
||||
enum PairMenuState {
|
||||
STATE_WAIT, // Wait for SYNC button press
|
||||
STATE_SYNC_WPAD,
|
||||
STATE_SYNC_GAMEPAD,
|
||||
STATE_PAIRING,
|
||||
STATE_CANCEL,
|
||||
};
|
||||
|
||||
IOSHandle mIMHandle{};
|
||||
IMRequest *mIMRequest{};
|
||||
IMRequest *mIMCancelRequest{};
|
||||
OSTime mSyncWPADStartTime = 0;
|
||||
OSTime mSyncGamePadStartTime = 0;
|
||||
uint32_t mGamePadPincode = 0;
|
||||
PairMenuState mState = STATE_WAIT;
|
||||
uint32_t mGamePadSyncTimeout = 120;
|
||||
IMEventMask mIMEventMask{};
|
||||
};
|
@ -15,3 +15,12 @@ template<class T, class... Args>
|
||||
std::shared_ptr<T> make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
||||
return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
std::string string_format(const std::string &format, Args... args) {
|
||||
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
|
||||
auto size = static_cast<size_t>(size_s);
|
||||
auto buf = std::make_unique<char[]>(size);
|
||||
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user