| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/gamepad/raw_input_data_fetcher_win.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include "base/macros.h" | |
| 10 #include "base/trace_event/trace_event.h" | |
| 11 #include "content/common/gamepad_hardware_buffer.h" | |
| 12 #include "content/common/gamepad_messages.h" | |
| 13 | |
| 14 namespace content { | |
| 15 | |
| 16 using namespace blink; | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 float NormalizeAxis(long value, long min, long max) { | |
| 21 return (2.f * (value - min) / static_cast<float>(max - min)) - 1.f; | |
| 22 } | |
| 23 | |
| 24 unsigned long GetBitmask(unsigned short bits) { | |
| 25 return (1 << bits) - 1; | |
| 26 } | |
| 27 | |
| 28 // From the HID Usage Tables specification. | |
| 29 USHORT DeviceUsages[] = { | |
| 30 0x04, // Joysticks | |
| 31 0x05, // Gamepads | |
| 32 0x08, // Multi Axis | |
| 33 }; | |
| 34 | |
| 35 const uint32_t kAxisMinimumUsageNumber = 0x30; | |
| 36 const uint32_t kGameControlsUsagePage = 0x05; | |
| 37 const uint32_t kButtonUsagePage = 0x09; | |
| 38 | |
| 39 } // namespace | |
| 40 | |
| 41 RawGamepadInfo::RawGamepadInfo() { | |
| 42 } | |
| 43 | |
| 44 RawGamepadInfo::~RawGamepadInfo() { | |
| 45 } | |
| 46 | |
| 47 RawInputDataFetcher::RawInputDataFetcher() | |
| 48 : hid_dll_(base::FilePath(FILE_PATH_LITERAL("hid.dll"))), | |
| 49 rawinput_available_(GetHidDllFunctions()), | |
| 50 filter_xinput_(true), | |
| 51 events_monitored_(false) { | |
| 52 } | |
| 53 | |
| 54 RawInputDataFetcher::~RawInputDataFetcher() { | |
| 55 ClearControllers(); | |
| 56 DCHECK(!window_); | |
| 57 DCHECK(!events_monitored_); | |
| 58 } | |
| 59 | |
| 60 void RawInputDataFetcher::WillDestroyCurrentMessageLoop() { | |
| 61 StopMonitor(); | |
| 62 } | |
| 63 | |
| 64 RAWINPUTDEVICE* RawInputDataFetcher::GetRawInputDevices(DWORD flags) { | |
| 65 size_t usage_count = arraysize(DeviceUsages); | |
| 66 std::unique_ptr<RAWINPUTDEVICE[]> devices(new RAWINPUTDEVICE[usage_count]); | |
| 67 for (size_t i = 0; i < usage_count; ++i) { | |
| 68 devices[i].dwFlags = flags; | |
| 69 devices[i].usUsagePage = 1; | |
| 70 devices[i].usUsage = DeviceUsages[i]; | |
| 71 devices[i].hwndTarget = (flags & RIDEV_REMOVE) ? 0 : window_->hwnd(); | |
| 72 } | |
| 73 return devices.release(); | |
| 74 } | |
| 75 | |
| 76 void RawInputDataFetcher::StartMonitor() { | |
| 77 if (!rawinput_available_ || events_monitored_) | |
| 78 return; | |
| 79 | |
| 80 if (!window_) { | |
| 81 window_.reset(new base::win::MessageWindow()); | |
| 82 if (!window_->Create(base::Bind(&RawInputDataFetcher::HandleMessage, | |
| 83 base::Unretained(this)))) { | |
| 84 PLOG(ERROR) << "Failed to create the raw input window"; | |
| 85 window_.reset(); | |
| 86 return; | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 // Register to receive raw HID input. | |
| 91 std::unique_ptr<RAWINPUTDEVICE[]> devices( | |
| 92 GetRawInputDevices(RIDEV_INPUTSINK)); | |
| 93 if (!RegisterRawInputDevices(devices.get(), arraysize(DeviceUsages), | |
| 94 sizeof(RAWINPUTDEVICE))) { | |
| 95 PLOG(ERROR) << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK"; | |
| 96 window_.reset(); | |
| 97 return; | |
| 98 } | |
| 99 | |
| 100 // Start observing message loop destruction if we start monitoring the first | |
| 101 // event. | |
| 102 if (!events_monitored_) | |
| 103 base::MessageLoop::current()->AddDestructionObserver(this); | |
| 104 | |
| 105 events_monitored_ = true; | |
| 106 } | |
| 107 | |
| 108 void RawInputDataFetcher::StopMonitor() { | |
| 109 if (!rawinput_available_ || !events_monitored_) | |
| 110 return; | |
| 111 | |
| 112 // Stop receiving raw input. | |
| 113 DCHECK(window_); | |
| 114 std::unique_ptr<RAWINPUTDEVICE[]> devices(GetRawInputDevices(RIDEV_REMOVE)); | |
| 115 | |
| 116 if (!RegisterRawInputDevices(devices.get(), arraysize(DeviceUsages), | |
| 117 sizeof(RAWINPUTDEVICE))) { | |
| 118 PLOG(INFO) << "RegisterRawInputDevices() failed for RIDEV_REMOVE"; | |
| 119 } | |
| 120 | |
| 121 events_monitored_ = false; | |
| 122 window_.reset(); | |
| 123 | |
| 124 // Stop observing message loop destruction if no event is being monitored. | |
| 125 base::MessageLoop::current()->RemoveDestructionObserver(this); | |
| 126 } | |
| 127 | |
| 128 void RawInputDataFetcher::ClearControllers() { | |
| 129 while (!controllers_.empty()) { | |
| 130 RawGamepadInfo* gamepad_info = controllers_.begin()->second; | |
| 131 controllers_.erase(gamepad_info->handle); | |
| 132 delete gamepad_info; | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 std::vector<RawGamepadInfo*> RawInputDataFetcher::EnumerateDevices() { | |
| 137 std::vector<RawGamepadInfo*> valid_controllers; | |
| 138 | |
| 139 ClearControllers(); | |
| 140 | |
| 141 UINT count = 0; | |
| 142 UINT result = GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)); | |
| 143 if (result == static_cast<UINT>(-1)) { | |
| 144 PLOG(ERROR) << "GetRawInputDeviceList() failed"; | |
| 145 return valid_controllers; | |
| 146 } | |
| 147 DCHECK_EQ(0u, result); | |
| 148 | |
| 149 std::unique_ptr<RAWINPUTDEVICELIST[]> device_list( | |
| 150 new RAWINPUTDEVICELIST[count]); | |
| 151 result = GetRawInputDeviceList(device_list.get(), &count, | |
| 152 sizeof(RAWINPUTDEVICELIST)); | |
| 153 if (result == static_cast<UINT>(-1)) { | |
| 154 PLOG(ERROR) << "GetRawInputDeviceList() failed"; | |
| 155 return valid_controllers; | |
| 156 } | |
| 157 DCHECK_EQ(count, result); | |
| 158 | |
| 159 for (UINT i = 0; i < count; ++i) { | |
| 160 if (device_list[i].dwType == RIM_TYPEHID) { | |
| 161 HANDLE device_handle = device_list[i].hDevice; | |
| 162 RawGamepadInfo* gamepad_info = ParseGamepadInfo(device_handle); | |
| 163 if (gamepad_info) { | |
| 164 controllers_[device_handle] = gamepad_info; | |
| 165 valid_controllers.push_back(gamepad_info); | |
| 166 } | |
| 167 } | |
| 168 } | |
| 169 return valid_controllers; | |
| 170 } | |
| 171 | |
| 172 RawGamepadInfo* RawInputDataFetcher::GetGamepadInfo(HANDLE handle) { | |
| 173 std::map<HANDLE, RawGamepadInfo*>::iterator it = controllers_.find(handle); | |
| 174 if (it != controllers_.end()) | |
| 175 return it->second; | |
| 176 | |
| 177 return NULL; | |
| 178 } | |
| 179 | |
| 180 RawGamepadInfo* RawInputDataFetcher::ParseGamepadInfo(HANDLE hDevice) { | |
| 181 UINT size = 0; | |
| 182 | |
| 183 // Do we already have this device in the map? | |
| 184 if (GetGamepadInfo(hDevice)) | |
| 185 return NULL; | |
| 186 | |
| 187 // Query basic device info. | |
| 188 UINT result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, | |
| 189 NULL, &size); | |
| 190 if (result == static_cast<UINT>(-1)) { | |
| 191 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; | |
| 192 return NULL; | |
| 193 } | |
| 194 DCHECK_EQ(0u, result); | |
| 195 | |
| 196 std::unique_ptr<uint8_t[]> di_buffer(new uint8_t[size]); | |
| 197 RID_DEVICE_INFO* device_info = | |
| 198 reinterpret_cast<RID_DEVICE_INFO*>(di_buffer.get()); | |
| 199 result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, | |
| 200 di_buffer.get(), &size); | |
| 201 if (result == static_cast<UINT>(-1)) { | |
| 202 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; | |
| 203 return NULL; | |
| 204 } | |
| 205 DCHECK_EQ(size, result); | |
| 206 | |
| 207 // Make sure this device is of a type that we want to observe. | |
| 208 bool valid_type = false; | |
| 209 for (USHORT device_usage : DeviceUsages) { | |
| 210 if (device_info->hid.usUsage == device_usage) { | |
| 211 valid_type = true; | |
| 212 break; | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 if (!valid_type) | |
| 217 return NULL; | |
| 218 | |
| 219 std::unique_ptr<RawGamepadInfo> gamepad_info(new RawGamepadInfo); | |
| 220 gamepad_info->handle = hDevice; | |
| 221 gamepad_info->report_id = 0; | |
| 222 gamepad_info->vendor_id = device_info->hid.dwVendorId; | |
| 223 gamepad_info->product_id = device_info->hid.dwProductId; | |
| 224 gamepad_info->buttons_length = 0; | |
| 225 ZeroMemory(gamepad_info->buttons, sizeof(gamepad_info->buttons)); | |
| 226 gamepad_info->axes_length = 0; | |
| 227 ZeroMemory(gamepad_info->axes, sizeof(gamepad_info->axes)); | |
| 228 | |
| 229 // Query device identifier | |
| 230 result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, | |
| 231 NULL, &size); | |
| 232 if (result == static_cast<UINT>(-1)) { | |
| 233 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; | |
| 234 return NULL; | |
| 235 } | |
| 236 DCHECK_EQ(0u, result); | |
| 237 | |
| 238 std::unique_ptr<wchar_t[]> name_buffer(new wchar_t[size]); | |
| 239 result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, | |
| 240 name_buffer.get(), &size); | |
| 241 if (result == static_cast<UINT>(-1)) { | |
| 242 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; | |
| 243 return NULL; | |
| 244 } | |
| 245 DCHECK_EQ(size, result); | |
| 246 | |
| 247 // The presence of "IG_" in the device name indicates that this is an XInput | |
| 248 // Gamepad. Skip enumerating these devices and let the XInput path handle it. | |
| 249 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee417014.aspx | |
| 250 if (filter_xinput_ && wcsstr( name_buffer.get(), L"IG_" ) ) | |
| 251 return NULL; | |
| 252 | |
| 253 // Get a friendly device name | |
| 254 BOOLEAN got_product_string = FALSE; | |
| 255 HANDLE hid_handle = CreateFile(name_buffer.get(), GENERIC_READ|GENERIC_WRITE, | |
| 256 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL); | |
| 257 if (hid_handle) { | |
| 258 got_product_string = hidd_get_product_string_(hid_handle, gamepad_info->id, | |
| 259 sizeof(gamepad_info->id)); | |
| 260 CloseHandle(hid_handle); | |
| 261 } | |
| 262 | |
| 263 if (!got_product_string) | |
| 264 swprintf(gamepad_info->id, WebGamepad::idLengthCap, L"Unknown Gamepad"); | |
| 265 | |
| 266 // Query device capabilities. | |
| 267 result = GetRawInputDeviceInfo(hDevice, RIDI_PREPARSEDDATA, | |
| 268 NULL, &size); | |
| 269 if (result == static_cast<UINT>(-1)) { | |
| 270 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; | |
| 271 return NULL; | |
| 272 } | |
| 273 DCHECK_EQ(0u, result); | |
| 274 | |
| 275 gamepad_info->ppd_buffer.reset(new uint8_t[size]); | |
| 276 gamepad_info->preparsed_data = | |
| 277 reinterpret_cast<PHIDP_PREPARSED_DATA>(gamepad_info->ppd_buffer.get()); | |
| 278 result = GetRawInputDeviceInfo(hDevice, RIDI_PREPARSEDDATA, | |
| 279 gamepad_info->ppd_buffer.get(), &size); | |
| 280 if (result == static_cast<UINT>(-1)) { | |
| 281 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; | |
| 282 return NULL; | |
| 283 } | |
| 284 DCHECK_EQ(size, result); | |
| 285 | |
| 286 HIDP_CAPS caps; | |
| 287 NTSTATUS status = hidp_get_caps_(gamepad_info->preparsed_data, &caps); | |
| 288 DCHECK_EQ(HIDP_STATUS_SUCCESS, status); | |
| 289 | |
| 290 // Query button information. | |
| 291 USHORT count = caps.NumberInputButtonCaps; | |
| 292 if (count > 0) { | |
| 293 std::unique_ptr<HIDP_BUTTON_CAPS[]> button_caps( | |
| 294 new HIDP_BUTTON_CAPS[count]); | |
| 295 status = hidp_get_button_caps_( | |
| 296 HidP_Input, button_caps.get(), &count, gamepad_info->preparsed_data); | |
| 297 DCHECK_EQ(HIDP_STATUS_SUCCESS, status); | |
| 298 | |
| 299 for (uint32_t i = 0; i < count; ++i) { | |
| 300 if (button_caps[i].Range.UsageMin <= WebGamepad::buttonsLengthCap && | |
| 301 button_caps[i].UsagePage == kButtonUsagePage) { | |
| 302 uint32_t max_index = | |
| 303 std::min(WebGamepad::buttonsLengthCap, | |
| 304 static_cast<size_t>(button_caps[i].Range.UsageMax)); | |
| 305 gamepad_info->buttons_length = std::max( | |
| 306 gamepad_info->buttons_length, max_index); | |
| 307 } | |
| 308 } | |
| 309 } | |
| 310 | |
| 311 // Query axis information. | |
| 312 count = caps.NumberInputValueCaps; | |
| 313 std::unique_ptr<HIDP_VALUE_CAPS[]> axes_caps(new HIDP_VALUE_CAPS[count]); | |
| 314 status = hidp_get_value_caps_(HidP_Input, axes_caps.get(), &count, | |
| 315 gamepad_info->preparsed_data); | |
| 316 | |
| 317 bool mapped_all_axes = true; | |
| 318 | |
| 319 for (UINT i = 0; i < count; i++) { | |
| 320 uint32_t axis_index = axes_caps[i].Range.UsageMin - kAxisMinimumUsageNumber; | |
| 321 if (axis_index < WebGamepad::axesLengthCap) { | |
| 322 gamepad_info->axes[axis_index].caps = axes_caps[i]; | |
| 323 gamepad_info->axes[axis_index].value = 0; | |
| 324 gamepad_info->axes[axis_index].active = true; | |
| 325 gamepad_info->axes[axis_index].bitmask = GetBitmask(axes_caps[i].BitSize); | |
| 326 gamepad_info->axes_length = | |
| 327 std::max(gamepad_info->axes_length, axis_index + 1); | |
| 328 } else { | |
| 329 mapped_all_axes = false; | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 if (!mapped_all_axes) { | |
| 334 // For axes who's usage puts them outside the standard axesLengthCap range. | |
| 335 uint32_t next_index = 0; | |
| 336 for (UINT i = 0; i < count; i++) { | |
| 337 uint32_t usage = axes_caps[i].Range.UsageMin - kAxisMinimumUsageNumber; | |
| 338 if (usage >= WebGamepad::axesLengthCap && | |
| 339 axes_caps[i].UsagePage <= kGameControlsUsagePage) { | |
| 340 | |
| 341 for (; next_index < WebGamepad::axesLengthCap; ++next_index) { | |
| 342 if (!gamepad_info->axes[next_index].active) | |
| 343 break; | |
| 344 } | |
| 345 if (next_index < WebGamepad::axesLengthCap) { | |
| 346 gamepad_info->axes[next_index].caps = axes_caps[i]; | |
| 347 gamepad_info->axes[next_index].value = 0; | |
| 348 gamepad_info->axes[next_index].active = true; | |
| 349 gamepad_info->axes[next_index].bitmask = GetBitmask( | |
| 350 axes_caps[i].BitSize); | |
| 351 gamepad_info->axes_length = | |
| 352 std::max(gamepad_info->axes_length, next_index + 1); | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 if (next_index >= WebGamepad::axesLengthCap) | |
| 357 break; | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 return gamepad_info.release(); | |
| 362 } | |
| 363 | |
| 364 void RawInputDataFetcher::UpdateGamepad( | |
| 365 RAWINPUT* input, | |
| 366 RawGamepadInfo* gamepad_info) { | |
| 367 NTSTATUS status; | |
| 368 | |
| 369 gamepad_info->report_id++; | |
| 370 | |
| 371 // Query button state. | |
| 372 if (gamepad_info->buttons_length) { | |
| 373 // Clear the button state | |
| 374 ZeroMemory(gamepad_info->buttons, sizeof(gamepad_info->buttons)); | |
| 375 ULONG buttons_length = 0; | |
| 376 | |
| 377 hidp_get_usages_ex_(HidP_Input, | |
| 378 0, | |
| 379 NULL, | |
| 380 &buttons_length, | |
| 381 gamepad_info->preparsed_data, | |
| 382 reinterpret_cast<PCHAR>(input->data.hid.bRawData), | |
| 383 input->data.hid.dwSizeHid); | |
| 384 | |
| 385 std::unique_ptr<USAGE_AND_PAGE[]> usages( | |
| 386 new USAGE_AND_PAGE[buttons_length]); | |
| 387 status = | |
| 388 hidp_get_usages_ex_(HidP_Input, | |
| 389 0, | |
| 390 usages.get(), | |
| 391 &buttons_length, | |
| 392 gamepad_info->preparsed_data, | |
| 393 reinterpret_cast<PCHAR>(input->data.hid.bRawData), | |
| 394 input->data.hid.dwSizeHid); | |
| 395 | |
| 396 if (status == HIDP_STATUS_SUCCESS) { | |
| 397 // Set each reported button to true. | |
| 398 for (uint32_t j = 0; j < buttons_length; j++) { | |
| 399 int32_t button_index = usages[j].Usage - 1; | |
| 400 if (usages[j].UsagePage == kButtonUsagePage && | |
| 401 button_index >= 0 && | |
| 402 button_index < | |
| 403 static_cast<int>(blink::WebGamepad::buttonsLengthCap)) { | |
| 404 gamepad_info->buttons[button_index] = true; | |
| 405 } | |
| 406 } | |
| 407 } | |
| 408 } | |
| 409 | |
| 410 // Query axis state. | |
| 411 ULONG axis_value = 0; | |
| 412 LONG scaled_axis_value = 0; | |
| 413 for (uint32_t i = 0; i < gamepad_info->axes_length; i++) { | |
| 414 RawGamepadAxis* axis = &gamepad_info->axes[i]; | |
| 415 | |
| 416 // If the min is < 0 we have to query the scaled value, otherwise we need | |
| 417 // the normal unscaled value. | |
| 418 if (axis->caps.LogicalMin < 0) { | |
| 419 status = hidp_get_scaled_usage_value_(HidP_Input, axis->caps.UsagePage, 0, | |
| 420 axis->caps.Range.UsageMin, &scaled_axis_value, | |
| 421 gamepad_info->preparsed_data, | |
| 422 reinterpret_cast<PCHAR>(input->data.hid.bRawData), | |
| 423 input->data.hid.dwSizeHid); | |
| 424 if (status == HIDP_STATUS_SUCCESS) { | |
| 425 axis->value = NormalizeAxis(scaled_axis_value, | |
| 426 axis->caps.PhysicalMin, axis->caps.PhysicalMax); | |
| 427 } | |
| 428 } else { | |
| 429 status = hidp_get_usage_value_(HidP_Input, axis->caps.UsagePage, 0, | |
| 430 axis->caps.Range.UsageMin, &axis_value, | |
| 431 gamepad_info->preparsed_data, | |
| 432 reinterpret_cast<PCHAR>(input->data.hid.bRawData), | |
| 433 input->data.hid.dwSizeHid); | |
| 434 if (status == HIDP_STATUS_SUCCESS) { | |
| 435 axis->value = NormalizeAxis(axis_value & axis->bitmask, | |
| 436 axis->caps.LogicalMin & axis->bitmask, | |
| 437 axis->caps.LogicalMax & axis->bitmask); | |
| 438 } | |
| 439 } | |
| 440 } | |
| 441 } | |
| 442 | |
| 443 LRESULT RawInputDataFetcher::OnInput(HRAWINPUT input_handle) { | |
| 444 // Get the size of the input record. | |
| 445 UINT size = 0; | |
| 446 UINT result = GetRawInputData( | |
| 447 input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); | |
| 448 if (result == static_cast<UINT>(-1)) { | |
| 449 PLOG(ERROR) << "GetRawInputData() failed"; | |
| 450 return 0; | |
| 451 } | |
| 452 DCHECK_EQ(0u, result); | |
| 453 | |
| 454 // Retrieve the input record. | |
| 455 std::unique_ptr<uint8_t[]> buffer(new uint8_t[size]); | |
| 456 RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get()); | |
| 457 result = GetRawInputData( | |
| 458 input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER)); | |
| 459 if (result == static_cast<UINT>(-1)) { | |
| 460 PLOG(ERROR) << "GetRawInputData() failed"; | |
| 461 return 0; | |
| 462 } | |
| 463 DCHECK_EQ(size, result); | |
| 464 | |
| 465 // Notify the observer about events generated locally. | |
| 466 if (input->header.dwType == RIM_TYPEHID && input->header.hDevice != NULL) { | |
| 467 RawGamepadInfo* gamepad = GetGamepadInfo(input->header.hDevice); | |
| 468 if (gamepad) | |
| 469 UpdateGamepad(input, gamepad); | |
| 470 } | |
| 471 | |
| 472 return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER)); | |
| 473 } | |
| 474 | |
| 475 bool RawInputDataFetcher::HandleMessage(UINT message, | |
| 476 WPARAM wparam, | |
| 477 LPARAM lparam, | |
| 478 LRESULT* result) { | |
| 479 switch (message) { | |
| 480 case WM_INPUT: | |
| 481 *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam)); | |
| 482 return true; | |
| 483 | |
| 484 default: | |
| 485 return false; | |
| 486 } | |
| 487 } | |
| 488 | |
| 489 bool RawInputDataFetcher::GetHidDllFunctions() { | |
| 490 hidp_get_caps_ = NULL; | |
| 491 hidp_get_button_caps_ = NULL; | |
| 492 hidp_get_value_caps_ = NULL; | |
| 493 hidp_get_usages_ex_ = NULL; | |
| 494 hidp_get_usage_value_ = NULL; | |
| 495 hidp_get_scaled_usage_value_ = NULL; | |
| 496 hidd_get_product_string_ = NULL; | |
| 497 | |
| 498 if (!hid_dll_.is_valid()) return false; | |
| 499 | |
| 500 hidp_get_caps_ = reinterpret_cast<HidPGetCapsFunc>( | |
| 501 hid_dll_.GetFunctionPointer("HidP_GetCaps")); | |
| 502 if (!hidp_get_caps_) | |
| 503 return false; | |
| 504 hidp_get_button_caps_ = reinterpret_cast<HidPGetButtonCapsFunc>( | |
| 505 hid_dll_.GetFunctionPointer("HidP_GetButtonCaps")); | |
| 506 if (!hidp_get_button_caps_) | |
| 507 return false; | |
| 508 hidp_get_value_caps_ = reinterpret_cast<HidPGetValueCapsFunc>( | |
| 509 hid_dll_.GetFunctionPointer("HidP_GetValueCaps")); | |
| 510 if (!hidp_get_value_caps_) | |
| 511 return false; | |
| 512 hidp_get_usages_ex_ = reinterpret_cast<HidPGetUsagesExFunc>( | |
| 513 hid_dll_.GetFunctionPointer("HidP_GetUsagesEx")); | |
| 514 if (!hidp_get_usages_ex_) | |
| 515 return false; | |
| 516 hidp_get_usage_value_ = reinterpret_cast<HidPGetUsageValueFunc>( | |
| 517 hid_dll_.GetFunctionPointer("HidP_GetUsageValue")); | |
| 518 if (!hidp_get_usage_value_) | |
| 519 return false; | |
| 520 hidp_get_scaled_usage_value_ = reinterpret_cast<HidPGetScaledUsageValueFunc>( | |
| 521 hid_dll_.GetFunctionPointer("HidP_GetScaledUsageValue")); | |
| 522 if (!hidp_get_scaled_usage_value_) | |
| 523 return false; | |
| 524 hidd_get_product_string_ = reinterpret_cast<HidDGetStringFunc>( | |
| 525 hid_dll_.GetFunctionPointer("HidD_GetProductString")); | |
| 526 if (!hidd_get_product_string_) | |
| 527 return false; | |
| 528 | |
| 529 return true; | |
| 530 } | |
| 531 | |
| 532 } // namespace content | |
| OLD | NEW |