mirror of
https://github.com/Maschell/hid_to_vpad.git
synced 2024-11-12 18:25:05 +01:00
- 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)
This commit is contained in:
parent
de97bae3ad
commit
03c0c8a55e
@ -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
|
||||
|
56
src/ConfigHooks.cpp
Normal file
56
src/ConfigHooks.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#include <wups.h>
|
||||
#include <wups/config.h>
|
||||
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||
#include <controller_patcher/ControllerPatcher.hpp>
|
||||
#include <utils/logger.h>
|
||||
#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;
|
||||
}
|
189
src/FunctionPatches.cpp
Normal file
189
src/FunctionPatches.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include <wups.h>
|
||||
|
||||
#include <controller_patcher/ControllerPatcher.hpp>
|
||||
#include <vpad/input.h>
|
||||
#include <padscore/wpad.h>
|
||||
|
||||
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);
|
214
src/WUPSConfigItemPadMapping.cpp
Normal file
214
src/WUPSConfigItemPadMapping.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#include "WUPSConfigItemPadMapping.h"
|
||||
#include <controller_patcher/ControllerPatcher.hpp>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <utils/logger.h>
|
||||
#include <vpad/input.h>
|
||||
#include <padscore/wpad.h>
|
||||
#include <utils/StringTools.h>
|
||||
|
||||
|
||||
// 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<std::string> 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; i<result; i++) {
|
||||
for(int32_t j = 0; j<HID_MAX_PADS_COUNT; j++) {
|
||||
//log_printf("check pad %d. %08X\n",j,hiddata[i].button_data[j].btn_h);
|
||||
if(hiddata[i].button_data[j].btn_h != 0) {
|
||||
//log_printf("It pressed a buttons!\n",result);
|
||||
pad_result.pad = j;
|
||||
pad_result.vidpid.vid = hiddata[i].device_info.vidpid.vid;
|
||||
pad_result.vidpid.pid = hiddata[i].device_info.vidpid.pid;
|
||||
pad_result.active = 1;
|
||||
pad_result.type = hiddata[i].type;
|
||||
|
||||
gotPress = true;
|
||||
DEBUG_FUNCTION_LINE("%04X %04X (PAD: %d) pressed a buttons %08X\n",hiddata[i].device_info.vidpid.vid,hiddata[i].device_info.vidpid.pid,j,hiddata[i].button_data[j].btn_h);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(gotPress) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(gotPress) {
|
||||
// TODO: Save the choice and use a callback??!??!
|
||||
ControllerPatcher::addControllerMapping(this->controllerType,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<std::string> 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;
|
||||
}
|
65
src/WUPSConfigItemPadMapping.h
Normal file
65
src/WUPSConfigItemPadMapping.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _WUPS_CONFIG_ITEM_PAD_MAPPING_H_
|
||||
#define _WUPS_CONFIG_ITEM_PAD_MAPPING_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wups/config/WUPSConfigItem.h>
|
||||
#include <controller_patcher/ControllerPatcher.hpp>
|
||||
|
||||
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
|
125
src/main.cpp
125
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 <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#include <wups.h>
|
||||
#include <wups/config.h>
|
||||
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <controller_patcher/ControllerPatcher.hpp>
|
||||
#include <utils/logger.h>
|
||||
#include <vpad/input.h>
|
||||
|
||||
#include <nsysnet/socket.h>
|
||||
#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);
|
||||
|
Loading…
Reference in New Issue
Block a user