Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1458)

Unified Diff: content/browser/gamepad/gamepad_platform_data_fetcher_win.cc

Issue 12260011: Support DirectInput gamepads on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
diff --git a/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc b/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
index 838a626d0184b093df64cb1ba6a2269dd9060022..7d81496f3484288056f52c62eacde8f75884c349 100644
--- a/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
@@ -4,7 +4,21 @@
#include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
+#define DIRECTINPUT_VERSION 0x0800
+#ifndef _WIN32_DCOM
+#define _WIN32_DCOM
+#endif
+
+#include <basetsd.h>
+#include <commctrl.h>
+#include <dinput.h>
+#include <dinputd.h>
+#include <oleauto.h>
+#include <wbemidl.h>
+#include <windows.h>
+
#include "base/debug/trace_event.h"
+#include "base/string_util.h"
#include "content/common/gamepad_messages.h"
#include "content/common/gamepad_hardware_buffer.h"
@@ -28,7 +42,7 @@ static const BYTE kDeviceSubTypeDrumKit = 8;
static const BYTE kDeviceSubTypeGuitarBass = 11;
static const BYTE kDeviceSubTypeArcadePad = 19;
-float NormalizeAxis(SHORT value) {
+float NormalizeXInputAxis(SHORT value) {
return ((value + 32768.f) / 32767.5f) - 1.f;
}
@@ -48,105 +62,492 @@ const WebUChar* const GamepadSubTypeName(BYTE sub_type) {
}
}
+// A nicer version of the DirectX SAFE_RELEASE macro.
+template <class T>
+void SafeRelease(T** p) {
+ if (*p)
+ (*p)->Release();
+ *p = NULL;
+}
+
+bool GetDirectInputVendorProduct(IDirectInputDevice8* gamepad,
+ std::string* vendor,
+ std::string* product) {
+ DIPROPDWORD property;
+ property.diph.dwSize = sizeof(DIPROPDWORD);
+ property.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+ property.diph.dwObj = 0;
+ property.diph.dwHow = DIPH_DEVICE;
+
+ if (FAILED(gamepad->GetProperty(DIPROP_VIDPID, &property.diph)))
+ return false;
+ int vendorData = LOWORD(property.dwData);
+ int productData = HIWORD(property.dwData);
+ std::stringstream vendorstream;
+ vendorstream << std::setw(4) << std::setfill('0') << std::hex << vendorData;
scottmg 2013/02/13 19:19:07 http://google-styleguide.googlecode.com/svn/trunk/
teravest 2013/02/13 21:59:22 Done.
+ *vendor = vendorstream.str();
+
+ std::stringstream productstream;
+ productstream << std::setw(4) << std::setfill('0') << std::hex << productData;
+ *product = productstream.str();
+ return true;
+}
+
+// Sets the deadzone value for all axes of a gamepad.
+// deadzone values range from 0 (no deadzone) to 10,000 (entire range
+// is dead).
+bool SetDirectInputDeadZone(IDirectInputDevice8* gamepad,
+ int deadzone) {
+ DIPROPDWORD prop;
+ prop.diph.dwSize = sizeof(DIPROPDWORD);
+ prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+ prop.diph.dwObj = 0;
+ prop.diph.dwHow = DIPH_DEVICE;
+ prop.dwData = deadzone;
+ return SUCCEEDED(gamepad->SetProperty(DIPROP_DEADZONE, &prop.diph));
+}
+
+struct InternalDirectInputDevice {
+ IDirectInputDevice8* gamepad;
+ GamepadStandardMappingFunction mapper;
+ wchar_t id[WebGamepad::idLengthCap];
+};
+
+struct EnumDevicesContext {
+ std::vector<uint32>* xinput_devices;
+ IDirectInput8* directinput_interface;
+ std::vector<InternalDirectInputDevice>* directinput_devices;
+};
+
+// We have to define our own structure here; I was unable to link the
+// "global" joydata2 structure from directx. This one is smaller anyway.
scottmg 2013/02/13 19:19:07 What? Why?
teravest 2013/02/13 21:59:22 I didn't want to muck around with how we were link
+struct JoyData {
+ long axes[10];
+ char buttons[24];
+ DWORD pov; // Often used for D-pads.
+};
+
+BOOL CALLBACK DirectInputEnumDevicesCallback(const DIDEVICEINSTANCE* instance,
+ void* context) {
+ EnumDevicesContext* ctxt = (EnumDevicesContext*) context;
+ // Skip XInput devices.
+ for (size_t i = 0; i < ctxt->xinput_devices->size(); ++i) {
+ if ((*ctxt->xinput_devices)[i] == instance->guidProduct.Data1)
+ return DIENUM_CONTINUE;
+ }
+ IDirectInputDevice8* gamepad;
+ if (FAILED(ctxt->directinput_interface->CreateDevice(instance->guidInstance,
+ &gamepad,
+ NULL)))
+ return DIENUM_CONTINUE;
+
+#define MAKE_AXIS(i) \
+ {0, FIELD_OFFSET(JoyData, axes) + 4 * i, \
+ DIDFT_AXIS | DIDFT_MAKEINSTANCE(i) | DIDFT_OPTIONAL, 0}
+#define MAKE_BUTTON(i) \
+ {&GUID_Button, FIELD_OFFSET(JoyData, buttons) + i, \
+ DIDFT_BUTTON | DIDFT_MAKEINSTANCE(i) | DIDFT_OPTIONAL, 0}
+#define MAKE_POV() \
+ {&GUID_POV, FIELD_OFFSET(JoyData, pov), DIDFT_POV | DIDFT_OPTIONAL, 0}
+ DIOBJECTDATAFORMAT rgodf[] = {
+ MAKE_AXIS(0),
+ MAKE_AXIS(1),
+ MAKE_AXIS(2),
+ MAKE_AXIS(3),
+ MAKE_AXIS(4),
+ MAKE_AXIS(5),
+ MAKE_AXIS(6),
+ MAKE_AXIS(7),
+ MAKE_AXIS(8),
+ MAKE_AXIS(9),
+ MAKE_BUTTON(0),
+ MAKE_BUTTON(1),
+ MAKE_BUTTON(2),
+ MAKE_BUTTON(3),
+ MAKE_BUTTON(4),
+ MAKE_BUTTON(5),
+ MAKE_BUTTON(6),
+ MAKE_BUTTON(7),
+ MAKE_BUTTON(8),
+ MAKE_BUTTON(9),
+ MAKE_BUTTON(10),
+ MAKE_BUTTON(11),
+ MAKE_BUTTON(12),
+ MAKE_BUTTON(13),
+ MAKE_BUTTON(14),
+ MAKE_BUTTON(15),
+ MAKE_BUTTON(16),
+ MAKE_POV(),
+ };
+#undef MAKE_AXIS
+#undef MAKE_BUTTON
+#undef MAKE_POV
+
+ DIDATAFORMAT df = {
+ sizeof (DIDATAFORMAT),
+ sizeof (DIOBJECTDATAFORMAT),
+ DIDF_ABSAXIS,
+ sizeof (JoyData),
+ sizeof (rgodf) / sizeof (rgodf[0]),
+ rgodf
+ };
+
+ // If we can't set the data format on the device, don't add it to our
+ // list, since we won't know how to read data from it.
+ if (FAILED(gamepad->SetDataFormat(&df)))
+ return DIENUM_CONTINUE;
+
+ InternalDirectInputDevice device;
+ device.gamepad = gamepad;
+ std::string vendor;
+ std::string product;
+ if (!GetDirectInputVendorProduct(gamepad, &vendor, &product))
+ return DIENUM_CONTINUE;
+
+ wcscpy_s(device.id, WebGamepad::idLengthCap, instance->tszInstanceName);
+
+ SetDirectInputDeadZone(gamepad, 1000);
scottmg 2013/02/13 19:19:07 Where did this 1000 come from?
teravest 2013/02/13 21:59:22 I've added a comment here explaining what this is.
+ device.mapper = GetGamepadStandardMappingFunction(vendor, product);
+ if (device.mapper)
+ ctxt->directinput_devices->push_back(device);
+ return DIENUM_CONTINUE;
+}
+
+// Adapted from the DirectInput samples in the DirectX SDK.
+// http://goo.gl/53Sfw
+void FillXInputDeviceList(std::vector<uint32>* xinput_devices) {
+ xinput_devices->clear();
+ IWbemServices* pIWbemServices = NULL;
+ IEnumWbemClassObject* pEnumDevices = NULL;
+ IWbemLocator* pIWbemLocator = NULL;
+ IWbemClassObject* pDevices[20] = {0};
+ BSTR bstrDeviceID = NULL;
+ BSTR bstrClassName = NULL;
+ BSTR bstrNamespace = NULL;
+ DWORD uReturned = 0;
+ bool bCleanupCOM = false;
+ UINT iDevice = 0;
+ VARIANT var;
+ HRESULT hr;
+
+ // CoInit if needed
+ hr = CoInitialize(NULL);
scottmg 2013/02/13 19:19:07 We shouldn't be doing this here.
teravest 2013/02/13 21:59:22 I've changed this to use a ScopedCOMInitializer. O
+ bCleanupCOM = SUCCEEDED(hr);
+
+ // Create WMI
+ hr = CoCreateInstance(__uuidof(WbemLocator),
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IWbemLocator),
+ (void**)&pIWbemLocator);
scottmg 2013/02/13 19:19:07 Please fix all the identifiers to match Chromium s
teravest 2013/02/13 21:59:22 Done.
+ if (FAILED(hr) || pIWbemLocator == NULL )
+ goto LCleanup;
+
+ // Create BSTRs for WMI
+ bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2");
+ if (bstrNamespace == NULL)
+ goto LCleanup;
+ bstrDeviceID = SysAllocString(L"DeviceID");
+ if (bstrDeviceID == NULL)
+ goto LCleanup;
+ bstrClassName = SysAllocString(L"Win32_PNPEntity");
+ if (bstrClassName == 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,
+ 0);
+
+ // Get list of Win32_PNPEntity devices
+ hr = pIWbemServices->CreateInstanceEnum(bstrClassName, 0, NULL,
+ &pEnumDevices);
+ if (FAILED(hr) || pEnumDevices == NULL )
+ goto LCleanup;
+
+ // Loop over all devices
+ while (true) {
+ // 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++) {
+ if (!pDevices[iDevice])
+ continue;
+ // 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
+ // Unfortunately this information can not be found by just using
+ // 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;
+ DWORD dwVidPid = MAKELONG(dwVid, dwPid);
+
+ // Add the VID/PID to a linked list
+ xinput_devices->push_back(dwVidPid);
+ }
+ }
+ SafeRelease(&pDevices[iDevice]);
+ }
+ }
+
+LCleanup:
+ if (bstrNamespace)
+ SysFreeString(bstrNamespace);
+ if (bstrDeviceID)
+ SysFreeString(bstrDeviceID);
+ if (bstrClassName)
+ SysFreeString(bstrClassName);
+ for (iDevice = 0; iDevice < 20; iDevice++)
+ SafeRelease(&pDevices[iDevice]);
+ SafeRelease(&pEnumDevices);
+ SafeRelease(&pIWbemLocator);
+ SafeRelease(&pIWbemServices);
+}
+
} // namespace
GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin()
: xinput_dll_(FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))),
- xinput_available_(GetXinputDllFunctions()) {
+ xinput_available_(GetXInputDllFunctions()),
+ directinput_dll_(FilePath(FILE_PATH_LITERAL("dinput8.dll"))),
+ directinput_available_(GetDirectInputDllFunctions()) {
}
GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() {
}
+void GamepadPlatformDataFetcherWin::EnumerateDevices(
+ WebGamepads* pads) {
+ TRACE_EVENT0("GAMEPAD", "EnumerateDevices");
+ pad_state_.clear();
+ for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
+ PadState s;
+ s.status = DISCONNECTED;
+ pad_state_.push_back(s);
+ }
+
+ for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
+ WebGamepad &pad = pads->items[i];
+ if (xinput_available_ && GetXInputPadConnectivity(i, &pad)) {
+ pad_state_[i].status = XINPUT_CONNECTED;
+ continue;
+ }
+ }
+
+ if (directinput_available_) {
+ FillXInputDeviceList(&xinput_devices_);
+ struct EnumDevicesContext ctxt;
+ std::vector<InternalDirectInputDevice> directinput_gamepads;
+ ctxt.xinput_devices = &xinput_devices_;
+ ctxt.directinput_interface = directinput_interface_;
+ ctxt.directinput_devices = &directinput_gamepads;
+
+ directinput_interface_->EnumDevices(
+ DI8DEVCLASS_GAMECTRL,
+ &DirectInputEnumDevicesCallback,
+ &ctxt,
+ DIEDFL_ATTACHEDONLY);
+
+ // Fill the "disconnected" pad state entries with our DirectInput
+ // gamepads.
+ unsigned pad_state_index = 0;
+ unsigned directinput_index = 0;
+ while (pad_state_index < WebGamepads::itemsLengthCap &&
+ directinput_index < directinput_gamepads.size()) {
+ if (pad_state_[pad_state_index].status != DISCONNECTED) {
+ ++pad_state_index;
+ continue;
+ }
+ WebGamepad &pad = pads->items[pad_state_index];
+ pad.connected = true;
+ wcscpy_s(pad.id, WebGamepad::idLengthCap,
+ directinput_gamepads[directinput_index].id);
+ pad_state_[pad_state_index].status = DIRECTINPUT_CONNECTED;
+ pad_state_[pad_state_index].directinput_gamepad =
+ directinput_gamepads[directinput_index].gamepad;
+ pad_state_[pad_state_index].mapper =
+ directinput_gamepads[directinput_index].mapper;
+ ++directinput_index;
+ ++pad_state_index;
+ }
+ }
+}
+
+
void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads,
- bool devices_changed_hint) {
+ bool devices_changed_hint) {
TRACE_EVENT0("GAMEPAD", "GetGamepadData");
- // If there's no XInput DLL on the system, early out so that we don't
- // call any other XInput functions.
- if (!xinput_available_) {
+ if (!xinput_available_ && !directinput_available_) {
pads->length = 0;
return;
}
- pads->length = WebGamepads::itemsLengthCap;
-
+ // A note on XInput devices:
// If we got notification that system devices have been updated, then
// run GetCapabilities to update the connected status and the device
// identifier. It can be slow to do to both GetCapabilities and
// GetState on unconnected devices, so we want to avoid a 2-5ms pause
// here by only doing this when the devices are updated (despite
// documentation claiming it's OK to call it any time).
- if (devices_changed_hint) {
- for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
- WebGamepad& pad = pads->items[i];
- TRACE_EVENT1("GAMEPAD", "GetCapabilities", "id", i);
- XINPUT_CAPABILITIES caps;
- DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps);
- if (res == ERROR_DEVICE_NOT_CONNECTED) {
- pad.connected = false;
- } else {
- pad.connected = true;
- base::swprintf(pad.id,
- WebGamepad::idLengthCap,
- L"Xbox 360 Controller (XInput STANDARD %ls)",
- GamepadSubTypeName(caps.SubType));
- }
- }
- }
+ if (devices_changed_hint)
+ EnumerateDevices(pads);
- // We've updated the connection state if necessary, now update the actual
- // data for the devices that are connected.
for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
WebGamepad& pad = pads->items[i];
+ if (pad_state_[i].status == XINPUT_CONNECTED)
+ GetXInputPadData(i, &pad);
+ else if (pad_state_[i].status == DIRECTINPUT_CONNECTED)
+ GetDirectInputPadData(i, &pad);
+ }
+ pads->length = WebGamepads::itemsLengthCap;
+ return;
scottmg 2013/02/13 19:19:07 nit: remove
teravest 2013/02/13 21:59:22 Done.
+}
- // We rely on device_changed and GetCapabilities to tell us that
- // something's been connected, but we will mark as disconnected if
- // GetState returns that we've lost the pad.
- if (!pad.connected)
- continue;
+bool GamepadPlatformDataFetcherWin::GetXInputPadConnectivity(
+ int i,
+ WebGamepad* pad) const {
+ DCHECK(pad);
+ TRACE_EVENT1("GAMEPAD", "GetXInputPadConnectivity", "id", i);
+ XINPUT_CAPABILITIES caps;
+ DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps);
+ if (res == ERROR_DEVICE_NOT_CONNECTED) {
+ pad->connected = false;
+ return false;
+ } else {
+ pad->connected = true;
+ base::swprintf(pad->id,
+ WebGamepad::idLengthCap,
+ L"Xbox 360 Controller (XInput STANDARD %ls)",
+ GamepadSubTypeName(caps.SubType));
+ return true;
+ }
+}
+
+void GamepadPlatformDataFetcherWin::GetXInputPadData(
+ int i,
+ WebGamepad* pad) {
+ // We rely on device_changed and GetCapabilities to tell us that
+ // something's been connected, but we will mark as disconnected if
+ // GetState returns that we've lost the pad.
+ if (!pad->connected)
+ return;
- XINPUT_STATE state;
- memset(&state, 0, sizeof(XINPUT_STATE));
- TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i);
- DWORD dwResult = xinput_get_state_(i, &state);
- TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i);
-
- if (dwResult == ERROR_SUCCESS) {
- pad.timestamp = state.dwPacketNumber;
- pad.buttonsLength = 0;
-#define ADD(b) pad.buttons[pad.buttonsLength++] = \
- ((state.Gamepad.wButtons & (b)) ? 1.0 : 0.0);
- ADD(XINPUT_GAMEPAD_A);
- ADD(XINPUT_GAMEPAD_B);
- ADD(XINPUT_GAMEPAD_X);
- ADD(XINPUT_GAMEPAD_Y);
- ADD(XINPUT_GAMEPAD_LEFT_SHOULDER);
- ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER);
- pad.buttons[pad.buttonsLength++] = state.Gamepad.bLeftTrigger / 255.0;
- pad.buttons[pad.buttonsLength++] = state.Gamepad.bRightTrigger / 255.0;
- ADD(XINPUT_GAMEPAD_BACK);
- ADD(XINPUT_GAMEPAD_START);
- ADD(XINPUT_GAMEPAD_LEFT_THUMB);
- ADD(XINPUT_GAMEPAD_RIGHT_THUMB);
- ADD(XINPUT_GAMEPAD_DPAD_UP);
- ADD(XINPUT_GAMEPAD_DPAD_DOWN);
- ADD(XINPUT_GAMEPAD_DPAD_LEFT);
- ADD(XINPUT_GAMEPAD_DPAD_RIGHT);
+ XINPUT_STATE state;
+ memset(&state, 0, sizeof(XINPUT_STATE));
+ TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i);
+ DWORD dwResult = xinput_get_state_(i, &state);
+ TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i);
+
+ if (dwResult == ERROR_SUCCESS) {
+ pad->timestamp = state.dwPacketNumber;
+ pad->buttonsLength = 0;
+#define ADD(b) pad->buttons[pad->buttonsLength++] = \
+ ((state.Gamepad.wButtons & (b)) ? 1.0 : 0.0);
+ ADD(XINPUT_GAMEPAD_A);
+ ADD(XINPUT_GAMEPAD_B);
+ ADD(XINPUT_GAMEPAD_X);
+ ADD(XINPUT_GAMEPAD_Y);
+ ADD(XINPUT_GAMEPAD_LEFT_SHOULDER);
+ ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER);
+ pad->buttons[pad->buttonsLength++] = state.Gamepad.bLeftTrigger / 255.0;
+ pad->buttons[pad->buttonsLength++] = state.Gamepad.bRightTrigger / 255.0;
+ ADD(XINPUT_GAMEPAD_BACK);
+ ADD(XINPUT_GAMEPAD_START);
+ ADD(XINPUT_GAMEPAD_LEFT_THUMB);
+ ADD(XINPUT_GAMEPAD_RIGHT_THUMB);
+ ADD(XINPUT_GAMEPAD_DPAD_UP);
+ ADD(XINPUT_GAMEPAD_DPAD_DOWN);
+ ADD(XINPUT_GAMEPAD_DPAD_LEFT);
+ ADD(XINPUT_GAMEPAD_DPAD_RIGHT);
#undef ADD
- pad.axesLength = 0;
- // XInput are +up/+right, -down/-left, we want -up/-left.
- pad.axes[pad.axesLength++] = NormalizeAxis(state.Gamepad.sThumbLX);
- pad.axes[pad.axesLength++] = -NormalizeAxis(state.Gamepad.sThumbLY);
- pad.axes[pad.axesLength++] = NormalizeAxis(state.Gamepad.sThumbRX);
- pad.axes[pad.axesLength++] = -NormalizeAxis(state.Gamepad.sThumbRY);
- } else {
- pad.connected = false;
- }
+ pad->axesLength = 0;
+ // XInput are +up/+right, -down/-left, we want -up/-left.
+ pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbLX);
+ pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbLY);
+ pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbRX);
+ pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbRY);
+ } else {
+ pad->connected = false;
}
}
-bool GamepadPlatformDataFetcherWin::GetXinputDllFunctions() {
+void GamepadPlatformDataFetcherWin::GetDirectInputPadData(
+ int index,
+ WebGamepad* pad) {
+ if (!pad->connected)
+ return;
+
+ IDirectInputDevice8* gamepad = pad_state_[index].directinput_gamepad;
+ if (FAILED(gamepad->Poll())) {
+ HRESULT hr;
+ while ((hr = gamepad->Acquire()) == DIERR_INPUTLOST) { }
+ return;
+ }
+
+ JoyData state;
+ if (FAILED(gamepad->GetDeviceState(sizeof(JoyData), &state))) {
+ pad->connected = false;
+ return;
+ }
+
+ WebGamepad raw;
+ raw.connected = true;
+ for (int i = 0; i < 16; i++)
+ raw.buttons[i] = (state.buttons[i] & 0x80) ? 1.0 : 0.0;
+
+ // We map the POV (often a D-pad) into the buttons 16-19.
+ // DirectInput gives pov measurements in hundredths of degrees,
+ // clockwise from "North".
+ // We use 22.5 degree slices so we can handle diagonal D-raw presses.
+ static const int arc_segment = 2250; // 22.5 degrees = 1/16 circle
+ if (state.pov > arc_segment && state.pov < 7 * arc_segment)
+ raw.buttons[19] = 1;
+ else
+ raw.buttons[19] = 0;
+
+ if (state.pov > 5 * arc_segment && state.pov < 11 * arc_segment)
+ raw.buttons[17] = 1;
+ else
+ raw.buttons[17] = 0;
+
+ if (state.pov > 9 * arc_segment && state.pov < 15 * arc_segment)
+ raw.buttons[18] = 1;
+ else
+ raw.buttons[18] = 0;
+
+ if (state.pov < 3 * arc_segment ||
+ (state.pov > 13 * arc_segment && state.pov < 36000))
+ raw.buttons[16] = 1;
+ else
+ raw.buttons[16] = 0;
+
+ for (int i = 0; i < 10; i++)
+ raw.axes[i] = state.axes[i];
+
+ pad_state_[index].mapper(raw, pad);
+}
+
+bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() {
xinput_get_capabilities_ = NULL;
xinput_get_state_ = NULL;
xinput_enable_ = static_cast<XInputEnableFunc>(
@@ -165,4 +566,18 @@ bool GamepadPlatformDataFetcherWin::GetXinputDllFunctions() {
return true;
}
+bool GamepadPlatformDataFetcherWin::GetDirectInputDllFunctions() {
+ directinput_create_ = static_cast<DirectInputCreateFunc>(
scottmg 2013/02/13 19:19:07 According to http://msdn.microsoft.com/en-us/libra
teravest 2013/02/13 21:59:22 Cool. I'm still trying to figure out how to do thi
+ directinput_dll_.GetFunctionPointer("DirectInput8Create"));
+ if (!directinput_create_)
+ return false;
+ if (FAILED(directinput_create_(GetModuleHandle(NULL),
+ DIRECTINPUT_VERSION,
+ IID_IDirectInput8,
+ (void **)&directinput_interface_,
+ NULL)))
+ return false;
+ return true;
+}
+
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698