Skip to content

Commit

Permalink
Begin implementing Xbox controller
Browse files Browse the repository at this point in the history
  • Loading branch information
cathery committed Nov 8, 2019
1 parent 7ae2204 commit fc0d313
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 19 deletions.
1 change: 1 addition & 0 deletions ControllerUSB/include/Controllers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
84 changes: 84 additions & 0 deletions ControllerUSB/include/Controllers/XboxController.h
Original file line number Diff line number Diff line change
@@ -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);
};
2 changes: 1 addition & 1 deletion ControllerUSB/source/Controllers/Dualshock4Controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
197 changes: 197 additions & 0 deletions ControllerUSB/source/Controllers/XboxController.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
16 changes: 16 additions & 0 deletions source/configFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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)
{
Expand Down
Loading

0 comments on commit fc0d313

Please sign in to comment.