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);