| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/gamepad/raw_input_data_fetcher_win.h" | 5 #include "device/gamepad/raw_input_data_fetcher_win.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "base/strings/stringprintf.h" |
| 10 #include "base/trace_event/trace_event.h" | 11 #include "base/trace_event/trace_event.h" |
| 11 | 12 |
| 12 namespace device { | 13 namespace device { |
| 13 | 14 |
| 14 using namespace blink; | 15 using namespace blink; |
| 15 | 16 |
| 16 namespace { | 17 namespace { |
| 17 | 18 |
| 18 float NormalizeAxis(long value, long min, long max) { | 19 float NormalizeAxis(long value, long min, long max) { |
| 19 return (2.f * (value - min) / static_cast<float>(max - min)) - 1.f; | 20 return (2.f * (value - min) / static_cast<float>(max - min)) - 1.f; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 34 const uint32_t kGameControlsUsagePage = 0x05; | 35 const uint32_t kGameControlsUsagePage = 0x05; |
| 35 const uint32_t kButtonUsagePage = 0x09; | 36 const uint32_t kButtonUsagePage = 0x09; |
| 36 | 37 |
| 37 } // namespace | 38 } // namespace |
| 38 | 39 |
| 39 RawGamepadInfo::RawGamepadInfo() {} | 40 RawGamepadInfo::RawGamepadInfo() {} |
| 40 | 41 |
| 41 RawGamepadInfo::~RawGamepadInfo() {} | 42 RawGamepadInfo::~RawGamepadInfo() {} |
| 42 | 43 |
| 43 RawInputDataFetcher::RawInputDataFetcher() | 44 RawInputDataFetcher::RawInputDataFetcher() |
| 44 : hid_dll_(base::FilePath(FILE_PATH_LITERAL("hid.dll"))), | 45 : rawinput_available_(false), |
| 45 rawinput_available_(GetHidDllFunctions()), | |
| 46 filter_xinput_(true), | 46 filter_xinput_(true), |
| 47 events_monitored_(false) {} | 47 events_monitored_(false), |
| 48 last_source_id_(0), |
| 49 last_enumeration_id_(0) {} |
| 48 | 50 |
| 49 RawInputDataFetcher::~RawInputDataFetcher() { | 51 RawInputDataFetcher::~RawInputDataFetcher() { |
| 50 ClearControllers(); | 52 ClearControllers(); |
| 51 DCHECK(!window_); | 53 DCHECK(!window_); |
| 52 DCHECK(!events_monitored_); | 54 DCHECK(!events_monitored_); |
| 53 } | 55 } |
| 54 | 56 |
| 57 GamepadSource RawInputDataFetcher::source() { |
| 58 return Factory::static_source(); |
| 59 } |
| 60 |
| 55 void RawInputDataFetcher::WillDestroyCurrentMessageLoop() { | 61 void RawInputDataFetcher::WillDestroyCurrentMessageLoop() { |
| 56 StopMonitor(); | 62 StopMonitor(); |
| 57 } | 63 } |
| 58 | 64 |
| 65 void RawInputDataFetcher::OnAddedToProvider() { |
| 66 hid_dll_.Reset(base::LoadNativeLibrary( |
| 67 base::FilePath(FILE_PATH_LITERAL("hid.dll")), nullptr)); |
| 68 rawinput_available_ = GetHidDllFunctions(); |
| 69 } |
| 70 |
| 59 RAWINPUTDEVICE* RawInputDataFetcher::GetRawInputDevices(DWORD flags) { | 71 RAWINPUTDEVICE* RawInputDataFetcher::GetRawInputDevices(DWORD flags) { |
| 60 size_t usage_count = arraysize(DeviceUsages); | 72 size_t usage_count = arraysize(DeviceUsages); |
| 61 std::unique_ptr<RAWINPUTDEVICE[]> devices(new RAWINPUTDEVICE[usage_count]); | 73 std::unique_ptr<RAWINPUTDEVICE[]> devices(new RAWINPUTDEVICE[usage_count]); |
| 62 for (size_t i = 0; i < usage_count; ++i) { | 74 for (size_t i = 0; i < usage_count; ++i) { |
| 63 devices[i].dwFlags = flags; | 75 devices[i].dwFlags = flags; |
| 64 devices[i].usUsagePage = 1; | 76 devices[i].usUsagePage = 1; |
| 65 devices[i].usUsage = DeviceUsages[i]; | 77 devices[i].usUsage = DeviceUsages[i]; |
| 66 devices[i].hwndTarget = (flags & RIDEV_REMOVE) ? 0 : window_->hwnd(); | 78 devices[i].hwndTarget = (flags & RIDEV_REMOVE) ? 0 : window_->hwnd(); |
| 67 } | 79 } |
| 68 return devices.release(); | 80 return devices.release(); |
| 69 } | 81 } |
| 70 | 82 |
| 83 void RawInputDataFetcher::PauseHint(bool pause) { |
| 84 if (pause) |
| 85 StopMonitor(); |
| 86 else |
| 87 StartMonitor(); |
| 88 } |
| 89 |
| 71 void RawInputDataFetcher::StartMonitor() { | 90 void RawInputDataFetcher::StartMonitor() { |
| 72 if (!rawinput_available_ || events_monitored_) | 91 if (!rawinput_available_ || events_monitored_) |
| 73 return; | 92 return; |
| 74 | 93 |
| 75 if (!window_) { | 94 if (!window_) { |
| 76 window_.reset(new base::win::MessageWindow()); | 95 window_.reset(new base::win::MessageWindow()); |
| 77 if (!window_->Create(base::Bind(&RawInputDataFetcher::HandleMessage, | 96 if (!window_->Create(base::Bind(&RawInputDataFetcher::HandleMessage, |
| 78 base::Unretained(this)))) { | 97 base::Unretained(this)))) { |
| 79 PLOG(ERROR) << "Failed to create the raw input window"; | 98 PLOG(ERROR) << "Failed to create the raw input window"; |
| 80 window_.reset(); | 99 window_.reset(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 } | 140 } |
| 122 | 141 |
| 123 void RawInputDataFetcher::ClearControllers() { | 142 void RawInputDataFetcher::ClearControllers() { |
| 124 while (!controllers_.empty()) { | 143 while (!controllers_.empty()) { |
| 125 RawGamepadInfo* gamepad_info = controllers_.begin()->second; | 144 RawGamepadInfo* gamepad_info = controllers_.begin()->second; |
| 126 controllers_.erase(gamepad_info->handle); | 145 controllers_.erase(gamepad_info->handle); |
| 127 delete gamepad_info; | 146 delete gamepad_info; |
| 128 } | 147 } |
| 129 } | 148 } |
| 130 | 149 |
| 131 std::vector<RawGamepadInfo*> RawInputDataFetcher::EnumerateDevices() { | 150 void RawInputDataFetcher::GetGamepadData(bool devices_changed_hint) { |
| 132 std::vector<RawGamepadInfo*> valid_controllers; | 151 if (!rawinput_available_) |
| 152 return; |
| 133 | 153 |
| 134 ClearControllers(); | 154 if (devices_changed_hint) |
| 155 EnumerateDevices(); |
| 156 |
| 157 for (const auto& controller : controllers_) { |
| 158 RawGamepadInfo* gamepad = controller.second; |
| 159 PadState* state = GetPadState(gamepad->source_id); |
| 160 if (!state) |
| 161 continue; |
| 162 |
| 163 WebGamepad& pad = state->data; |
| 164 |
| 165 pad.timestamp = gamepad->report_id; |
| 166 pad.buttonsLength = gamepad->buttons_length; |
| 167 pad.axesLength = gamepad->axes_length; |
| 168 |
| 169 for (unsigned int i = 0; i < pad.buttonsLength; i++) { |
| 170 pad.buttons[i].pressed = gamepad->buttons[i]; |
| 171 pad.buttons[i].value = gamepad->buttons[i] ? 1.0 : 0.0; |
| 172 } |
| 173 |
| 174 for (unsigned int i = 0; i < pad.axesLength; i++) |
| 175 pad.axes[i] = gamepad->axes[i].value; |
| 176 } |
| 177 } |
| 178 |
| 179 void RawInputDataFetcher::EnumerateDevices() { |
| 180 last_enumeration_id_++; |
| 135 | 181 |
| 136 UINT count = 0; | 182 UINT count = 0; |
| 137 UINT result = GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)); | 183 UINT result = GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)); |
| 138 if (result == static_cast<UINT>(-1)) { | 184 if (result == static_cast<UINT>(-1)) { |
| 139 PLOG(ERROR) << "GetRawInputDeviceList() failed"; | 185 PLOG(ERROR) << "GetRawInputDeviceList() failed"; |
| 140 return valid_controllers; | 186 return; |
| 141 } | 187 } |
| 142 DCHECK_EQ(0u, result); | 188 DCHECK_EQ(0u, result); |
| 143 | 189 |
| 144 std::unique_ptr<RAWINPUTDEVICELIST[]> device_list( | 190 std::unique_ptr<RAWINPUTDEVICELIST[]> device_list( |
| 145 new RAWINPUTDEVICELIST[count]); | 191 new RAWINPUTDEVICELIST[count]); |
| 146 result = GetRawInputDeviceList(device_list.get(), &count, | 192 result = GetRawInputDeviceList(device_list.get(), &count, |
| 147 sizeof(RAWINPUTDEVICELIST)); | 193 sizeof(RAWINPUTDEVICELIST)); |
| 148 if (result == static_cast<UINT>(-1)) { | 194 if (result == static_cast<UINT>(-1)) { |
| 149 PLOG(ERROR) << "GetRawInputDeviceList() failed"; | 195 PLOG(ERROR) << "GetRawInputDeviceList() failed"; |
| 150 return valid_controllers; | 196 return; |
| 151 } | 197 } |
| 152 DCHECK_EQ(count, result); | 198 DCHECK_EQ(count, result); |
| 153 | 199 |
| 154 for (UINT i = 0; i < count; ++i) { | 200 for (UINT i = 0; i < count; ++i) { |
| 155 if (device_list[i].dwType == RIM_TYPEHID) { | 201 if (device_list[i].dwType == RIM_TYPEHID) { |
| 156 HANDLE device_handle = device_list[i].hDevice; | 202 HANDLE device_handle = device_list[i].hDevice; |
| 157 RawGamepadInfo* gamepad_info = ParseGamepadInfo(device_handle); | 203 ControllerMap::iterator controller = controllers_.find(device_handle); |
| 158 if (gamepad_info) { | 204 |
| 159 controllers_[device_handle] = gamepad_info; | 205 RawGamepadInfo* gamepad; |
| 160 valid_controllers.push_back(gamepad_info); | 206 if (controller != controllers_.end()) { |
| 207 gamepad = controller->second; |
| 208 } else { |
| 209 gamepad = ParseGamepadInfo(device_handle); |
| 210 if (!gamepad) |
| 211 continue; |
| 212 |
| 213 PadState* state = GetPadState(gamepad->source_id); |
| 214 if (!state) |
| 215 continue; // No slot available for this gamepad. |
| 216 |
| 217 controllers_[device_handle] = gamepad; |
| 218 |
| 219 WebGamepad& pad = state->data; |
| 220 pad.connected = true; |
| 221 |
| 222 std::string vendor = base::StringPrintf("%04x", gamepad->vendor_id); |
| 223 std::string product = base::StringPrintf("%04x", gamepad->product_id); |
| 224 state->mapper = GetGamepadStandardMappingFunction(vendor, product); |
| 225 state->axis_mask = 0; |
| 226 state->button_mask = 0; |
| 227 |
| 228 swprintf(pad.id, WebGamepad::idLengthCap, |
| 229 L"%ls (%lsVendor: %04x Product: %04x)", gamepad->id, |
| 230 state->mapper ? L"STANDARD GAMEPAD " : L"", gamepad->vendor_id, |
| 231 gamepad->product_id); |
| 232 |
| 233 if (state->mapper) |
| 234 swprintf(pad.mapping, WebGamepad::mappingLengthCap, L"standard"); |
| 235 else |
| 236 pad.mapping[0] = 0; |
| 161 } | 237 } |
| 238 |
| 239 gamepad->enumeration_id = last_enumeration_id_; |
| 162 } | 240 } |
| 163 } | 241 } |
| 164 return valid_controllers; | |
| 165 } | |
| 166 | 242 |
| 167 RawGamepadInfo* RawInputDataFetcher::GetGamepadInfo(HANDLE handle) { | 243 // Clear out old controllers that weren't part of this enumeration pass. |
| 168 std::map<HANDLE, RawGamepadInfo*>::iterator it = controllers_.find(handle); | 244 for (const auto& controller : controllers_) { |
| 169 if (it != controllers_.end()) | 245 RawGamepadInfo* gamepad = controller.second; |
| 170 return it->second; | 246 if (gamepad->enumeration_id != last_enumeration_id_) { |
| 171 | 247 controllers_.erase(gamepad->handle); |
| 172 return NULL; | 248 delete gamepad; |
| 249 } |
| 250 } |
| 173 } | 251 } |
| 174 | 252 |
| 175 RawGamepadInfo* RawInputDataFetcher::ParseGamepadInfo(HANDLE hDevice) { | 253 RawGamepadInfo* RawInputDataFetcher::ParseGamepadInfo(HANDLE hDevice) { |
| 176 UINT size = 0; | 254 UINT size = 0; |
| 177 | 255 |
| 178 // Do we already have this device in the map? | |
| 179 if (GetGamepadInfo(hDevice)) | |
| 180 return NULL; | |
| 181 | |
| 182 // Query basic device info. | 256 // Query basic device info. |
| 183 UINT result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, NULL, &size); | 257 UINT result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, NULL, &size); |
| 184 if (result == static_cast<UINT>(-1)) { | 258 if (result == static_cast<UINT>(-1)) { |
| 185 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; | 259 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; |
| 186 return NULL; | 260 return NULL; |
| 187 } | 261 } |
| 188 DCHECK_EQ(0u, result); | 262 DCHECK_EQ(0u, result); |
| 189 | 263 |
| 190 std::unique_ptr<uint8_t[]> di_buffer(new uint8_t[size]); | 264 std::unique_ptr<uint8_t[]> di_buffer(new uint8_t[size]); |
| 191 RID_DEVICE_INFO* device_info = | 265 RID_DEVICE_INFO* device_info = |
| 192 reinterpret_cast<RID_DEVICE_INFO*>(di_buffer.get()); | 266 reinterpret_cast<RID_DEVICE_INFO*>(di_buffer.get()); |
| 193 result = | 267 result = |
| 194 GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, di_buffer.get(), &size); | 268 GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, di_buffer.get(), &size); |
| 195 if (result == static_cast<UINT>(-1)) { | 269 if (result == static_cast<UINT>(-1)) { |
| 196 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; | 270 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; |
| 197 return NULL; | 271 return NULL; |
| 198 } | 272 } |
| 199 DCHECK_EQ(size, result); | 273 DCHECK_EQ(size, result); |
| 200 | 274 |
| 201 // Make sure this device is of a type that we want to observe. | 275 // Make sure this device is of a type that we want to observe. |
| 202 bool valid_type = false; | 276 bool valid_type = false; |
| 203 for (USHORT device_usage : DeviceUsages) { | 277 for (USHORT device_usage : DeviceUsages) { |
| 204 if (device_info->hid.usUsage == device_usage) { | 278 if (device_info->hid.usUsage == device_usage) { |
| 205 valid_type = true; | 279 valid_type = true; |
| 206 break; | 280 break; |
| 207 } | 281 } |
| 208 } | 282 } |
| 209 | 283 |
| 284 // This is terrible, but the Oculus Rift seems to think it's a gamepad. |
| 285 // Filter out any Oculus devices. (We'll handle Oculus Touch elsewhere.) |
| 286 if (device_info->hid.dwVendorId == 0x2833) { |
| 287 valid_type = false; |
| 288 } |
| 289 |
| 210 if (!valid_type) | 290 if (!valid_type) |
| 211 return NULL; | 291 return NULL; |
| 212 | 292 |
| 213 std::unique_ptr<RawGamepadInfo> gamepad_info(new RawGamepadInfo); | 293 std::unique_ptr<RawGamepadInfo> gamepad_info(new RawGamepadInfo); |
| 294 gamepad_info->source_id = ++last_source_id_; |
| 214 gamepad_info->handle = hDevice; | 295 gamepad_info->handle = hDevice; |
| 215 gamepad_info->report_id = 0; | 296 gamepad_info->report_id = 0; |
| 216 gamepad_info->vendor_id = device_info->hid.dwVendorId; | 297 gamepad_info->vendor_id = device_info->hid.dwVendorId; |
| 217 gamepad_info->product_id = device_info->hid.dwProductId; | 298 gamepad_info->product_id = device_info->hid.dwProductId; |
| 218 gamepad_info->buttons_length = 0; | 299 gamepad_info->buttons_length = 0; |
| 219 ZeroMemory(gamepad_info->buttons, sizeof(gamepad_info->buttons)); | 300 ZeroMemory(gamepad_info->buttons, sizeof(gamepad_info->buttons)); |
| 220 gamepad_info->axes_length = 0; | 301 gamepad_info->axes_length = 0; |
| 221 ZeroMemory(gamepad_info->axes, sizeof(gamepad_info->axes)); | 302 ZeroMemory(gamepad_info->axes, sizeof(gamepad_info->axes)); |
| 222 | 303 |
| 223 // Query device identifier | 304 // Query device identifier |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 gamepad_info->axes_length = | 424 gamepad_info->axes_length = |
| 344 std::max(gamepad_info->axes_length, next_index + 1); | 425 std::max(gamepad_info->axes_length, next_index + 1); |
| 345 } | 426 } |
| 346 } | 427 } |
| 347 | 428 |
| 348 if (next_index >= WebGamepad::axesLengthCap) | 429 if (next_index >= WebGamepad::axesLengthCap) |
| 349 break; | 430 break; |
| 350 } | 431 } |
| 351 } | 432 } |
| 352 | 433 |
| 434 // Sometimes devices show up with no buttons or axes. Don't return these. |
| 435 if (gamepad_info->buttons_length == 0 && gamepad_info->axes_length == 0) |
| 436 return nullptr; |
| 437 |
| 353 return gamepad_info.release(); | 438 return gamepad_info.release(); |
| 354 } | 439 } |
| 355 | 440 |
| 356 void RawInputDataFetcher::UpdateGamepad(RAWINPUT* input, | 441 void RawInputDataFetcher::UpdateGamepad(RAWINPUT* input, |
| 357 RawGamepadInfo* gamepad_info) { | 442 RawGamepadInfo* gamepad_info) { |
| 358 NTSTATUS status; | 443 NTSTATUS status; |
| 359 | 444 |
| 360 gamepad_info->report_id++; | 445 gamepad_info->report_id++; |
| 361 | 446 |
| 362 // Query button state. | 447 // Query button state. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 result = GetRawInputData(input_handle, RID_INPUT, buffer.get(), &size, | 526 result = GetRawInputData(input_handle, RID_INPUT, buffer.get(), &size, |
| 442 sizeof(RAWINPUTHEADER)); | 527 sizeof(RAWINPUTHEADER)); |
| 443 if (result == static_cast<UINT>(-1)) { | 528 if (result == static_cast<UINT>(-1)) { |
| 444 PLOG(ERROR) << "GetRawInputData() failed"; | 529 PLOG(ERROR) << "GetRawInputData() failed"; |
| 445 return 0; | 530 return 0; |
| 446 } | 531 } |
| 447 DCHECK_EQ(size, result); | 532 DCHECK_EQ(size, result); |
| 448 | 533 |
| 449 // Notify the observer about events generated locally. | 534 // Notify the observer about events generated locally. |
| 450 if (input->header.dwType == RIM_TYPEHID && input->header.hDevice != NULL) { | 535 if (input->header.dwType == RIM_TYPEHID && input->header.hDevice != NULL) { |
| 451 RawGamepadInfo* gamepad = GetGamepadInfo(input->header.hDevice); | 536 ControllerMap::iterator it = controllers_.find(input->header.hDevice); |
| 452 if (gamepad) | 537 if (it != controllers_.end()) |
| 453 UpdateGamepad(input, gamepad); | 538 UpdateGamepad(input, it->second); |
| 454 } | 539 } |
| 455 | 540 |
| 456 return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER)); | 541 return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER)); |
| 457 } | 542 } |
| 458 | 543 |
| 459 bool RawInputDataFetcher::HandleMessage(UINT message, | 544 bool RawInputDataFetcher::HandleMessage(UINT message, |
| 460 WPARAM wparam, | 545 WPARAM wparam, |
| 461 LPARAM lparam, | 546 LPARAM lparam, |
| 462 LRESULT* result) { | 547 LRESULT* result) { |
| 463 switch (message) { | 548 switch (message) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 return false; | 593 return false; |
| 509 hidd_get_product_string_ = reinterpret_cast<HidDGetStringFunc>( | 594 hidd_get_product_string_ = reinterpret_cast<HidDGetStringFunc>( |
| 510 hid_dll_.GetFunctionPointer("HidD_GetProductString")); | 595 hid_dll_.GetFunctionPointer("HidD_GetProductString")); |
| 511 if (!hidd_get_product_string_) | 596 if (!hidd_get_product_string_) |
| 512 return false; | 597 return false; |
| 513 | 598 |
| 514 return true; | 599 return true; |
| 515 } | 600 } |
| 516 | 601 |
| 517 } // namespace device | 602 } // namespace device |
| OLD | NEW |