From 03c0c8a55e6ec03a99892e1d1b54e54290682fee Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 14 Sep 2018 20:29:06 +0200 Subject: [PATCH] - Split the main.cpp into multiple files - Add missing functions patches to allows pro controller emulation - Add a custom config item type which can be used to map controller during gameplay! - Usage of a real (pro) controller is currently broken - Mapping of the a keyboard/mouse is not tested (probably broken) --- makefile.mk | 2 +- src/ConfigHooks.cpp | 56 ++++++++ src/FunctionPatches.cpp | 189 +++++++++++++++++++++++++++ src/WUPSConfigItemPadMapping.cpp | 214 +++++++++++++++++++++++++++++++ src/WUPSConfigItemPadMapping.h | 65 ++++++++++ src/main.cpp | 125 ++++++------------ 6 files changed, 565 insertions(+), 86 deletions(-) create mode 100644 src/ConfigHooks.cpp create mode 100644 src/FunctionPatches.cpp create mode 100644 src/WUPSConfigItemPadMapping.cpp create mode 100644 src/WUPSConfigItemPadMapping.h diff --git a/makefile.mk b/makefile.mk index 561321a..e8e517f 100644 --- a/makefile.mk +++ b/makefile.mk @@ -48,7 +48,7 @@ LIBDIRS := $(WUPSDIR) $(WUT_ROOT) #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- -LIBS := -lwups -lcontrollerpatcherwut -lutilswut -lcoreinit -lnsysnet -lnsyshid -lvpadbase +LIBS := -lwups -lcontrollerpatcherwut -lutilswut -lcoreinit -lnsysnet -lnsyshid -lvpadbase -lvpad -lpadscore #--------------------------------------------------------------------------------- # Will be added to the final lib paths diff --git a/src/ConfigHooks.cpp b/src/ConfigHooks.cpp new file mode 100644 index 0000000..6ba950f --- /dev/null +++ b/src/ConfigHooks.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 . + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include "WUPSConfigItemPadMapping.h" + +void rumbleChanged(WUPSConfigItemBoolean * item, bool newValue) { + DEBUG_FUNCTION_LINE("rumbleChanged %d \n",newValue); + ControllerPatcher::setRumbleActivated(newValue); +} + +void networkClient(WUPSConfigItemBoolean * item, bool newValue) { + DEBUG_FUNCTION_LINE("Trigger network %d\n",newValue); + ControllerPatcher::setNetworkControllerActivated(newValue); + if(newValue) { + ControllerPatcher::startNetworkServer(); + } else { + ControllerPatcher::stopNetworkServer(); + } +} + +WUPS_GET_CONFIG() { + WUPSConfig* config = new WUPSConfig("HID to VPAD"); + WUPSConfigCategory* catOther = config->addCategory("Other"); + WUPSConfigCategory* catMapping = config->addCategory("Controller Mapping"); + + // item Type config id displayed name default value onChangeCallback. + catOther->addItem(new WUPSConfigItemBoolean("rumble", "Enable rumble", ControllerPatcher::isRumbleActivated(), rumbleChanged)); + catOther->addItem(new WUPSConfigItemBoolean("networkclient", "Enable network client", true, networkClient)); + + catMapping->addItem(new WUPSConfigItemPadMapping("gamepadmapping", "Gamepad", UController_Type_Gamepad)); + catMapping->addItem(new WUPSConfigItemPadMapping("propad1mapping", "Pro Controller 1", UController_Type_Pro1)); + catMapping->addItem(new WUPSConfigItemPadMapping("propad2mapping", "Pro Controller 2", UController_Type_Pro2)); + catMapping->addItem(new WUPSConfigItemPadMapping("propad3mapping", "Pro Controller 3", UController_Type_Pro3)); + catMapping->addItem(new WUPSConfigItemPadMapping("propad4mapping", "Pro Controller 4", UController_Type_Pro4)); + + return config; +} diff --git a/src/FunctionPatches.cpp b/src/FunctionPatches.cpp new file mode 100644 index 0000000..0ba6aff --- /dev/null +++ b/src/FunctionPatches.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 . + ****************************************************************************/ +#include + +#include +#include +#include + +DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error) { + int32_t result = real_VPADRead(chan, buffer, buffer_size, error); + //A keyboard only sends data when the state changes. We force it to call the sampling callback on each frame! + ControllerPatcher::sampleKeyboardData(); + + bool do_callback = (result > 0 && (buffer[0].hold & VPAD_BUTTON_TV)); + ControllerPatcher::handleCallbackData(do_callback); + + if(ControllerPatcher::areControllersConnected() && buffer_size > 0) { + ControllerPatcher::setRumble(UController_Type_Gamepad,!!VPADBASEGetMotorOnRemainingCount(VPAD_CHAN_0)); + + if(ControllerPatcher::setControllerDataFromHID(buffer) == CONTROLLER_PATCHER_ERROR_NONE) { + + if(buffer[0].hold & VPAD_BUTTON_HOME) { + //You can open the home menu this way, but not close it. Need a proper way to close it using the same button... + //OSSendAppSwitchRequest(5,0,0); //Open the home menu! + } + + if(error != NULL) { + *error = VPAD_READ_SUCCESS; + } + result = 1; // We want the WiiU to ignore everything else. + } + } + + if(ControllerPatcher::isButtonRemappingDone()) { + ControllerPatcher::buttonRemapping(buffer,result); + //ControllerPatcher::printVPADButtons(buffer); //Leads to random crashes on app transitions. + } + + return result; +} + +DECL_FUNCTION(int32_t, WPADProbe, WPADChan chan, uint32_t * result ) { + if( (chan == WPAD_CHAN_0 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro1)) || + (chan == WPAD_CHAN_1 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro2)) || + (chan == WPAD_CHAN_2 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro3)) || + (chan == WPAD_CHAN_3 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro4))) { + if(result != NULL) { + *result = WPAD_EXT_PRO_CONTROLLER; + } + return 0; + } + + return real_WPADProbe(chan,result); +} + +DECL_FUNCTION(WPADConnectCallback,WPADSetConnectCallback,WPADChan chan, WPADConnectCallback callback ) { + //log_printf("WPADSetConnectCallback chan %d %08X\n",chan,callback); + + ControllerPatcher::setWPADConnectCallback(chan,callback); + + if( (chan == WPAD_CHAN_0 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro1)) || + (chan == WPAD_CHAN_1 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro2)) || + (chan == WPAD_CHAN_2 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro3)) || + (chan == WPAD_CHAN_3 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro4))) { + if(callback != NULL) { + callback(chan,0); + } + } + return real_WPADSetConnectCallback(chan,callback); +} + +DECL_FUNCTION(WPADExtensionCallback,WPADSetExtensionCallback,WPADChan chan, WPADExtensionCallback callback ) { + //log_printf("WPADSetExtensionCallback chan %d %08X\n",chan,callback); + + ControllerPatcher::setKPADExtensionCallback(chan,callback); + + if((chan == WPAD_CHAN_0 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro1)) || + (chan == WPAD_CHAN_1 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro2)) || + (chan == WPAD_CHAN_2 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro3)) || + (chan == WPAD_CHAN_3 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro4))) { + if(callback != NULL) { + callback(chan,WPAD_EXT_PRO_CONTROLLER); + } + } + return real_WPADSetExtensionCallback(chan,callback); +} + +DECL_FUNCTION(WPADConnectCallback,KPADSetConnectCallback,WPADChan chan, WPADConnectCallback callback ) { + //log_printf("KPADSetConnectCallback chan %d %08X\n",chan,callback); + + ControllerPatcher::setKPADConnectedCallback(chan,callback); + + if( (chan == WPAD_CHAN_0 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro1)) || + (chan == WPAD_CHAN_1 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro2)) || + (chan == WPAD_CHAN_2 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro3)) || + (chan == WPAD_CHAN_3 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro4))) { + if(callback != NULL) { + callback(chan,0); + } + } + return real_KPADSetConnectCallback(chan,callback); +} + +DECL_FUNCTION(uint8_t, WPADGetBatteryLevel, WPADChan chan) { + uint8_t result = real_WPADGetBatteryLevel(chan); + + if( (chan == WPAD_CHAN_0 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro1)) || + (chan == WPAD_CHAN_1 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro2)) || + (chan == WPAD_CHAN_2 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro3)) || + (chan == WPAD_CHAN_3 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro4))) { + result = 4; // Full battery + } + return result; +} + +//In case a game relies on this... +DECL_FUNCTION(uint32_t, WPADGetDataFormat, WPADChan chan) { + //log_printf("WPADGetDataFormat chan: %d result: %d\n",chan,result); + if((chan == WPAD_CHAN_0 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro1)) || + (chan == WPAD_CHAN_1 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro2)) || + (chan == WPAD_CHAN_2 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro3)) || + (chan == WPAD_CHAN_3 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro4))) { + return WPAD_FMT_PRO_CONTROLLER; + } + return real_WPADGetDataFormat(chan); +} + +DECL_FUNCTION(int32_t, WPADSetDataFormat, WPADChan chan, WPADDataFormat fmt) { + int32_t result = -1; + if((chan == WPAD_CHAN_0 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro1)) || + (chan == WPAD_CHAN_1 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro2)) || + (chan == WPAD_CHAN_2 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro3)) || + (chan == WPAD_CHAN_3 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro4))) { + real_WPADSetDataFormat(chan,WPAD_FMT_PRO_CONTROLLER); + result = 0; + } + result = real_WPADSetDataFormat(chan,fmt); + return result; +} + +DECL_FUNCTION(void,WPADRead,WPADChan chan, WPADStatusProController *data ) { + if((chan == WPAD_CHAN_0 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro1)) || + (chan == WPAD_CHAN_1 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro2)) || + (chan == WPAD_CHAN_2 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro3)) || + (chan == WPAD_CHAN_3 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro4))) { + ControllerPatcher::setProControllerDataFromHID((void*)data,chan,PRO_CONTROLLER_MODE_WPADReadData); + } else { + real_WPADRead(chan,data); + + } +} + +DECL_FUNCTION(void,WPADControlMotor, WPADChan chan, uint32_t status ) { + if(chan == WPAD_CHAN_0 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro1)) { + ControllerPatcher::setRumble(UController_Type_Pro1,status); + } else if(chan == WPAD_CHAN_1 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro2)) { + ControllerPatcher::setRumble(UController_Type_Pro2,status); + } else if(chan == WPAD_CHAN_2 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro3)) { + ControllerPatcher::setRumble(UController_Type_Pro3,status); + } else if(chan == WPAD_CHAN_3 && ControllerPatcher::isControllerConnectedAndActive(UController_Type_Pro4)) { + ControllerPatcher::setRumble(UController_Type_Pro4,status); + } + real_WPADControlMotor(chan,status); +} + +WUPS_MUST_REPLACE(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead); +WUPS_MUST_REPLACE(WPADGetBatteryLevel, WUPS_LOADER_LIBRARY_PADSCORE, WPADGetBatteryLevel); +WUPS_MUST_REPLACE(KPADSetConnectCallback, WUPS_LOADER_LIBRARY_PADSCORE, KPADSetConnectCallback); +WUPS_MUST_REPLACE(WPADSetConnectCallback, WUPS_LOADER_LIBRARY_PADSCORE, WPADSetConnectCallback); +WUPS_MUST_REPLACE(WPADSetExtensionCallback, WUPS_LOADER_LIBRARY_PADSCORE, WPADSetExtensionCallback); +WUPS_MUST_REPLACE(WPADRead, WUPS_LOADER_LIBRARY_PADSCORE, WPADRead); +WUPS_MUST_REPLACE(WPADGetDataFormat, WUPS_LOADER_LIBRARY_PADSCORE, WPADGetDataFormat); +WUPS_MUST_REPLACE(WPADSetDataFormat, WUPS_LOADER_LIBRARY_PADSCORE, WPADSetDataFormat); +WUPS_MUST_REPLACE(WPADControlMotor, WUPS_LOADER_LIBRARY_PADSCORE, WPADControlMotor); +WUPS_MUST_REPLACE(WPADProbe, WUPS_LOADER_LIBRARY_PADSCORE, WPADProbe); diff --git a/src/WUPSConfigItemPadMapping.cpp b/src/WUPSConfigItemPadMapping.cpp new file mode 100644 index 0000000..33fb0fb --- /dev/null +++ b/src/WUPSConfigItemPadMapping.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 . + ****************************************************************************/ + +#include "WUPSConfigItemPadMapping.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +// At this point the VPADRead function is already patched. But we want to use the original function (note: this could be patched by a different plugin) +typedef int32_t (*VPADReadFunction) (VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error); +extern VPADReadFunction real_VPADRead; + +WUPSConfigItemPadMapping::WUPSConfigItemPadMapping(std::string configID, std::string displayName, UController_Type controller) : WUPSConfigItem(configID,displayName) { + this->controllerType = controller; +} + +WUPSConfigItemPadMapping::~WUPSConfigItemPadMapping() { + +} + +bool WUPSConfigItemPadMapping::updatePadInfo() { + int32_t found = ControllerPatcher::getActiveMappingSlot(controllerType); + if(found != -1) { + ControllerMappingPADInfo * info = ControllerPatcher::getControllerMappingInfo(controllerType,found); + if(info != NULL) { + memcpy(&mappedPadInfo,info,sizeof(mappedPadInfo)); + return true; + } + } else { + this->restoreDefault(); + return false; + } + return false; +} + +std::string WUPSConfigItemPadMapping::getCurrentValueDisplay() { + if(!updatePadInfo()) { + return "No Device"; + } + std::string name = ""; + std::string isConnectedString = "attached"; + + if(!ControllerPatcher::isControllerConnectedAndActive(controllerType)) { + isConnectedString = "detached"; + } + + ControllerMappingPADInfo * info = &mappedPadInfo; + + if(info->type == CM_Type_Controller) { + std::string titleString = ControllerPatcher::getIdentifierByVIDPID(info->vidpid.vid,info->vidpid.pid); + std::vector result = StringTools::stringSplit(titleString, "\n"); + if(result.size() == 1) { + name = titleString; + } else if(result.size() == 2) { + name = StringTools::strfmt("0x%04X / 0x%04X(%d) %s",info->vidpid.vid, info->vidpid.pid, info->pad, isConnectedString.c_str()); + } + } else if(info->type == CM_Type_RealController) { + // currently this case can't happen. + name = "Real (Pro) Controller"; + } else if(info->type == CM_Type_Mouse || info->type == CM_Type_Keyboard) { + // currently this case can't happen. + name = "Mouse / Keyboard"; + } + + return name.c_str(); +} + +std::string WUPSConfigItemPadMapping::getCurrentValueSelectedDisplay() { + return getCurrentValueDisplay(); +} + +void WUPSConfigItemPadMapping::onSelected(bool isSelected) { + +} + +void WUPSConfigItemPadMapping::checkForInput() { + int32_t inputsize = gHIDMaxDevices; + InputData * hiddata = (InputData * ) malloc(sizeof(InputData)*inputsize); + memset(hiddata,0,sizeof(InputData)*inputsize); + + ControllerMappingPADInfo pad_result; + memset(&pad_result,0,sizeof(ControllerMappingPADInfo)); + bool gotPress = false; + + VPADStatus vpad_data; + VPADReadError error; + + while(!gotPress) { + real_VPADRead(VPAD_CHAN_0, &vpad_data, 1, &error); + if(error != VPAD_READ_SUCCESS) { + if(vpad_data.hold == VPAD_BUTTON_B || vpad_data.hold == VPAD_BUTTON_HOME) { + break; + } + } + + int32_t result = ControllerPatcher::gettingInputAllDevices(hiddata,inputsize); + if(result > 0) { + //log_printf("got %d results\n",result); + for(int32_t i =0; icontrollerType,pad_result); + updatePadInfo(); + } + + free(hiddata); +} + +void WUPSConfigItemPadMapping::onButtonPressed(WUPSConfigButtons buttons) { + if(buttons & WUPS_CONFIG_BUTTON_A) { + // Lets remove the old mapping. + ControllerPatcher::resetControllerMapping(this->controllerType); + + // And draw the text on the screen the config menu is drawn to. + wups_overlay_options_type_t screen = this->lastVisibleOnScreen(); + + WUPS_Overlay_OSScreenClear(screen); + + // TODO: Add more information about the target (e.g. is the mapping for the gamepad or pro controller 1/2/3/4) + WUPS_Overlay_PrintTextOnScreen(screen, 0,0,"Press a button on the HID controller to map it."); + WUPS_Overlay_PrintTextOnScreen(screen, 0,10,"Press HOME or B on the gamepad to abort."); + + WUPS_Overlay_FlipBuffers(screen); + + checkForInput(); + } +} + +bool WUPSConfigItemPadMapping::isMovementAllowed() { + return true; +} + +std::string WUPSConfigItemPadMapping::persistValue() { + updatePadInfo(); + if(mappedPadInfo.type == CM_Type_Controller){ + return StringTools::strfmt("%d,%d,%d,%d",mappedPadInfo.vidpid.vid,mappedPadInfo.vidpid.pid,mappedPadInfo.pad,mappedPadInfo.type); + } + return "0"; +} + +void WUPSConfigItemPadMapping::loadValue(std::string persistedValue) { + if(persistedValue.compare("0") == 0) { + // No device mapped. + return; + } + std::vector result = StringTools::stringSplit(persistedValue, ","); + if(result.size() != 4) { + return; + } + + updatePadInfo(); + + this->mappedPadInfo.vidpid.vid = atoi(result.at(0).c_str()); + this->mappedPadInfo.vidpid.pid = atoi(result.at(1).c_str()); + this->mappedPadInfo.pad = atoi(result.at(2).c_str()); + //Currently only persisting mapped controllers is supported. + this->mappedPadInfo.type = CM_Type_Controller; //atoi(result.at(3).c_str()); + + ControllerPatcher::resetControllerMapping(this->controllerType); + // TODO: Save the choice and use a callback??!??! + ControllerPatcher::addControllerMapping(this->controllerType,this->mappedPadInfo); + + return; +} + +void WUPSConfigItemPadMapping::restoreDefault() { + memset(&mappedPadInfo,0,sizeof(mappedPadInfo)); +} + +bool WUPSConfigItemPadMapping::callCallback() { + // Currently we don't use a callback. + return false; +} diff --git a/src/WUPSConfigItemPadMapping.h b/src/WUPSConfigItemPadMapping.h new file mode 100644 index 0000000..4fb1322 --- /dev/null +++ b/src/WUPSConfigItemPadMapping.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 . + ****************************************************************************/ + +#ifndef _WUPS_CONFIG_ITEM_PAD_MAPPING_H_ +#define _WUPS_CONFIG_ITEM_PAD_MAPPING_H_ + +#include +#include +#include +#include + +class WUPSConfigItemPadMapping; + +typedef void (*PadMappingChangedCallback)(WUPSConfigItemPadMapping *, bool); + +class WUPSConfigItemPadMapping : public WUPSConfigItem { +public: + WUPSConfigItemPadMapping(std::string configID, std::string displayName, UController_Type controller); + + void checkForInput(); + + virtual ~WUPSConfigItemPadMapping(); + + void resetMappingAndDetachController(); + + bool updatePadInfo(); + + virtual std::string getCurrentValueDisplay(); + + virtual std::string getCurrentValueSelectedDisplay(); + + virtual void onSelected(bool isSelected); + + virtual void onButtonPressed(WUPSConfigButtons buttons); + + virtual bool isMovementAllowed(); + + virtual std::string persistValue(); + + virtual void loadValue(std::string persistedValue); + + virtual void restoreDefault(); + + virtual bool callCallback(); + +private: + UController_Type controllerType = UController_Type_Gamepad; + ControllerMappingPADInfo mappedPadInfo; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index 6d1207a..e05162e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,28 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 . + ****************************************************************************/ + #include -#include -#include + #include #include #include -#include + #include +#include "WUPSConfigItemPadMapping.h" WUPS_PLUGIN_NAME("HID to VPAD lite"); WUPS_PLUGIN_DESCRIPTION("Enables HID devices as controllers on your Wii U"); @@ -20,95 +37,33 @@ WUPS_FS_ACCESS() #define WIIU_PATH "/wiiu" #define DEFAULT_HID_TO_VPAD_PATH SD_PATH WIIU_PATH "/apps/hidtovpad" -void rumbleChanged(WUPSConfigItemBoolean * item, bool newValue) { - DEBUG_FUNCTION_LINE("rumbleChanged %d \n",newValue); - ControllerPatcher::setRumbleActivated(newValue); +ON_APPLICATION_START(args) { + socket_lib_init(); + log_init(); + + DEBUG_FUNCTION_LINE("Initializing the controller data\n"); + ControllerPatcher::Init(CONTROLLER_PATCHER_PATH); + ControllerPatcher::enableControllerMapping(); + DEBUG_FUNCTION_LINE("Starting HID to VPAD network server\n"); + ControllerPatcher::startNetworkServer(); + ControllerPatcher::disableWiiUEnergySetting(); } -void networkClient(WUPSConfigItemBoolean * item, bool newValue) { - DEBUG_FUNCTION_LINE("Trigger network %d\n",newValue); - ControllerPatcher::setNetworkControllerActivated(newValue); - if(newValue) { - ControllerPatcher::startNetworkServer(); - } else { - ControllerPatcher::stopNetworkServer(); - } -} - -WUPS_GET_CONFIG() { - WUPSConfig* config = new WUPSConfig("HID to VPAD"); - WUPSConfigCategory* catOther = config->addCategory("Other"); - - // item Type config id displayed name default value onChangeCallback. - catOther->addItem(new WUPSConfigItemBoolean("rumble", "Enable rumble", ControllerPatcher::isRumbleActivated(), rumbleChanged)); - catOther->addItem(new WUPSConfigItemBoolean("networkclient", "Enable network client", true, networkClient)); - - return config; -} - - DEINITIALIZE_PLUGIN() { //CursorDrawer::destroyInstance(); ControllerPatcher::DeInit(); ControllerPatcher::stopNetworkServer(); } -ON_APPLICATION_START(args) { - socket_lib_init(); - log_init(); +ON_APPLICATION_ENDING() { + //CursorDrawer::destroyInstance(); + DEBUG_FUNCTION_LINE("ON_APPLICATION_ENDING\n"); + ControllerPatcher::destroyConfigHelper(); + DEBUG_FUNCTION_LINE("Calling stopNetworkServer\n"); + ControllerPatcher::stopNetworkServer(); + DEBUG_FUNCTION_LINE("Calling resetCallbackData\n"); + ControllerPatcher::resetCallbackData(); + ControllerPatcher::restoreWiiUEnergySetting(); - DEBUG_FUNCTION_LINE("Initializing the controller data\n"); - ControllerPatcher::Init(CONTROLLER_PATCHER_PATH); - ControllerPatcher::disableControllerMapping(); - DEBUG_FUNCTION_LINE("Starting HID to VPAD network server\n"); - ControllerPatcher::startNetworkServer(); - ControllerPatcher::disableWiiUEnergySetting(); + DEBUG_FUNCTION_LINE("Closing\n"); } - -ON_APP_STATUS_CHANGED(status) { - if(status == WUPS_APP_STATUS_CLOSED) { - //CursorDrawer::destroyInstance(); - DEBUG_FUNCTION_LINE("ON_APPLICATION_ENDING\n"); - ControllerPatcher::destroyConfigHelper(); - DEBUG_FUNCTION_LINE("Calling stopNetworkServer\n"); - ControllerPatcher::stopNetworkServer(); - DEBUG_FUNCTION_LINE("Calling resetCallbackData\n"); - ControllerPatcher::resetCallbackData(); - ControllerPatcher::restoreWiiUEnergySetting(); - } -} - -DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, int32_t *error) { - int32_t result = real_VPADRead(chan, buffer, buffer_size, error); - //A keyboard only sends data when the state changes. We force it to call the sampling callback on each frame! - ControllerPatcher::sampleKeyboardData(); - - bool do_callback = (result > 0 && (buffer[0].hold & VPAD_BUTTON_TV)); - ControllerPatcher::handleCallbackData(do_callback); - - if(ControllerPatcher::areControllersConnected() && buffer_size > 0) { - ControllerPatcher::setRumble(UController_Type_Gamepad,!!VPADBASEGetMotorOnRemainingCount(VPAD_CHAN_0)); - - if(ControllerPatcher::setControllerDataFromHID(buffer) == CONTROLLER_PATCHER_ERROR_NONE) { - - if(buffer[0].hold & VPAD_BUTTON_HOME) { - //You can open the home menu this way, but not close it. Need a proper way to close it using the same button... - //OSSendAppSwitchRequest(5,0,0); //Open the home menu! - } - - if(error != NULL) { - *error = 0; - } - result = 1; // We want the WiiU to ignore everything else. - } - } - - if(ControllerPatcher::isButtonRemappingDone()) { - ControllerPatcher::buttonRemapping(buffer,result); - //ControllerPatcher::printVPADButtons(buffer); //Leads to random crashes on app transitions. - } - - return result; -} - -WUPS_MUST_REPLACE(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead);