mirror of
https://github.com/cathery/sys-con.git
synced 2025-03-14 01:27:37 +00:00
Begin implementing Xbox controller
This commit is contained in:
parent
7ae2204070
commit
fc0d3136e3
@ -2,6 +2,7 @@
|
||||
|
||||
#include "Controllers/Xbox360Controller.h"
|
||||
#include "Controllers/Xbox360WirelessController.h"
|
||||
#include "Controllers/XboxController.h"
|
||||
#include "Controllers/XboxOneController.h"
|
||||
#include "Controllers/Dualshock3Controller.h"
|
||||
#include "Controllers/Dualshock4Controller.h"
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "Xbox360Controller.h"
|
||||
|
||||
//References used:
|
||||
//https://cs.chromium.org/chromium/src/device/gamepad/xbox_controller_mac.mm
|
||||
//https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c
|
||||
|
||||
class Xbox360WirelessController : public IController
|
||||
{
|
||||
|
84
ControllerUSB/include/Controllers/XboxController.h
Normal file
84
ControllerUSB/include/Controllers/XboxController.h
Normal file
@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include "IController.h"
|
||||
|
||||
//References used:
|
||||
//http://euc.jp/periphs/xbox-controller.ja.html
|
||||
|
||||
struct XboxButtonData
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
|
||||
bool dpad_up : 1;
|
||||
bool dpad_down : 1;
|
||||
bool dpad_left : 1;
|
||||
bool dpad_right : 1;
|
||||
|
||||
bool start : 1;
|
||||
bool back : 1;
|
||||
bool stick_left_click : 1;
|
||||
bool stick_right_click : 1;
|
||||
|
||||
uint8_t reserved;
|
||||
|
||||
bool a;
|
||||
bool b;
|
||||
bool x;
|
||||
bool y;
|
||||
|
||||
bool black_buttton;
|
||||
bool white_button;
|
||||
|
||||
bool trigger_left;
|
||||
bool trigger_right;
|
||||
|
||||
int16_t stick_left_x;
|
||||
int16_t stick_left_y;
|
||||
int16_t stick_right_x;
|
||||
int16_t stick_right_y;
|
||||
};
|
||||
|
||||
struct XboxRumbleData
|
||||
{
|
||||
uint8_t command;
|
||||
uint8_t size;
|
||||
uint8_t dummy1;
|
||||
uint8_t big;
|
||||
uint8_t dummy2;
|
||||
uint8_t little;
|
||||
};
|
||||
|
||||
class XboxController : public IController
|
||||
{
|
||||
private:
|
||||
IUSBEndpoint *m_inPipe = nullptr;
|
||||
IUSBEndpoint *m_outPipe = nullptr;
|
||||
|
||||
XboxButtonData m_buttonData;
|
||||
|
||||
public:
|
||||
XboxController(std::unique_ptr<IUSBDevice> &&interface);
|
||||
virtual ~XboxController();
|
||||
|
||||
virtual Status Initialize();
|
||||
virtual void Exit();
|
||||
|
||||
Status OpenInterfaces();
|
||||
void CloseInterfaces();
|
||||
|
||||
virtual Status GetInput();
|
||||
|
||||
virtual NormalizedButtonData GetNormalizedButtonData();
|
||||
|
||||
virtual ControllerType GetType() { return CONTROLLER_XBOX360; }
|
||||
|
||||
inline const XboxButtonData &GetButtonData() { return m_buttonData; };
|
||||
|
||||
float NormalizeTrigger(uint8_t value);
|
||||
void NormalizeAxis(int16_t x, int16_t y, uint8_t deadzonePercent, float *x_out, float *y_out);
|
||||
|
||||
Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude);
|
||||
|
||||
static void LoadConfig(const ControllerConfig *config);
|
||||
};
|
@ -38,7 +38,7 @@ Status Dualshock4Controller::OpenInterfaces()
|
||||
if (S_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
//This will open each interface and try to acquire Xbox One controller's in and out endpoints, if it hasn't already
|
||||
//This will open each interface and try to acquire Dualshock 4 controller's in and out endpoints, if it hasn't already
|
||||
std::vector<std::unique_ptr<IUSBInterface>> &interfaces = m_device->GetInterfaces();
|
||||
for (auto &&interface : interfaces)
|
||||
{
|
||||
|
@ -40,7 +40,7 @@ Status Xbox360WirelessController::OpenInterfaces()
|
||||
if (S_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
//This will open each interface and try to acquire Xbox One controller's in and out endpoints, if it hasn't already
|
||||
//This will open each interface and try to acquire Xbox 360 controller's in and out endpoints, if it hasn't already
|
||||
std::vector<std::unique_ptr<IUSBInterface>> &interfaces = m_device->GetInterfaces();
|
||||
for (auto &&interface : interfaces)
|
||||
{
|
||||
|
197
ControllerUSB/source/Controllers/XboxController.cpp
Normal file
197
ControllerUSB/source/Controllers/XboxController.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
#include "Controllers/XboxController.h"
|
||||
#include <cmath>
|
||||
|
||||
static ControllerConfig _xboxControllerConfig{};
|
||||
|
||||
XboxController::XboxController(std::unique_ptr<IUSBDevice> &&interface)
|
||||
: IController(std::move(interface))
|
||||
{
|
||||
}
|
||||
|
||||
XboxController::~XboxController()
|
||||
{
|
||||
Exit();
|
||||
}
|
||||
|
||||
Status XboxController::Initialize()
|
||||
{
|
||||
Status rc;
|
||||
|
||||
rc = OpenInterfaces();
|
||||
if (S_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
void XboxController::Exit()
|
||||
{
|
||||
CloseInterfaces();
|
||||
}
|
||||
|
||||
Status XboxController::OpenInterfaces()
|
||||
{
|
||||
Status rc;
|
||||
rc = m_device->Open();
|
||||
if (S_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
//This will open each interface and try to acquire Xbox controller's in and out endpoints, if it hasn't already
|
||||
std::vector<std::unique_ptr<IUSBInterface>> &interfaces = m_device->GetInterfaces();
|
||||
for (auto &&interface : interfaces)
|
||||
{
|
||||
rc = interface->Open();
|
||||
if (S_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
if (interface->GetDescriptor()->bInterfaceProtocol != 0)
|
||||
continue;
|
||||
|
||||
if (interface->GetDescriptor()->bNumEndpoints < 2)
|
||||
continue;
|
||||
|
||||
if (!m_inPipe)
|
||||
{
|
||||
for (int i = 0; i != 15; ++i)
|
||||
{
|
||||
IUSBEndpoint *inEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_IN, i);
|
||||
if (inEndpoint)
|
||||
{
|
||||
rc = inEndpoint->Open();
|
||||
if (S_FAILED(rc))
|
||||
return 55555;
|
||||
|
||||
m_inPipe = inEndpoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_outPipe)
|
||||
{
|
||||
for (int i = 0; i != 15; ++i)
|
||||
{
|
||||
IUSBEndpoint *outEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_OUT, i);
|
||||
if (outEndpoint)
|
||||
{
|
||||
rc = outEndpoint->Open();
|
||||
if (S_FAILED(rc))
|
||||
return 66666;
|
||||
|
||||
m_outPipe = outEndpoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_inPipe || !m_outPipe)
|
||||
return 69;
|
||||
|
||||
return rc;
|
||||
}
|
||||
void XboxController::CloseInterfaces()
|
||||
{
|
||||
//m_device->Reset();
|
||||
m_device->Close();
|
||||
}
|
||||
|
||||
Status XboxController::GetInput()
|
||||
{
|
||||
uint8_t input_bytes[64];
|
||||
|
||||
Status rc = m_inPipe->Read(input_bytes, sizeof(input_bytes));
|
||||
|
||||
if (S_SUCCEEDED(rc))
|
||||
m_buttonData = *reinterpret_cast<XboxButtonData *>(input_bytes);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void XboxController::NormalizeAxis(int16_t x,
|
||||
int16_t y,
|
||||
uint8_t deadzonePercent,
|
||||
float *x_out,
|
||||
float *y_out)
|
||||
{
|
||||
float x_val = x;
|
||||
float y_val = y;
|
||||
// Determine how far the stick is pushed.
|
||||
//This will never exceed 32767 because if the stick is
|
||||
//horizontally maxed in one direction, vertically it must be neutral(0) and vice versa
|
||||
float real_magnitude = std::sqrt(x_val * x_val + y_val * y_val);
|
||||
float real_deadzone = (32767 * deadzonePercent) / 100;
|
||||
// Check if the controller is outside a circular dead zone.
|
||||
if (real_magnitude > real_deadzone)
|
||||
{
|
||||
// Clip the magnitude at its expected maximum value.
|
||||
float magnitude = std::min(32767.0f, real_magnitude);
|
||||
// Adjust magnitude relative to the end of the dead zone.
|
||||
magnitude -= real_deadzone;
|
||||
// Normalize the magnitude with respect to its expected range giving a
|
||||
// magnitude value of 0.0 to 1.0
|
||||
//ratio = (currentValue / maxValue) / realValue
|
||||
float ratio = (magnitude / (32767 - real_deadzone)) / real_magnitude;
|
||||
// Y is negated because xbox controllers have an opposite sign from
|
||||
// the 'standard controller' recommendations.
|
||||
*x_out = x_val * ratio;
|
||||
*y_out = y_val * ratio;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the controller is in the deadzone zero out the magnitude.
|
||||
*x_out = *y_out = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
//Pass by value should hopefully be optimized away by RVO
|
||||
NormalizedButtonData XboxController::GetNormalizedButtonData()
|
||||
{
|
||||
NormalizedButtonData normalData;
|
||||
|
||||
normalData.triggers[0] = m_buttonData.trigger_left;
|
||||
normalData.triggers[1] = m_buttonData.trigger_right;
|
||||
|
||||
NormalizeAxis(m_buttonData.stick_left_x, m_buttonData.stick_left_y, _xboxControllerConfig.leftStickDeadzonePercent,
|
||||
&normalData.sticks[0].axis_x, &normalData.sticks[0].axis_y);
|
||||
NormalizeAxis(m_buttonData.stick_right_x, m_buttonData.stick_right_y, _xboxControllerConfig.rightStickDeadzonePercent,
|
||||
&normalData.sticks[1].axis_x, &normalData.sticks[1].axis_y);
|
||||
|
||||
bool buttons[NUM_CONTROLLERBUTTONS]{
|
||||
m_buttonData.y,
|
||||
m_buttonData.b,
|
||||
m_buttonData.a,
|
||||
m_buttonData.x,
|
||||
m_buttonData.stick_left_click,
|
||||
m_buttonData.stick_right_click,
|
||||
false,
|
||||
false,
|
||||
m_buttonData.trigger_left,
|
||||
m_buttonData.trigger_right,
|
||||
m_buttonData.back,
|
||||
m_buttonData.start,
|
||||
m_buttonData.dpad_up,
|
||||
m_buttonData.dpad_right,
|
||||
m_buttonData.dpad_down,
|
||||
m_buttonData.dpad_left,
|
||||
m_buttonData.white_button,
|
||||
m_buttonData.black_buttton,
|
||||
};
|
||||
|
||||
for (int i = 0; i != NUM_CONTROLLERBUTTONS; ++i)
|
||||
{
|
||||
ControllerButton button = _xboxControllerConfig.buttons[i];
|
||||
normalData.buttons[(button != NOT_SET ? button : i)] = buttons[i];
|
||||
}
|
||||
|
||||
return normalData;
|
||||
}
|
||||
|
||||
Status XboxController::SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude)
|
||||
{
|
||||
uint8_t rumbleData[]{0x00, 0x06, 0x00, strong_magnitude, weak_magnitude, 0x00, 0x00, 0x00};
|
||||
return m_outPipe->Write(rumbleData, sizeof(rumbleData));
|
||||
}
|
||||
void XboxController::LoadConfig(const ControllerConfig *config)
|
||||
{
|
||||
_xboxControllerConfig = *config;
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
|
||||
#define GLOBALCONFIG "config_global.ini"
|
||||
|
||||
#define XBOXCONFIG "config_xboxorig.ini"
|
||||
#define XBOX360CONFIG "config_xbox360.ini"
|
||||
#define XBOXONECONFIG "config_xboxone.ini"
|
||||
#define DUALSHOCK3CONFIG "config_dualshock3.ini"
|
||||
@ -102,6 +103,13 @@ static Result _ReadFromConfig(const char *path)
|
||||
|
||||
void LoadAllConfigs()
|
||||
{
|
||||
if (R_SUCCEEDED(_ReadFromConfig(CONFIG_PATH XBOXCONFIG)))
|
||||
{
|
||||
XboxController::LoadConfig(&temp_config);
|
||||
}
|
||||
else
|
||||
WriteToLog("Failed to read from xbox orig config!");
|
||||
|
||||
if (R_SUCCEEDED(_ReadFromConfig(CONFIG_PATH XBOXONECONFIG)))
|
||||
XboxOneController::LoadConfig(&temp_config);
|
||||
else
|
||||
@ -131,6 +139,7 @@ bool CheckForFileChanges()
|
||||
bool filesChanged = false;
|
||||
|
||||
static time_t globalConfigLastModified;
|
||||
static time_t xboxConfigLastModified;
|
||||
static time_t xbox360ConfigLastModified;
|
||||
static time_t xboxOneConfigLastModified;
|
||||
static time_t dualshock3ConfigLastModified;
|
||||
@ -144,6 +153,13 @@ bool CheckForFileChanges()
|
||||
filesChanged = true;
|
||||
}
|
||||
|
||||
if (stat(CONFIG_PATH XBOXCONFIG, &result) == 0)
|
||||
if (xboxConfigLastModified != result.st_mtime)
|
||||
{
|
||||
xboxConfigLastModified = result.st_mtime;
|
||||
filesChanged = true;
|
||||
}
|
||||
|
||||
if (stat(CONFIG_PATH XBOX360CONFIG, &result) == 0)
|
||||
if (xbox360ConfigLastModified != result.st_mtime)
|
||||
{
|
||||
|
@ -34,8 +34,8 @@ Result mainLoop()
|
||||
Result rc = 0;
|
||||
bool useAbstractedPad = hosversionBetween(5, 7);
|
||||
|
||||
Event xinputEvent;
|
||||
Event dinputEvent;
|
||||
Event catchAllEvent;
|
||||
Event ds3Event;
|
||||
std::vector<std::unique_ptr<SwitchVirtualGamepadHandler>> controllerInterfaces;
|
||||
|
||||
UTimer filecheckTimer;
|
||||
@ -47,13 +47,13 @@ Result mainLoop()
|
||||
|
||||
{
|
||||
UsbHsInterfaceFilter filter;
|
||||
filter.Flags = UsbHsInterfaceFilterFlags_bInterfaceClass;
|
||||
filter.bInterfaceClass = USB_CLASS_VENDOR_SPEC;
|
||||
rc = usbHsCreateInterfaceAvailableEvent(&xinputEvent, true, 0, &filter);
|
||||
filter.Flags = UsbHsInterfaceFilterFlags_bcdDevice_Min;
|
||||
filter.bcdDevice_Min = 0;
|
||||
rc = usbHsCreateInterfaceAvailableEvent(&catchAllEvent, true, 0, &filter);
|
||||
if (R_FAILED(rc))
|
||||
WriteToLog("Failed to open event for XInput");
|
||||
WriteToLog("Failed to open catch-all event");
|
||||
else
|
||||
WriteToLog("Successfully created event for XInput");
|
||||
WriteToLog("Successfully created catch-all event");
|
||||
|
||||
//filter.Flags = UsbHsInterfaceFilterFlags_bInterfaceClass | UsbHsInterfaceFilterFlags_bcdDevice_Min;
|
||||
//filter.bInterfaceClass = USB_CLASS_HID;
|
||||
@ -61,11 +61,11 @@ Result mainLoop()
|
||||
filter.Flags = UsbHsInterfaceFilterFlags_idVendor | UsbHsInterfaceFilterFlags_idProduct;
|
||||
filter.idVendor = VENDOR_SONY;
|
||||
filter.idProduct = PRODUCT_DUALSHOCK3;
|
||||
rc = usbHsCreateInterfaceAvailableEvent(&dinputEvent, true, 1, &filter);
|
||||
rc = usbHsCreateInterfaceAvailableEvent(&ds3Event, true, 1, &filter);
|
||||
if (R_FAILED(rc))
|
||||
WriteToLog("Failed to open event for DInput");
|
||||
WriteToLog("Failed to open event for Dualshock 3");
|
||||
else
|
||||
WriteToLog("Successfully created event for DInput");
|
||||
WriteToLog("Successfully created event for Dualshock 3");
|
||||
}
|
||||
|
||||
controllerInterfaces.reserve(8);
|
||||
@ -82,10 +82,10 @@ Result mainLoop()
|
||||
if (kDown & KEY_B)
|
||||
break;
|
||||
#endif
|
||||
rc = eventWait(&xinputEvent, 0);
|
||||
rc = eventWait(&catchAllEvent, 0);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
WriteToLog("XInput went off");
|
||||
WriteToLog("Catch-all event went off");
|
||||
UsbHsInterface interfaces[8];
|
||||
s32 total_entries;
|
||||
|
||||
@ -101,6 +101,12 @@ Result mainLoop()
|
||||
devicePtr = std::make_unique<SwitchUSBDevice>(interfaces, total_entries);
|
||||
controllerPtr = std::make_unique<Xbox360WirelessController>(std::move(devicePtr));
|
||||
}
|
||||
else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, 0x58, 0x42, 0x00)))
|
||||
{
|
||||
WriteToLog("Registering Xbox One controller");
|
||||
devicePtr = std::make_unique<SwitchUSBDevice>(interfaces, total_entries);
|
||||
controllerPtr = std::make_unique<XboxController>(std::move(devicePtr));
|
||||
}
|
||||
else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_VENDOR_SPEC, 71, 208)))
|
||||
{
|
||||
WriteToLog("Registering Xbox One controller");
|
||||
@ -108,10 +114,10 @@ Result mainLoop()
|
||||
controllerPtr = std::make_unique<XboxOneController>(std::move(devicePtr));
|
||||
}
|
||||
}
|
||||
rc = eventWait(&dinputEvent, 0);
|
||||
rc = eventWait(&ds3Event, 0);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
WriteToLog("DInput went off");
|
||||
WriteToLog("Dualshock 3 event went off");
|
||||
UsbHsInterface interfaces[4];
|
||||
s32 total_entries;
|
||||
|
||||
@ -203,8 +209,8 @@ Result mainLoop()
|
||||
|
||||
//After we break out of the loop, close all events and exit
|
||||
WriteToLog("Destroying events");
|
||||
usbHsDestroyInterfaceAvailableEvent(&xinputEvent, 0);
|
||||
usbHsDestroyInterfaceAvailableEvent(&dinputEvent, 1);
|
||||
usbHsDestroyInterfaceAvailableEvent(&catchAllEvent, 0);
|
||||
usbHsDestroyInterfaceAvailableEvent(&ds3Event, 1);
|
||||
|
||||
//controllerInterfaces.clear();
|
||||
return rc;
|
||||
|
Loading…
x
Reference in New Issue
Block a user