XInput_Scp/SCPController.cpp (256 lines of code) (raw):

#include "StdAfx.h" CSCPController::CSCPController() { m_bConnected = false; m_xConnected = false; m_Report = NULL; m_deviceId = NULL; m_devicePath = NULL; m_lpHidDevice = NULL; } CSCPController::CSCPController(DWORD dwIndex, DWORD dwReportSize) { m_bConnected = false; m_xConnected = false; m_bReportEnabled = true; m_dwIndex = dwIndex; m_deviceId = NULL; m_devicePath = NULL; m_dwReportSize = dwReportSize; if (m_dwReportSize) m_Report = (BYTE *) calloc(m_dwReportSize, sizeof(BYTE)); else m_Report = NULL; m_lpHidDevice = new HID_DEVICE(); memset(&m_Writer, 0, sizeof(OVERLAPPED)); m_Writer.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); memset(&m_Reader, 0, sizeof(OVERLAPPED)); m_Reader.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); } CSCPController::~CSCPController(void) { if (m_deviceId ) free(m_deviceId); if (m_devicePath) free(m_devicePath); if (m_Report) free(m_Report); Close(); if (m_lpHidDevice) { delete m_lpHidDevice; m_lpHidDevice = NULL; CloseHandle(m_Writer.hEvent); CloseHandle(m_Reader.hEvent); } } SHORT CSCPController::Scale(SHORT Value) { Value -= 0x80; if(Value == -128) Value = -127; return (SHORT) (((float) Value / 127.0f) * 32767.0f); } BOOL CSCPController::Open(void) { PHID_DEVICE lpHidDevice = NULL; ULONG nDevices = 0; DWORD nDevice = 0; FindKnownHidDevices(&lpHidDevice, &nDevices); // Look for our Device for (ULONG nCurrent = 0; nCurrent < nDevices; nCurrent++) { _tstring devicePath(lpHidDevice[nCurrent].DevicePath); if (!m_bConnected && devicePath.find(m_deviceId) != _tstring::npos) { if (nDevice == m_dwIndex) { m_devicePath = _tcsdup(lpHidDevice[nCurrent].DevicePath); init_lib_usb(); if (OpenHidDevice(m_devicePath, true, true, true, false, m_lpHidDevice)) { InitReport(); m_bConnected = m_xConnected = true; _beginthread(ReadThread, 0, this); } } nDevice++; } CloseHidDevice(&lpHidDevice[nCurrent]); } if (lpHidDevice != NULL) free(lpHidDevice); return m_bConnected; } BOOL CSCPController::Close(void) { if (m_bConnected) { m_bConnected = false; if (m_xConnected) { InitReport(); Sleep(100); CloseHidDevice(m_lpHidDevice); } } return !m_bConnected; } DWORD CSCPController::GetState(DWORD dwUserIndex, XINPUT_STATE* pState) { if (m_xConnected) { m_padState.dwPacketNumber++; memcpy(pState, &m_padState, sizeof(XINPUT_STATE)); } return m_xConnected ? ERROR_SUCCESS : ERROR_DEVICE_NOT_CONNECTED; } DWORD CSCPController::SetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration) { if (m_xConnected) { if ((pVibration->wLeftMotorSpeed != m_padVibration.wLeftMotorSpeed) || (pVibration->wRightMotorSpeed != m_padVibration.wRightMotorSpeed)) { m_padVibration.wRightMotorSpeed = pVibration->wRightMotorSpeed; m_padVibration.wLeftMotorSpeed = pVibration->wLeftMotorSpeed; Report(); } } return m_xConnected ? ERROR_SUCCESS : ERROR_DEVICE_NOT_CONNECTED; } DWORD CSCPController::GetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities) { if (m_xConnected) { if (dwFlags == XINPUT_FLAG_GAMEPAD || dwFlags == 0) { memset(pCapabilities, 0, sizeof(XINPUT_CAPABILITIES)); pCapabilities->Flags = XINPUT_CAPS_VOICE_SUPPORTED; pCapabilities->Type = XINPUT_DEVTYPE_GAMEPAD; pCapabilities->SubType = XINPUT_DEVSUBTYPE_GAMEPAD; pCapabilities->Gamepad.wButtons = 0xF3FF; pCapabilities->Gamepad.bLeftTrigger = pCapabilities->Gamepad.bRightTrigger = 0xFF; pCapabilities->Gamepad.sThumbLX = pCapabilities->Gamepad.sThumbLY = pCapabilities->Gamepad.sThumbRX = pCapabilities->Gamepad.sThumbRY = (SHORT) 0xFFC0; pCapabilities->Vibration.wLeftMotorSpeed = pCapabilities->Vibration.wRightMotorSpeed = 0xFF; return ERROR_SUCCESS; } } else { return ERROR_BAD_ARGUMENTS; } return ERROR_DEVICE_NOT_CONNECTED; } DWORD CSCPController::GetDSoundAudioDeviceGuids(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid) { if (m_xConnected) { memset(pDSoundRenderGuid, 0, sizeof(GUID)); memset(pDSoundCaptureGuid, 0, sizeof(GUID)); } return m_xConnected ? ERROR_SUCCESS : ERROR_DEVICE_NOT_CONNECTED; } DWORD CSCPController::GetBatteryInformation(DWORD dwUserIndex, BYTE devType, XINPUT_BATTERY_INFORMATION* pBatteryInformation) { if (m_xConnected) { pBatteryInformation->BatteryType = BATTERY_TYPE_WIRED; pBatteryInformation->BatteryLevel = BATTERY_LEVEL_FULL; } return m_xConnected ? ERROR_SUCCESS : ERROR_DEVICE_NOT_CONNECTED; } DWORD CSCPController::GetKeystroke(DWORD dwUserIndex, DWORD dwReserved, PXINPUT_KEYSTROKE pKeystroke) { return m_xConnected ? ERROR_EMPTY : ERROR_DEVICE_NOT_CONNECTED; } DWORD CSCPController::GetExtended(DWORD dwUserIndex, SCP_EXTN* pPressure) { if (m_xConnected) { memcpy(pPressure, &m_Extended, sizeof(SCP_EXTN)); } return m_xConnected ? ERROR_SUCCESS : ERROR_DEVICE_NOT_CONNECTED;; } BOOL CSCPController::Reopen(void) { init_lib_usb(); if (OpenHidDevice(m_devicePath, true, true, true, false, m_lpHidDevice)) { InitReport(); m_xConnected = true; } return m_xConnected; } BOOL CSCPController::Read(void) { if (m_bConnected) { if(ReadOverlapped(m_lpHidDevice, &m_Reader)) { if (WaitForSingleObject(m_Reader.hEvent, 250) == WAIT_OBJECT_0) { UnpackReport(m_lpHidDevice->InputReportBuffer, m_lpHidDevice->Caps.InputReportByteLength, HidP_Input, m_lpHidDevice->InputData, m_lpHidDevice->InputDataLength, m_lpHidDevice->Ppd); return true; } else { SetEvent(m_Reader.hEvent); } } } return false; } void CSCPController::ReadThread(void *lpController) { CSCPController* Pad = (CSCPController *) lpController; while (Pad->m_bConnected) { if (Pad->Read()) { Pad->m_xConnected = true; Pad->XInputMapState(); } else { Pad->m_xConnected = false; CloseHidDevice(Pad->m_lpHidDevice); do { Sleep(500); } while (Pad->m_bConnected && !Pad->Reopen()); } } _endthread(); } void CSCPController::Report(void) { if (m_bReportEnabled) { DWORD bytesWritten = 0; FormatReport(); if (WaitForSingleObject(m_Writer.hEvent, 100) == WAIT_OBJECT_0) { WriteFile(m_lpHidDevice->HidDevice, m_Report, m_dwReportSize, &bytesWritten, &m_Writer); } else { SetEvent(m_Writer.hEvent); } } } void CSCPController::InitReport(void) { memset(&m_padState, 0, sizeof(XINPUT_STATE)); memset(&m_padVibration, 0, sizeof(XINPUT_VIBRATION)); Report(); } // UNDOCUMENTED DWORD CSCPController::GetStateEx(DWORD dwUserIndex, XINPUT_STATE *pState) { return GetState(m_dwIndex, pState); } DWORD CSCPController::WaitForGuideButton(DWORD dwUserIndex, DWORD dwFlag, LPVOID pVoid) { return m_xConnected ? ERROR_SUCCESS : ERROR_DEVICE_NOT_CONNECTED; } DWORD CSCPController::CancelGuideButtonWait(DWORD dwUserIndex) { return m_xConnected ? ERROR_SUCCESS : ERROR_DEVICE_NOT_CONNECTED; } DWORD CSCPController::PowerOffController(DWORD dwUserIndex) { return m_xConnected ? ERROR_SUCCESS : ERROR_DEVICE_NOT_CONNECTED; }