Created
November 26, 2020 20:37
-
-
Save charlie-x/c42655120e81716e4ff580bec0b3d205 to your computer and use it in GitHub Desktop.
kmotion dinput starter
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
#include "stdafx.h" | |
#define DIRECTINPUT_VERSION 0x0700 | |
#include <wbemidl.h> | |
#include <dinput.h> | |
#include <xinput.h> | |
#pragma comment(lib,"xinput.lib") | |
#define SAFE_RELEASE(x) if(x) { x->Release(); x = NULL; } | |
//------------------------ | |
// Enum each PNP device using WMI and check each device ID to see if it contains | |
// "IG_" (ex. "VID_045E&PID_028E&IG_00"). If it does, then it's an XInput device | |
// Unfortunately this information can not be found by just using DirectInput | |
//----------------------------------------------------------------------------- | |
static BOOL IsXInputDevice(const GUID* pGuidProductFromDirectInput) | |
{ | |
IWbemLocator* pIWbemLocator = NULL; | |
IEnumWbemClassObject* pEnumDevices = NULL; | |
IWbemClassObject* pDevices[20] = { 0 }; | |
IWbemServices* pIWbemServices = NULL; | |
BSTR bstrNamespace = NULL; | |
BSTR bstrDeviceID = NULL; | |
BSTR bstrClassName = NULL; | |
DWORD uReturned = 0; | |
bool bIsXinputDevice = false; | |
UINT iDevice = 0; | |
VARIANT var; | |
HRESULT hr; | |
// CoInit if needed | |
hr = CoInitialize(NULL); | |
bool bCleanupCOM = SUCCEEDED(hr); | |
// So we can call VariantClear() later, even if we never had a successful IWbemClassObject::Get(). | |
VariantInit(&var); | |
// Create WMI | |
hr = CoCreateInstance(__uuidof(WbemLocator), | |
NULL, | |
CLSCTX_INPROC_SERVER, | |
__uuidof(IWbemLocator), | |
(LPVOID*)&pIWbemLocator); | |
if (FAILED(hr) || pIWbemLocator == NULL) | |
goto LCleanup; | |
bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == NULL) goto LCleanup; | |
bstrClassName = SysAllocString(L"Win32_PNPEntity"); if (bstrClassName == NULL) goto LCleanup; | |
bstrDeviceID = SysAllocString(L"DeviceID"); if (bstrDeviceID == NULL) goto LCleanup; | |
// Connect to WMI | |
hr = pIWbemLocator->ConnectServer(bstrNamespace, NULL, NULL, 0L, | |
0L, NULL, NULL, &pIWbemServices); | |
if (FAILED(hr) || pIWbemServices == NULL) | |
goto LCleanup; | |
// Switch security level to IMPERSONATE. | |
CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, | |
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); | |
hr = pIWbemServices->CreateInstanceEnum(bstrClassName, 0, NULL, &pEnumDevices); | |
if (FAILED(hr) || pEnumDevices == NULL) | |
goto LCleanup; | |
// Loop over all devices | |
for (;; ) | |
{ | |
// Get 20 at a time | |
hr = pEnumDevices->Next(10000, 20, pDevices, &uReturned); | |
if (FAILED(hr)) | |
goto LCleanup; | |
if (uReturned == 0) | |
break; | |
for (iDevice = 0; iDevice < uReturned; iDevice++) | |
{ | |
// For each device, get its device ID | |
hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, NULL, NULL); | |
if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) | |
{ | |
// Check if the device ID contains "IG_". If it does, then it's an XInput device | |
// This information can not be found from DirectInput | |
if (wcsstr(var.bstrVal, L"IG_")) | |
{ | |
// If it does, then get the VID/PID from var.bstrVal | |
DWORD dwPid = 0, dwVid = 0; | |
WCHAR* strVid = wcsstr(var.bstrVal, L"VID_"); | |
if (strVid && swscanf(strVid, L"VID_%4X", &dwVid) != 1) | |
dwVid = 0; | |
WCHAR* strPid = wcsstr(var.bstrVal, L"PID_"); | |
if (strPid && swscanf(strPid, L"PID_%4X", &dwPid) != 1) | |
dwPid = 0; | |
// Compare the VID/PID to the DInput device | |
DWORD dwVidPid = MAKELONG(dwVid, dwPid); | |
if (dwVidPid == pGuidProductFromDirectInput->Data1) | |
{ | |
bIsXinputDevice = true; | |
goto LCleanup; | |
} | |
} | |
} | |
VariantClear(&var); | |
SAFE_RELEASE(pDevices[iDevice]); | |
} | |
} | |
LCleanup: | |
VariantClear(&var); | |
if (bstrNamespace) | |
SysFreeString(bstrNamespace); | |
if (bstrDeviceID) | |
SysFreeString(bstrDeviceID); | |
if (bstrClassName) | |
SysFreeString(bstrClassName); | |
for (iDevice = 0; iDevice < 20; iDevice++) | |
SAFE_RELEASE(pDevices[iDevice]); | |
SAFE_RELEASE(pEnumDevices); | |
SAFE_RELEASE(pIWbemLocator); | |
SAFE_RELEASE(pIWbemServices); | |
if (bCleanupCOM) | |
CoUninitialize(); | |
return bIsXinputDevice; | |
} | |
// EnumJoysticksCallback() | |
// Called once for each enumerated joystick. If we find one, create a | |
// device interface on it so we can play with it. | |
BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, | |
VOID* pContext) | |
{ | |
HRESULT hr; | |
if (IsXInputDevice(&pdidInstance->guidProduct)) | |
return DIENUM_CONTINUE; | |
// Device is verified not XInput, so add it to the list of DInput devices | |
return DIENUM_CONTINUE; | |
} | |
// Check deadzone on left thumbstick | |
static bool LStickInDeadzone(XINPUT_STATE& state) | |
{ | |
short x = state.Gamepad.sThumbLX; | |
short y = state.Gamepad.sThumbLY; | |
if (x > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE || | |
x < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) | |
{ | |
// X axis outside of deadzone | |
return false; | |
} | |
if (y > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE || | |
y < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) | |
{ | |
// Y axis outside of deadzone | |
return false; | |
} | |
// One (or both) axis inside deadzone | |
return true; | |
} | |
// Check deadzone on right thumbstick | |
static bool RStickInDeadzone(XINPUT_STATE& state) | |
{ | |
short x = state.Gamepad.sThumbRX; | |
short y = state.Gamepad.sThumbRY; | |
if (x > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE || | |
x < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) | |
{ | |
// X axis outside of deadzone | |
return false; | |
} | |
if (y > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE || | |
y < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) | |
{ | |
// Y axis outside of deadzone | |
return false; | |
} | |
// One (or both) axis inside deadzone | |
return true; | |
} | |
// calculate deadzones for analog inputs (alternate with normalise) | |
void CalculateDeadZone(XINPUT_STATE& state, const int deadZone) | |
{ | |
float LX = state.Gamepad.sThumbLX; | |
float LY = state.Gamepad.sThumbLY; | |
//determine how far the controller is pushed | |
float magnitude = sqrt(LX * LX + LY * LY); | |
//determine the direction the controller is pushed | |
float normalizedLX = LX / magnitude; | |
float normalizedLY = LY / magnitude; | |
float normalizedMagnitude = 0; | |
//check if the controller is outside a circular dead zone | |
if (magnitude > deadZone) | |
{ | |
//clip the magnitude at its expected maximum value | |
if (magnitude > 32767) magnitude = 32767; | |
//adjust magnitude relative to the end of the dead zone | |
magnitude -= deadZone; | |
//optionally normalize the magnitude with respect to its expected range | |
//giving a magnitude value of 0.0 to 1.0 | |
normalizedMagnitude = magnitude / (32767 - deadZone); | |
} | |
else //if the controller is in the deadzone zero out the magnitude | |
{ | |
magnitude = 0.0; | |
normalizedMagnitude = 0.0; | |
} | |
} | |
// SetVibrate() | |
// Control vibration motors on GamePad | |
// | |
// @index = controller index 0 .. XUSER_MAX_COUNT | |
// @leftValue = 0 .. 65535 left vibration amount | |
// @rightValue = 0 .. 65535 right vibration amount | |
void SetVibrate(DWORD index, unsigned short leftValue, unsigned short rightValue) | |
{ | |
XINPUT_VIBRATION vibration; | |
ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); | |
vibration.wLeftMotorSpeed = leftValue; | |
vibration.wRightMotorSpeed = rightValue; | |
XInputSetState(index, &vibration); | |
} | |
MMRESULT WINAPI myjoyGetPosEx(_In_ UINT uJoyID, _Out_ LPJOYINFOEX pji) | |
{ | |
// this will return all ok for an XInput device that fails to run joystick info as well. | |
// the enumerate should skip XInput devices | |
if (joyGetPosEx(uJoyID, pji) == JOYERR_NOERROR) { | |
//return JOYERR_NOERROR; | |
} | |
XINPUT_STATE state; | |
ZeroMemory(&state, sizeof(XINPUT_STATE)); | |
DWORD dwResult = XInputGetState(uJoyID, &state); | |
if (dwResult == ERROR_SUCCESS) { | |
// map Xinput to exJoy | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) { | |
pji->dwButtons |= JOY_BUTTON1; | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) { | |
pji->dwButtons |= JOY_BUTTON2; | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) { | |
pji->dwButtons |= JOY_BUTTON3; | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) { | |
pji->dwButtons |= JOY_BUTTON4; | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) { | |
pji->dwButtons |= JOY_BUTTON5; | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) { | |
pji->dwButtons |= JOY_BUTTON6; | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) { | |
pji->dwButtons |= JOY_BUTTON7; | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) { | |
pji->dwButtons |= JOY_BUTTON8; | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) { | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) { | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) { | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) { | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) { | |
} | |
if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) { | |
} | |
// other analog inputs | |
// state.Gamepad.sThumbLX | |
// state.Gamepad.sThumbLY | |
// state.Gamepad.sThumbRX | |
// state.Gamepad.sThumbRY | |
const DWORD jScale = 32768; | |
if (!LStickInDeadzone(state)) { | |
// convert from - / + to 0 - 65536 | |
pji->dwRpos = ((state.Gamepad.sThumbLX) + 32768) / jScale; | |
pji->dwZpos = ((state.Gamepad.sThumbLY) + 32768) / jScale; | |
} | |
else { | |
pji->dwRpos = 32767; | |
pji->dwZpos = 32767; | |
} | |
if (!RStickInDeadzone(state)) { | |
pji->dwXpos = ((state.Gamepad.sThumbRX) + 32768) / jScale; | |
pji->dwYpos = ((state.Gamepad.sThumbRY) + 32768) / jScale; | |
} | |
else { | |
pji->dwXpos = 32767; | |
pji->dwYpos = 32767; | |
} | |
return JOYERR_NOERROR; | |
} | |
return JOYERR_NOCANDO; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment