mirror of
https://github.com/cathery/sys-con.git
synced 2025-02-04 21:39:56 +00:00
Add support for multiple 360 wireless controllers
This commit is contained in:
parent
435b203525
commit
ba7a0b754f
@ -20,7 +20,7 @@ private:
|
|||||||
|
|
||||||
Xbox360ButtonData m_buttonData;
|
Xbox360ButtonData m_buttonData;
|
||||||
|
|
||||||
bool m_presence;
|
bool m_presence = false;
|
||||||
|
|
||||||
std::vector<OutputPacket> m_outputBuffer;
|
std::vector<OutputPacket> m_outputBuffer;
|
||||||
|
|
||||||
@ -48,7 +48,12 @@ public:
|
|||||||
Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude);
|
Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude);
|
||||||
Status SetLED(Xbox360LEDValue value);
|
Status SetLED(Xbox360LEDValue value);
|
||||||
|
|
||||||
|
Status OnControllerConnect();
|
||||||
|
Status OnControllerDisconnect();
|
||||||
|
|
||||||
static void LoadConfig(const ControllerConfig *config);
|
static void LoadConfig(const ControllerConfig *config);
|
||||||
|
|
||||||
Status OutputBuffer();
|
Status OutputBuffer();
|
||||||
|
|
||||||
|
bool IsControllerActive() override { return m_presence; }
|
||||||
};
|
};
|
@ -32,6 +32,7 @@ public:
|
|||||||
inline IUSBDevice *GetDevice() { return m_device.get(); }
|
inline IUSBDevice *GetDevice() { return m_device.get(); }
|
||||||
virtual ControllerType GetType() = 0;
|
virtual ControllerType GetType() = 0;
|
||||||
virtual Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude) = 0;
|
virtual Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude) = 0;
|
||||||
|
virtual bool IsControllerActive() { return true; }
|
||||||
|
|
||||||
Status OutputBuffer() { return 1; };
|
Status OutputBuffer() { return 1; };
|
||||||
};
|
};
|
@ -4,7 +4,7 @@
|
|||||||
static ControllerConfig _xbox360WControllerConfig{};
|
static ControllerConfig _xbox360WControllerConfig{};
|
||||||
static const uint8_t reconnectPacket[]{0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
static const uint8_t reconnectPacket[]{0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
static const uint8_t poweroffPacket[]{0x00, 0x00, 0x08, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
static const uint8_t poweroffPacket[]{0x00, 0x00, 0x08, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
static const uint8_t ledPacket[]{0x00, 0x00, 0x08, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
static const uint8_t ledPacket[]{0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
Xbox360WirelessController::Xbox360WirelessController(std::unique_ptr<IUSBDevice> &&interface)
|
Xbox360WirelessController::Xbox360WirelessController(std::unique_ptr<IUSBDevice> &&interface)
|
||||||
: IController(std::move(interface))
|
: IController(std::move(interface))
|
||||||
@ -25,12 +25,13 @@ Status Xbox360WirelessController::Initialize()
|
|||||||
rc = OpenInterfaces();
|
rc = OpenInterfaces();
|
||||||
if (S_FAILED(rc))
|
if (S_FAILED(rc))
|
||||||
return rc;
|
return rc;
|
||||||
|
/*
|
||||||
rc = m_outPipe->Write(reconnectPacket, sizeof(reconnectPacket));
|
rc = m_outPipe->Write(reconnectPacket, sizeof(reconnectPacket));
|
||||||
if (S_FAILED(rc))
|
if (S_FAILED(rc))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
SetLED(XBOX360LED_TOPLEFT);
|
SetLED(XBOX360LED_TOPLEFT);
|
||||||
|
*/
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
void Xbox360WirelessController::Exit()
|
void Xbox360WirelessController::Exit()
|
||||||
@ -125,12 +126,9 @@ Status Xbox360WirelessController::GetInput()
|
|||||||
m_presence = newPresence;
|
m_presence = newPresence;
|
||||||
|
|
||||||
if (m_presence)
|
if (m_presence)
|
||||||
{
|
OnControllerConnect();
|
||||||
m_outputBuffer.push_back(OutputPacket{reconnectPacket, sizeof(reconnectPacket)});
|
|
||||||
m_outputBuffer.push_back(OutputPacket{ledPacket, sizeof(ledPacket)});
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
m_outputBuffer.push_back(OutputPacket{poweroffPacket, sizeof(poweroffPacket)});
|
OnControllerDisconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,8 +239,8 @@ Status Xbox360WirelessController::SetRumble(uint8_t strong_magnitude, uint8_t we
|
|||||||
|
|
||||||
Status Xbox360WirelessController::SetLED(Xbox360LEDValue value)
|
Status Xbox360WirelessController::SetLED(Xbox360LEDValue value)
|
||||||
{
|
{
|
||||||
uint8_t ledPacket[]{0x00, 0x00, 0x08, static_cast<uint8_t>(value + 40), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t customLEDPacket[]{0x00, 0x00, 0x08, static_cast<uint8_t>(value | 0x40), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
return m_outPipe->Write(ledPacket, sizeof(ledPacket));
|
return m_outPipe->Write(customLEDPacket, sizeof(customLEDPacket));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Xbox360WirelessController::LoadConfig(const ControllerConfig *config)
|
void Xbox360WirelessController::LoadConfig(const ControllerConfig *config)
|
||||||
@ -250,12 +248,28 @@ void Xbox360WirelessController::LoadConfig(const ControllerConfig *config)
|
|||||||
_xbox360WControllerConfig = *config;
|
_xbox360WControllerConfig = *config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status Xbox360WirelessController::OnControllerConnect()
|
||||||
|
{
|
||||||
|
m_outputBuffer.push_back(OutputPacket{reconnectPacket, sizeof(reconnectPacket)});
|
||||||
|
m_outputBuffer.push_back(OutputPacket{ledPacket, sizeof(ledPacket)});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status Xbox360WirelessController::OnControllerDisconnect()
|
||||||
|
{
|
||||||
|
m_outputBuffer.push_back(OutputPacket{poweroffPacket, sizeof(poweroffPacket)});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Status Xbox360WirelessController::OutputBuffer()
|
Status Xbox360WirelessController::OutputBuffer()
|
||||||
{
|
{
|
||||||
if (m_outputBuffer.empty())
|
if (m_outputBuffer.empty())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
Status rc = m_outPipe->Write(m_outputBuffer[0].packet, m_outputBuffer[0].length);
|
Status rc;
|
||||||
m_outputBuffer.erase(m_outputBuffer.begin());
|
auto it = m_outputBuffer.begin();
|
||||||
|
rc = m_outPipe->Write(it->packet, it->length);
|
||||||
|
m_outputBuffer.erase(it);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -18,39 +18,11 @@ Result SwitchHDLHandler::Initialize()
|
|||||||
if (R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/*
|
|
||||||
hidScanInput();
|
|
||||||
HidControllerID lastOfflineID = CONTROLLER_PLAYER_1;
|
|
||||||
for (int i = 0; i != 8; ++i)
|
|
||||||
{
|
|
||||||
if (!hidIsControllerConnected(static_cast<HidControllerID>(i)))
|
|
||||||
{
|
|
||||||
lastOfflineID = static_cast<HidControllerID>(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//WriteToLog("Found last offline ID: ", lastOfflineID);
|
|
||||||
*/
|
|
||||||
|
|
||||||
rc = InitHdlState();
|
rc = InitHdlState();
|
||||||
if (R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/*
|
if (DoesControllerSupport(GetController()->GetType(), SUPPORTS_PAIRING))
|
||||||
svcSleepThread(1e+7L);
|
|
||||||
hidScanInput();
|
|
||||||
|
|
||||||
//WriteToLog("Is last offline id connected? ", hidIsControllerConnected(lastOfflineID));
|
|
||||||
//WriteToLog("Last offline id type: ", hidGetControllerType(lastOfflineID));
|
|
||||||
|
|
||||||
Result rc2 = hidInitializeVibrationDevices(&m_vibrationDeviceHandle, 1, lastOfflineID, hidGetControllerType(lastOfflineID));
|
|
||||||
if (R_SUCCEEDED(rc2))
|
|
||||||
InitOutputThread();
|
|
||||||
else
|
|
||||||
WriteToLog("Failed to iniitalize vibration with error ", rc2);
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (DoesControllerSupport(m_controllerHandler.GetController()->GetType(), SUPPORTS_PAIRING))
|
|
||||||
{
|
{
|
||||||
rc = InitOutputThread();
|
rc = InitOutputThread();
|
||||||
if (R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
@ -93,7 +65,10 @@ Result SwitchHDLHandler::InitHdlState()
|
|||||||
m_hdlState.joysticks[JOYSTICK_RIGHT].dx = 0x5678;
|
m_hdlState.joysticks[JOYSTICK_RIGHT].dx = 0x5678;
|
||||||
m_hdlState.joysticks[JOYSTICK_RIGHT].dy = -0x5678;
|
m_hdlState.joysticks[JOYSTICK_RIGHT].dy = -0x5678;
|
||||||
|
|
||||||
return hiddbgAttachHdlsVirtualDevice(&m_hdlHandle, &m_deviceInfo);
|
if (GetController()->IsControllerActive())
|
||||||
|
return hiddbgAttachHdlsVirtualDevice(&m_hdlHandle, &m_deviceInfo);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
Result SwitchHDLHandler::ExitHdlState()
|
Result SwitchHDLHandler::ExitHdlState()
|
||||||
{
|
{
|
||||||
@ -155,18 +130,28 @@ void SwitchHDLHandler::UpdateInput()
|
|||||||
if (R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FillHdlState(GetController()->GetNormalizedButtonData());
|
if (!GetController()->IsControllerActive())
|
||||||
rc = UpdateHdlState();
|
{
|
||||||
if (R_FAILED(rc))
|
hiddbgDetachHdlsVirtualDevice(m_hdlHandle);
|
||||||
return;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FillHdlState(GetController()->GetNormalizedButtonData());
|
||||||
|
rc = UpdateHdlState();
|
||||||
|
if (R_FAILED(rc))
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchHDLHandler::UpdateOutput()
|
void SwitchHDLHandler::UpdateOutput()
|
||||||
{
|
{
|
||||||
if (R_SUCCEEDED(m_controllerHandler.GetController()->OutputBuffer()))
|
if (R_SUCCEEDED(GetController()->OutputBuffer()))
|
||||||
|
{
|
||||||
|
svcSleepThread(1e+7L);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (DoesControllerSupport(m_controllerHandler.GetController()->GetType(), SUPPORTS_RUMBLE))
|
if (DoesControllerSupport(GetController()->GetType(), SUPPORTS_RUMBLE))
|
||||||
{
|
{
|
||||||
Result rc;
|
Result rc;
|
||||||
HidVibrationValue value;
|
HidVibrationValue value;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "switch.h"
|
#include "switch.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "mainLoop.h"
|
#include "mainLoop.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
//ISSUES:
|
//ISSUES:
|
||||||
// when exiting the applet, only one of the controllers is reset
|
// when exiting the applet, only one of the controllers is reset
|
||||||
@ -9,8 +10,6 @@
|
|||||||
|
|
||||||
//TODO:
|
//TODO:
|
||||||
// Shrink unneessary heap memory/stack size used for the sysmodule
|
// Shrink unneessary heap memory/stack size used for the sysmodule
|
||||||
// Allow to connect controllers paired through a bluetooth adapter
|
|
||||||
// Allow to connect controllers through usbDs (directly to switch)
|
|
||||||
// Make a config application companion to test controller input and edit various preferences (buttons, deadzones)
|
// Make a config application companion to test controller input and edit various preferences (buttons, deadzones)
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@ -38,7 +37,7 @@ extern "C"
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void __attribute__((weak)) userAppInit(void)
|
void userAppInit(void)
|
||||||
{
|
{
|
||||||
//Seems like every thread on the switch needs to sleep for a little
|
//Seems like every thread on the switch needs to sleep for a little
|
||||||
// or it will block the entire console
|
// or it will block the entire console
|
||||||
@ -65,7 +64,7 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void __attribute__((weak)) userAppExit(void)
|
void userAppExit(void)
|
||||||
{
|
{
|
||||||
#ifndef __APPLET__
|
#ifndef __APPLET__
|
||||||
hidExit();
|
hidExit();
|
||||||
|
@ -28,15 +28,45 @@ Result QueryInterfaces(UsbHsInterface *interfaces, size_t interfaces_size, s32 *
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IUSBDevice> devicePtr;
|
||||||
|
std::unique_ptr<IController> controllerPtr;
|
||||||
|
bool useAbstractedPad = hosversionBetween(5, 7);
|
||||||
|
std::vector<std::unique_ptr<SwitchVirtualGamepadHandler>> controllerInterfaces;
|
||||||
|
|
||||||
|
Result CallInitHandler()
|
||||||
|
{
|
||||||
|
if (controllerPtr)
|
||||||
|
{
|
||||||
|
Result rc;
|
||||||
|
std::unique_ptr<SwitchVirtualGamepadHandler> switchHandler;
|
||||||
|
if (useAbstractedPad)
|
||||||
|
switchHandler = std::make_unique<SwitchAbstractedPadHandler>(std::move(controllerPtr));
|
||||||
|
else
|
||||||
|
switchHandler = std::make_unique<SwitchHDLHandler>(std::move(controllerPtr));
|
||||||
|
|
||||||
|
rc = switchHandler->Initialize();
|
||||||
|
if (R_SUCCEEDED(rc))
|
||||||
|
{
|
||||||
|
controllerInterfaces.push_back(std::move(switchHandler));
|
||||||
|
WriteToLog("Interface created successfully");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteToLog("Error creating interface with error ", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Result mainLoop()
|
Result mainLoop()
|
||||||
{
|
{
|
||||||
WriteToLog("\n\nNew sysmodule session started");
|
WriteToLog("\n\nNew sysmodule session started");
|
||||||
Result rc = 0;
|
Result rc = 0;
|
||||||
bool useAbstractedPad = hosversionBetween(5, 7);
|
|
||||||
|
|
||||||
Event catchAllEvent;
|
Event catchAllEvent;
|
||||||
Event ds3Event;
|
Event ds3Event;
|
||||||
std::vector<std::unique_ptr<SwitchVirtualGamepadHandler>> controllerInterfaces;
|
|
||||||
|
|
||||||
UTimer filecheckTimer;
|
UTimer filecheckTimer;
|
||||||
Waiter filecheckTimerWaiter = waiterForUTimer(&filecheckTimer);
|
Waiter filecheckTimerWaiter = waiterForUTimer(&filecheckTimer);
|
||||||
@ -69,8 +99,6 @@ Result mainLoop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
controllerInterfaces.reserve(8);
|
controllerInterfaces.reserve(8);
|
||||||
std::unique_ptr<IUSBDevice> devicePtr;
|
|
||||||
std::unique_ptr<IController> controllerPtr;
|
|
||||||
|
|
||||||
while (appletMainLoop())
|
while (appletMainLoop())
|
||||||
{
|
{
|
||||||
@ -97,9 +125,13 @@ Result mainLoop()
|
|||||||
}
|
}
|
||||||
else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_VENDOR_SPEC, 93, 129)))
|
else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_VENDOR_SPEC, 93, 129)))
|
||||||
{
|
{
|
||||||
WriteToLog("Registering Xbox 360 Wireless controller");
|
WriteToLog("Registering Xbox 360 Wireless adapter");
|
||||||
devicePtr = std::make_unique<SwitchUSBDevice>(interfaces, total_entries);
|
for (int i = 0; i != total_entries; ++i)
|
||||||
controllerPtr = std::make_unique<Xbox360WirelessController>(std::move(devicePtr));
|
{
|
||||||
|
devicePtr = std::make_unique<SwitchUSBDevice>(interfaces + i, 1);
|
||||||
|
controllerPtr = std::make_unique<Xbox360WirelessController>(std::move(devicePtr));
|
||||||
|
CallInitHandler();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, 0x58, 0x42, 0x00)))
|
else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, 0x58, 0x42, 0x00)))
|
||||||
{
|
{
|
||||||
@ -128,26 +160,7 @@ Result mainLoop()
|
|||||||
controllerPtr = std::make_unique<Dualshock3Controller>(std::move(devicePtr));
|
controllerPtr = std::make_unique<Dualshock3Controller>(std::move(devicePtr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CallInitHandler();
|
||||||
if (controllerPtr)
|
|
||||||
{
|
|
||||||
std::unique_ptr<SwitchVirtualGamepadHandler> switchHandler;
|
|
||||||
if (useAbstractedPad)
|
|
||||||
switchHandler = std::make_unique<SwitchAbstractedPadHandler>(std::move(controllerPtr));
|
|
||||||
else
|
|
||||||
switchHandler = std::make_unique<SwitchHDLHandler>(std::move(controllerPtr));
|
|
||||||
|
|
||||||
rc = switchHandler->Initialize();
|
|
||||||
if (R_SUCCEEDED(rc))
|
|
||||||
{
|
|
||||||
controllerInterfaces.push_back(std::move(switchHandler));
|
|
||||||
WriteToLog("Interface created successfully");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteToLog("Error creating interface with error ", rc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//On interface change event, check if any devices were removed, and erase them from memory appropriately
|
//On interface change event, check if any devices were removed, and erase them from memory appropriately
|
||||||
rc = eventWait(usbHsGetInterfaceStateChangeEvent(), 0);
|
rc = eventWait(usbHsGetInterfaceStateChangeEvent(), 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user