Skip to content
This repository has been archived by the owner on Jun 23, 2018. It is now read-only.

Commit

Permalink
Getting Information from device
Browse files Browse the repository at this point in the history
Added a global variable (XINPUT_GAMEPAD g_Gamepad[MAX_NUMBER_XBOX_CTRLS]) that holds the updadted device posision (Array of 4 devices)
Adde an  internal function (InitAllGamePads) that initializes all 4 gamepad positions.
Added an internal function (XOutputSetGetState) that writes device position and gets info from device
Modified interface function XOutputSetState() - it now modifies g_Gamepad[] and calls  internal function XOutputSetGetState()
Added Interface function: XoutputGetVibration()
Added Interface function: XoutputGetLedNumber()
Tester changed:  It now supports LED and Vibration
  • Loading branch information
shauleiz committed May 30, 2016
1 parent 5b9bc28 commit 49f7578
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 88 deletions.
26 changes: 22 additions & 4 deletions XOutput/Tester/Tester.cpp
Expand Up @@ -66,15 +66,33 @@ int main()
printf("Hit any key to continue\n\n");
getchar();

BYTE Led0, Led2;
result = XoutputGetLedNumber(2, &Led2);
printf("XoutputGetLedNumber(2): Led=%d; Return 0x%x\n", Led2, result);

XINPUT_GAMEPAD Gamepad = { 0 };
Gamepad.wButtons = 0x1;
XOutputSetState(2, &Gamepad);


Gamepad.wButtons = 0x2;
XOutputSetState(0, &Gamepad);
result = XoutputGetLedNumber(0, &Led0);
printf("XoutputGetLedNumber(0): Led=%d; Return 0x%x\n", Led0, result);

printf("Hit any key to continue - Testing vibrator-motors\n\n");
getchar();

XINPUT_VIBRATION vib0, vib2;

BYTE bVibrate[4], bLargeMotor[4], bSmallMotor[4], bLed[4];
XOutputGetState(0, &(bVibrate[0]), &(bLargeMotor[0]), &(bSmallMotor[0]), &(bLed[0]));
XOutputGetState(2, &(bVibrate[2]), &(bLargeMotor[2]), &(bSmallMotor[2]), &(bLed[2]));
result = XoutputGetVibration(0, &vib0);
printf("XoutputGetVibration(0): Left Motor:%d; Right Motor:%d; Return 0x%x\n", vib0.wLeftMotorSpeed, vib0.wRightMotorSpeed, result);
result = XoutputGetVibration(2, &vib2);
printf("XoutputGetVibration(2): Left Motor:%d; Right Motor:%d; Return 0x%x\n", vib2.wLeftMotorSpeed, vib2.wRightMotorSpeed, result);

printf("Hit any key to Exit\n\n");
getchar();

return 0;
return 0;
}

248 changes: 165 additions & 83 deletions XOutput/XOutput.cpp
Expand Up @@ -11,10 +11,18 @@
#include <SetupAPI.h>
#include <IoCtrl.h>

#define MAX_NUMBER_XBOX_CTRLS 4
#define FEEDBACK_BUFFER_LENGTH 9
static BYTE g_Feedback[XUSER_MAX_COUNT][FEEDBACK_BUFFER_LENGTH] = {};
std::once_flag initFlag;
HANDLE g_hScpVBus = INVALID_HANDLE_VALUE;
XINPUT_GAMEPAD g_Gamepad[MAX_NUMBER_XBOX_CTRLS];

/// Forward declarations of internal functions
void InitAllGamePads(void);
DWORD XOutputSetGetState(DWORD dwUserIndex, XINPUT_GAMEPAD * pGamepad, PBYTE bVibrate, PBYTE bLargeMotor, PBYTE bSmallMotor, PBYTE bLed);
DWORD XOutputUnPlug_Internal(DWORD dwUserIndex, BOOL bForce);


///-------------------------------------------------------------------------------------------------
/// <summary> Attempts to find and open the first instance of the virtual bus. </summary>
Expand All @@ -33,6 +41,8 @@ void Initialize()
DWORD memberIndex = 0;
DWORD requiredSize = 0;

InitAllGamePads();

auto deviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_SCPVBUS, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

while (SetupDiEnumDeviceInterfaces(deviceInfoSet, nullptr, &GUID_DEVINTERFACE_SCPVBUS, memberIndex, &deviceInterfaceData))
Expand Down Expand Up @@ -124,55 +134,36 @@ DWORD XOutputGetDriverPackageVersion(PDWORDLONG Version)

DWORD XOutputSetState(DWORD dwUserIndex, XINPUT_GAMEPAD* pGamepad)
{
Initialize();

if (VBUS_NOT_INITIALIZED())
{
return XOUTPUT_VBUS_NOT_CONNECTED;
}

if (USER_INDEX_OUT_OF_RANGE(dwUserIndex))
{
return XOUTPUT_VBUS_INDEX_OUT_OF_RANGE;
}

if (pGamepad == nullptr)
{
return XOUTPUT_VBUS_INVALID_STATE_INFO;
}

DWORD trasfered = 0;
BYTE buffer[28] = {};
auto busIndex = dwUserIndex + 1;
// Save last position data
memcpy_s(&g_Gamepad[dwUserIndex], sizeof(XINPUT_GAMEPAD), pGamepad, sizeof(XINPUT_GAMEPAD));

buffer[0] = 0x1C;

// encode user index
buffer[4] = ((busIndex >> 0) & 0xFF);
buffer[5] = ((busIndex >> 8) & 0xFF);
buffer[6] = ((busIndex >> 16) & 0xFF);
buffer[7] = ((busIndex >> 24) & 0xFF);

buffer[9] = 0x14;

// concat gamepad info to buffer
memcpy_s(&buffer[10], _countof(buffer), pGamepad, sizeof(XINPUT_GAMEPAD));

// vibration and LED info end up here
BYTE output[FEEDBACK_BUFFER_LENGTH] = {};

// send report to bus, receive vibration and LED status
auto retval = DeviceIoControl(g_hScpVBus, IOCTL_BUSENUM_REPORT_HARDWARE, buffer, _countof(buffer), output, FEEDBACK_BUFFER_LENGTH, &trasfered, nullptr);

if (DEVICE_IO_CONTROL_FAILED(retval))
{
return XOUTPUT_VBUS_IOCTL_REQUEST_FAILED;
}
// Set State
return XOutputSetGetState(dwUserIndex, pGamepad, NULL, NULL, NULL, NULL);
}

// cache feedback
memcpy_s(g_Feedback[dwUserIndex], FEEDBACK_BUFFER_LENGTH, output, FEEDBACK_BUFFER_LENGTH);
DWORD XoutputGetLedNumber(DWORD dwUserIndex, PBYTE bLed)
{
DWORD retval = XOutputSetGetState(dwUserIndex, &g_Gamepad[dwUserIndex], nullptr, nullptr, nullptr, bLed);
if (retval == ERROR_SUCCESS)
(*bLed)++;
return retval;
}

return ERROR_SUCCESS;
DWORD XoutputGetVibration(UINT dwUserIndex, PXINPUT_VIBRATION pVib)
{
BYTE LargeMotor, SmallMotor, Vibrate;
DWORD retval = XOutputSetGetState(dwUserIndex, &g_Gamepad[dwUserIndex], &Vibrate, &LargeMotor, &SmallMotor, nullptr);
if (retval == ERROR_SUCCESS)
{
if (Vibrate)
{
(*pVib).wLeftMotorSpeed = LargeMotor * 256;
(*pVib).wRightMotorSpeed = SmallMotor * 256;
}
else
(*pVib).wLeftMotorSpeed = (*pVib).wRightMotorSpeed = 0;
};
return retval;
}

DWORD XOutputGetState(DWORD dwUserIndex, PBYTE bVibrate, PBYTE bLargeMotor, PBYTE bSmallMotor, PBYTE bLed)
Expand Down Expand Up @@ -266,42 +257,6 @@ DWORD XOutputPlugIn(DWORD dwUserIndex)
return ERROR_SUCCESS;
}

DWORD XOutputUnPlug_Internal(DWORD dwUserIndex, BOOL bForce)
{
Initialize();

if (VBUS_NOT_INITIALIZED())
{
return XOUTPUT_VBUS_NOT_CONNECTED;
}

if (USER_INDEX_OUT_OF_RANGE(dwUserIndex))
{
return XOUTPUT_VBUS_INDEX_OUT_OF_RANGE;
}

DWORD trasfered = 0;
BUSENUM_UNPLUG_HARDWARE buffer = {};
auto busIndex = dwUserIndex + 1;

buffer.Size = sizeof(BUSENUM_UNPLUG_HARDWARE);
buffer.SerialNo = busIndex;

if (bForce)
buffer.Flags = 0x0001;
else
buffer.Flags = 0x0000;

auto retval = DeviceIoControl(g_hScpVBus, IOCTL_BUSENUM_UNPLUG_HARDWARE, static_cast<LPVOID>(&buffer), buffer.Size, nullptr, 0, &trasfered, nullptr);

if (DEVICE_IO_CONTROL_FAILED(retval))
{
return XOUTPUT_VBUS_IOCTL_REQUEST_FAILED;
}

return ERROR_SUCCESS;
}

DWORD XOutputUnPlug(DWORD dwUserIndex)
{
return XOutputUnPlug_Internal(dwUserIndex, FALSE);
Expand Down Expand Up @@ -522,4 +477,131 @@ DWORD XOutputGetBusVersion(PDWORD Version)
}

return ERROR_SUCCESS;
}
}

///-------------------------------------------------------------------------------------------------
/// <summary> Initialize all structures holding gamepad status </summary>
///
/// <remarks>
/// Called once from within Initialize()
/// </remarks>
///-------------------------------------------------------------------------------------------------
void InitAllGamePads(void)
{
for (auto pad : g_Gamepad)
{
pad.bLeftTrigger = 0;
pad.bRightTrigger = 0;
pad.sThumbLX = 0;
pad.sThumbLY = 0;
pad.sThumbRX = 0;
pad.sThumbRY = 0;
pad.wButtons = 0;
}
}

DWORD XOutputSetGetState(DWORD dwUserIndex, XINPUT_GAMEPAD * pGamepad, PBYTE bVibrate, PBYTE bLargeMotor, PBYTE bSmallMotor, PBYTE bLed)
{
Initialize();

if (VBUS_NOT_INITIALIZED())
{
return XOUTPUT_VBUS_NOT_CONNECTED;
}

if (USER_INDEX_OUT_OF_RANGE(dwUserIndex))
{
return XOUTPUT_VBUS_INDEX_OUT_OF_RANGE;
}

if (pGamepad == nullptr)
{
return XOUTPUT_VBUS_INVALID_STATE_INFO;
}

DWORD trasfered = 0;
BYTE buffer[28] = {};
auto busIndex = dwUserIndex + 1;

buffer[0] = 0x1C;

// encode user index
buffer[4] = ((busIndex >> 0) & 0xFF);
buffer[5] = ((busIndex >> 8) & 0xFF);
buffer[6] = ((busIndex >> 16) & 0xFF);
buffer[7] = ((busIndex >> 24) & 0xFF);

buffer[9] = 0x14;

// concat gamepad info to buffer
memcpy_s(&buffer[10], _countof(buffer), pGamepad, sizeof(XINPUT_GAMEPAD));

// vibration and LED info end up here
BYTE output[FEEDBACK_BUFFER_LENGTH] = {};

// send report to bus, receive vibration and LED status
auto retval = DeviceIoControl(g_hScpVBus, IOCTL_BUSENUM_REPORT_HARDWARE, buffer, _countof(buffer), output, FEEDBACK_BUFFER_LENGTH, &trasfered, nullptr);
if (DEVICE_IO_CONTROL_FAILED(retval))
{
return XOUTPUT_VBUS_IOCTL_REQUEST_FAILED;
}

// Feedback
if (bVibrate != nullptr)
{
*bVibrate = (output[1] == 0x08) ? 0x01 : 0x00;
}

if (bLargeMotor != nullptr)
{
*bLargeMotor = output[3];
}

if (bSmallMotor != nullptr)
{
*bSmallMotor = output[4];
}

if (bLed != nullptr)
{
*bLed = output[8];
}

return ERROR_SUCCESS;
}

DWORD XOutputUnPlug_Internal(DWORD dwUserIndex, BOOL bForce)
{
Initialize();

if (VBUS_NOT_INITIALIZED())
{
return XOUTPUT_VBUS_NOT_CONNECTED;
}

if (USER_INDEX_OUT_OF_RANGE(dwUserIndex))
{
return XOUTPUT_VBUS_INDEX_OUT_OF_RANGE;
}

DWORD trasfered = 0;
BUSENUM_UNPLUG_HARDWARE buffer = {};
auto busIndex = dwUserIndex + 1;

buffer.Size = sizeof(BUSENUM_UNPLUG_HARDWARE);
buffer.SerialNo = busIndex;

if (bForce)
buffer.Flags = 0x0001;
else
buffer.Flags = 0x0000;

auto retval = DeviceIoControl(g_hScpVBus, IOCTL_BUSENUM_UNPLUG_HARDWARE, static_cast<LPVOID>(&buffer), buffer.Size, nullptr, 0, &trasfered, nullptr);

if (DEVICE_IO_CONTROL_FAILED(retval))
{
return XOUTPUT_VBUS_IOCTL_REQUEST_FAILED;
}

return ERROR_SUCCESS;
}
58 changes: 57 additions & 1 deletion XOutput/XOutput.h
Expand Up @@ -10,7 +10,7 @@
/***************************************************************************
* *
* How to use this header file to compile your application: *
* There are 3 regions: *
* This header file has 3 regions: *
* 1. Compilation mode - sets the type of the compilation target *
* 2. Error Codes *
* 3. Interface Functions *
Expand Down Expand Up @@ -160,6 +160,62 @@ extern "C"
_Out_ DWORD* dwRealIndex
);

///-------------------------------------------------------------------------------------------------
/// <summary>
/// Retrieves the assigned LED number specified virtual controller.
/// </summary>
///
/// <remarks>
/// The device index used internally on the virtual bus does not reflect the index used by the
/// XInput API.
/// This function returns the value assigned to the device by the system.
/// Value range: From 1 to 4.
///
/// This function fails if the supplied user index represents an unplugged device or a device owned by
/// another process.
/// </remarks>
///
/// <param name="dwUserIndex"> Index of the virtual controller. Can be a value from 0 to 3. </param>
/// <param name="bLed"> [out] Pointer to a BYTE value receiving LED number </param>
///
/// <returns>
/// If the function succeeds, the return value is ERROR_SUCCESS.
///
/// If the function fails, the return value is an error code defined in XOutput.h. The function
/// does not use SetLastError to set the calling thread's last-error code.
/// </returns>
///-------------------------------------------------------------------------------------------------
XOUTPUT_API DWORD XoutputGetLedNumber(
_In_ DWORD dwUserIndex,
_Out_ PBYTE bLed
);



///-------------------------------------------------------------------------------------------------
/// <summary> Retrieves the current vibration state of the specified virtual controller. </summary>
///
/// <remarks>
/// This function fails if the supplied user index represents an
/// unplugged device or a device owned by another process.
/// </remarks>
///
/// <param name="dwUserIndex"> Index of the virtual controller. Can be a value from 0 to 3. </param>
/// <param name="pVib"> Pointer to XINPUT_VIBRATION structure that holds vibration data for both
/// Left and Right motors.
///
/// <returns>
/// If the function succeeds, the return value is ERROR_SUCCESS.
///
/// If the function fails, the return value is an error code defined in XOutput.h. The function
/// does not use SetLastError to set the calling thread's last-error code.
/// </returns>
///-------------------------------------------------------------------------------------------------
XOUTPUT_API DWORD XoutputGetVibration(
_In_ UINT dwUserIndex,
_Out_ PXINPUT_VIBRATION pVib
);

///-------------------------------------------------------------------------------------------------
/// <summary> Requests the bus driver to attach a virtual controller. </summary>
///
Expand Down

0 comments on commit 49f7578

Please sign in to comment.