-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
323 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.