Chromium Code Reviews| 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 "content/browser/gamepad/raw_input_data_fetcher_win.h" | 5 #include "content/browser/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/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" |
| 11 #include "content/common/gamepad_hardware_buffer.h" | |
| 12 #include "content/common/gamepad_messages.h" | 11 #include "content/common/gamepad_messages.h" |
| 13 | 12 |
| 14 namespace content { | 13 namespace content { |
| 15 | 14 |
| 16 using namespace blink; | 15 using namespace blink; |
| 17 | 16 |
| 18 namespace { | 17 namespace { |
| 19 | 18 |
| 20 float NormalizeAxis(long value, long min, long max) { | 19 float NormalizeAxis(long value, long min, long max) { |
| 21 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 15 matching lines...) Expand all Loading... | |
| 37 | 36 |
| 38 } // namespace | 37 } // namespace |
| 39 | 38 |
| 40 RawGamepadInfo::RawGamepadInfo() { | 39 RawGamepadInfo::RawGamepadInfo() { |
| 41 } | 40 } |
| 42 | 41 |
| 43 RawGamepadInfo::~RawGamepadInfo() { | 42 RawGamepadInfo::~RawGamepadInfo() { |
| 44 } | 43 } |
| 45 | 44 |
| 46 RawInputDataFetcher::RawInputDataFetcher() | 45 RawInputDataFetcher::RawInputDataFetcher() |
| 47 : hid_dll_(base::FilePath(FILE_PATH_LITERAL("hid.dll"))), | 46 : rawinput_available_(false), |
| 48 rawinput_available_(GetHidDllFunctions()), | |
| 49 filter_xinput_(true), | 47 filter_xinput_(true), |
| 50 events_monitored_(false) { | 48 events_monitored_(false), |
| 49 last_source_id_(0), | |
| 50 last_enumeration_id_(0) { | |
| 51 } | 51 } |
| 52 | 52 |
| 53 RawInputDataFetcher::~RawInputDataFetcher() { | 53 RawInputDataFetcher::~RawInputDataFetcher() { |
| 54 ClearControllers(); | 54 ClearControllers(); |
| 55 DCHECK(!window_); | 55 DCHECK(!window_); |
| 56 DCHECK(!events_monitored_); | 56 DCHECK(!events_monitored_); |
| 57 } | 57 } |
| 58 | 58 |
| 59 void RawInputDataFetcher::WillDestroyCurrentMessageLoop() { | 59 void RawInputDataFetcher::WillDestroyCurrentMessageLoop() { |
| 60 StopMonitor(); | 60 StopMonitor(); |
| 61 } | 61 } |
| 62 | 62 |
| 63 void RawInputDataFetcher::OnAddedToProvider() { | |
| 64 hid_dll_.Reset(base::LoadNativeLibrary( | |
| 65 base::FilePath(FILE_PATH_LITERAL("hid.dll")), nullptr)); | |
| 66 rawinput_available_ = GetHidDllFunctions(); | |
| 67 } | |
| 68 | |
| 63 RAWINPUTDEVICE* RawInputDataFetcher::GetRawInputDevices(DWORD flags) { | 69 RAWINPUTDEVICE* RawInputDataFetcher::GetRawInputDevices(DWORD flags) { |
| 64 size_t usage_count = arraysize(DeviceUsages); | 70 size_t usage_count = arraysize(DeviceUsages); |
| 65 scoped_ptr<RAWINPUTDEVICE[]> devices(new RAWINPUTDEVICE[usage_count]); | 71 scoped_ptr<RAWINPUTDEVICE[]> devices(new RAWINPUTDEVICE[usage_count]); |
| 66 for (size_t i = 0; i < usage_count; ++i) { | 72 for (size_t i = 0; i < usage_count; ++i) { |
| 67 devices[i].dwFlags = flags; | 73 devices[i].dwFlags = flags; |
| 68 devices[i].usUsagePage = 1; | 74 devices[i].usUsagePage = 1; |
| 69 devices[i].usUsage = DeviceUsages[i]; | 75 devices[i].usUsage = DeviceUsages[i]; |
| 70 devices[i].hwndTarget = (flags & RIDEV_REMOVE) ? 0 : window_->hwnd(); | 76 devices[i].hwndTarget = (flags & RIDEV_REMOVE) ? 0 : window_->hwnd(); |
| 71 } | 77 } |
| 72 return devices.release(); | 78 return devices.release(); |
| 73 } | 79 } |
| 74 | 80 |
| 81 void RawInputDataFetcher::PauseHint(bool pause) { | |
| 82 if (pause) | |
| 83 StopMonitor(); | |
| 84 else | |
| 85 StartMonitor(); | |
| 86 } | |
| 87 | |
| 75 void RawInputDataFetcher::StartMonitor() { | 88 void RawInputDataFetcher::StartMonitor() { |
| 76 if (!rawinput_available_ || events_monitored_) | 89 if (!rawinput_available_ || events_monitored_) |
| 77 return; | 90 return; |
| 78 | 91 |
| 79 if (!window_) { | 92 if (!window_) { |
| 80 window_.reset(new base::win::MessageWindow()); | 93 window_.reset(new base::win::MessageWindow()); |
| 81 if (!window_->Create(base::Bind(&RawInputDataFetcher::HandleMessage, | 94 if (!window_->Create(base::Bind(&RawInputDataFetcher::HandleMessage, |
| 82 base::Unretained(this)))) { | 95 base::Unretained(this)))) { |
| 83 PLOG(ERROR) << "Failed to create the raw input window"; | 96 PLOG(ERROR) << "Failed to create the raw input window"; |
| 84 window_.reset(); | 97 window_.reset(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 } | 137 } |
| 125 | 138 |
| 126 void RawInputDataFetcher::ClearControllers() { | 139 void RawInputDataFetcher::ClearControllers() { |
| 127 while (!controllers_.empty()) { | 140 while (!controllers_.empty()) { |
| 128 RawGamepadInfo* gamepad_info = controllers_.begin()->second; | 141 RawGamepadInfo* gamepad_info = controllers_.begin()->second; |
| 129 controllers_.erase(gamepad_info->handle); | 142 controllers_.erase(gamepad_info->handle); |
| 130 delete gamepad_info; | 143 delete gamepad_info; |
| 131 } | 144 } |
| 132 } | 145 } |
| 133 | 146 |
| 134 std::vector<RawGamepadInfo*> RawInputDataFetcher::EnumerateDevices() { | 147 void RawInputDataFetcher::GetGamepadData(bool devices_changed_hint) { |
| 135 std::vector<RawGamepadInfo*> valid_controllers; | 148 if (!rawinput_available_) |
| 149 return; | |
| 136 | 150 |
| 137 ClearControllers(); | 151 if (devices_changed_hint) |
| 152 EnumerateDevices(); | |
| 153 | |
| 154 for (const auto& controller : controllers_) { | |
| 155 RawGamepadInfo* gamepad = controller.second; | |
| 156 PadState* state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_RAW, | |
| 157 gamepad->source_id); | |
| 158 if (!state) | |
| 159 continue; | |
| 160 | |
| 161 WebGamepad& pad = state->data; | |
| 162 | |
| 163 pad.timestamp = gamepad->report_id; | |
| 164 pad.buttonsLength = gamepad->buttons_length; | |
| 165 pad.axesLength = gamepad->axes_length; | |
| 166 | |
| 167 for (unsigned int i = 0; i < pad.buttonsLength; i++) { | |
| 168 pad.buttons[i].pressed = gamepad->buttons[i]; | |
| 169 pad.buttons[i].value = gamepad->buttons[i] ? 1.0 : 0.0; | |
| 170 } | |
| 171 | |
| 172 for (unsigned int i = 0; i < pad.axesLength; i++) | |
| 173 pad.axes[i] = gamepad->axes[i].value; | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 void RawInputDataFetcher::EnumerateDevices() { | |
| 178 last_enumeration_id_++; | |
| 138 | 179 |
| 139 UINT count = 0; | 180 UINT count = 0; |
| 140 UINT result = GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)); | 181 UINT result = GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)); |
| 141 if (result == static_cast<UINT>(-1)) { | 182 if (result == static_cast<UINT>(-1)) { |
| 142 PLOG(ERROR) << "GetRawInputDeviceList() failed"; | 183 PLOG(ERROR) << "GetRawInputDeviceList() failed"; |
| 143 return valid_controllers; | 184 return; |
| 144 } | 185 } |
| 145 DCHECK_EQ(0u, result); | 186 DCHECK_EQ(0u, result); |
| 146 | 187 |
| 147 scoped_ptr<RAWINPUTDEVICELIST[]> device_list(new RAWINPUTDEVICELIST[count]); | 188 scoped_ptr<RAWINPUTDEVICELIST[]> device_list(new RAWINPUTDEVICELIST[count]); |
| 148 result = GetRawInputDeviceList(device_list.get(), &count, | 189 result = GetRawInputDeviceList(device_list.get(), &count, |
| 149 sizeof(RAWINPUTDEVICELIST)); | 190 sizeof(RAWINPUTDEVICELIST)); |
| 150 if (result == static_cast<UINT>(-1)) { | 191 if (result == static_cast<UINT>(-1)) { |
| 151 PLOG(ERROR) << "GetRawInputDeviceList() failed"; | 192 PLOG(ERROR) << "GetRawInputDeviceList() failed"; |
| 152 return valid_controllers; | 193 return; |
| 153 } | 194 } |
| 154 DCHECK_EQ(count, result); | 195 DCHECK_EQ(count, result); |
| 155 | 196 |
| 156 for (UINT i = 0; i < count; ++i) { | 197 for (UINT i = 0; i < count; ++i) { |
| 157 if (device_list[i].dwType == RIM_TYPEHID) { | 198 if (device_list[i].dwType == RIM_TYPEHID) { |
| 158 HANDLE device_handle = device_list[i].hDevice; | 199 HANDLE device_handle = device_list[i].hDevice; |
| 159 RawGamepadInfo* gamepad_info = ParseGamepadInfo(device_handle); | 200 ControllerMap::iterator controller = controllers_.find(device_handle); |
| 160 if (gamepad_info) { | 201 |
| 161 controllers_[device_handle] = gamepad_info; | 202 RawGamepadInfo* gamepad; |
| 162 valid_controllers.push_back(gamepad_info); | 203 if (controller != controllers_.end()) { |
| 204 gamepad = controller->second; | |
| 205 } else { | |
| 206 gamepad = ParseGamepadInfo(device_handle); | |
| 207 if (!gamepad) | |
| 208 continue; | |
| 209 | |
| 210 PadState* state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_RAW, | |
| 211 gamepad->source_id); | |
| 212 if (!state) | |
| 213 continue; // No slot available for this gamepad. | |
| 214 | |
| 215 controllers_[device_handle] = gamepad; | |
| 216 | |
| 217 WebGamepad& pad = state->data; | |
| 218 pad.connected = true; | |
| 219 | |
| 220 std::string vendor = base::StringPrintf("%04x", gamepad->vendor_id); | |
| 221 std::string product = base::StringPrintf("%04x", gamepad->product_id); | |
| 222 state->mapper = GetGamepadStandardMappingFunction(vendor, product); | |
| 223 state->axis_mask = 0; | |
| 224 state->button_mask = 0; | |
| 225 | |
| 226 swprintf(pad.id, WebGamepad::idLengthCap, | |
| 227 L"%ls (%lsVendor: %04x Product: %04x)", | |
| 228 gamepad->id, state->mapper ? L"STANDARD GAMEPAD " : L"", | |
| 229 gamepad->vendor_id, gamepad->product_id); | |
| 230 | |
| 231 if (state->mapper) | |
| 232 swprintf(pad.mapping, WebGamepad::mappingLengthCap, L"standard"); | |
| 233 else | |
| 234 pad.mapping[0] = 0; | |
| 163 } | 235 } |
| 236 | |
| 237 gamepad->enumeration_id = last_enumeration_id_; | |
| 164 } | 238 } |
| 165 } | 239 } |
| 166 return valid_controllers; | |
| 167 } | |
| 168 | 240 |
| 169 RawGamepadInfo* RawInputDataFetcher::GetGamepadInfo(HANDLE handle) { | 241 // Clear out old controllers that weren't part of this enumeration pass. |
| 170 std::map<HANDLE, RawGamepadInfo*>::iterator it = controllers_.find(handle); | 242 for (const auto& controller : controllers_) { |
| 171 if (it != controllers_.end()) | 243 RawGamepadInfo* gamepad = controller.second; |
| 172 return it->second; | 244 if (gamepad->enumeration_id != last_enumeration_id_) { |
| 245 controllers_.erase(gamepad->handle); | |
| 246 delete gamepad; | |
| 247 } | |
| 248 } | |
| 173 | 249 |
| 174 return NULL; | 250 return; |
| 175 } | 251 } |
| 176 | 252 |
| 177 RawGamepadInfo* RawInputDataFetcher::ParseGamepadInfo(HANDLE hDevice) { | 253 RawGamepadInfo* RawInputDataFetcher::ParseGamepadInfo(HANDLE hDevice) { |
| 178 UINT size = 0; | 254 UINT size = 0; |
| 179 | 255 |
| 180 // Do we already have this device in the map? | |
| 181 if (GetGamepadInfo(hDevice)) | |
| 182 return NULL; | |
| 183 | |
| 184 // Query basic device info. | 256 // Query basic device info. |
| 185 UINT result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, | 257 UINT result = GetRawInputDeviceInfo(hDevice, RIDI_DEVICEINFO, |
| 186 NULL, &size); | 258 NULL, &size); |
| 187 if (result == static_cast<UINT>(-1)) { | 259 if (result == static_cast<UINT>(-1)) { |
| 188 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; | 260 PLOG(ERROR) << "GetRawInputDeviceInfo() failed"; |
| 189 return NULL; | 261 return NULL; |
| 190 } | 262 } |
| 191 DCHECK_EQ(0u, result); | 263 DCHECK_EQ(0u, result); |
| 192 | 264 |
| 193 scoped_ptr<uint8_t[]> di_buffer(new uint8_t[size]); | 265 scoped_ptr<uint8_t[]> di_buffer(new uint8_t[size]); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 207 if (device_info->hid.usUsage == device_usage) { | 279 if (device_info->hid.usUsage == device_usage) { |
| 208 valid_type = true; | 280 valid_type = true; |
| 209 break; | 281 break; |
| 210 } | 282 } |
| 211 } | 283 } |
| 212 | 284 |
| 213 if (!valid_type) | 285 if (!valid_type) |
| 214 return NULL; | 286 return NULL; |
| 215 | 287 |
| 216 scoped_ptr<RawGamepadInfo> gamepad_info(new RawGamepadInfo); | 288 scoped_ptr<RawGamepadInfo> gamepad_info(new RawGamepadInfo); |
| 289 gamepad_info->source_id = ++last_source_id_; | |
|
scottmg
2016/01/18 22:54:52
Initialize enumeration_id here maybe? I can't tell
bajones
2016/01/20 22:49:32
I don't think it can be, but it also doesn't hurt
| |
| 217 gamepad_info->handle = hDevice; | 290 gamepad_info->handle = hDevice; |
| 218 gamepad_info->report_id = 0; | 291 gamepad_info->report_id = 0; |
| 219 gamepad_info->vendor_id = device_info->hid.dwVendorId; | 292 gamepad_info->vendor_id = device_info->hid.dwVendorId; |
| 220 gamepad_info->product_id = device_info->hid.dwProductId; | 293 gamepad_info->product_id = device_info->hid.dwProductId; |
| 221 gamepad_info->buttons_length = 0; | 294 gamepad_info->buttons_length = 0; |
| 222 ZeroMemory(gamepad_info->buttons, sizeof(gamepad_info->buttons)); | 295 ZeroMemory(gamepad_info->buttons, sizeof(gamepad_info->buttons)); |
| 223 gamepad_info->axes_length = 0; | 296 gamepad_info->axes_length = 0; |
| 224 ZeroMemory(gamepad_info->axes, sizeof(gamepad_info->axes)); | 297 ZeroMemory(gamepad_info->axes, sizeof(gamepad_info->axes)); |
| 225 | 298 |
| 226 // Query device identifier | 299 // Query device identifier |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 gamepad_info->axes_length = | 419 gamepad_info->axes_length = |
| 347 std::max(gamepad_info->axes_length, next_index + 1); | 420 std::max(gamepad_info->axes_length, next_index + 1); |
| 348 } | 421 } |
| 349 } | 422 } |
| 350 | 423 |
| 351 if (next_index >= WebGamepad::axesLengthCap) | 424 if (next_index >= WebGamepad::axesLengthCap) |
| 352 break; | 425 break; |
| 353 } | 426 } |
| 354 } | 427 } |
| 355 | 428 |
| 429 // Sometimes devices show up with no buttons or axes. Don't return these. | |
| 430 if (gamepad_info->buttons_length == 0 && gamepad_info->axes_length == 0) | |
| 431 return nullptr; | |
| 432 | |
| 356 return gamepad_info.release(); | 433 return gamepad_info.release(); |
| 357 } | 434 } |
| 358 | 435 |
| 359 void RawInputDataFetcher::UpdateGamepad( | 436 void RawInputDataFetcher::UpdateGamepad( |
| 360 RAWINPUT* input, | 437 RAWINPUT* input, |
| 361 RawGamepadInfo* gamepad_info) { | 438 RawGamepadInfo* gamepad_info) { |
| 362 NTSTATUS status; | 439 NTSTATUS status; |
| 363 | 440 |
| 364 gamepad_info->report_id++; | 441 gamepad_info->report_id++; |
| 365 | 442 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 450 result = GetRawInputData( | 527 result = GetRawInputData( |
| 451 input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER)); | 528 input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER)); |
| 452 if (result == static_cast<UINT>(-1)) { | 529 if (result == static_cast<UINT>(-1)) { |
| 453 PLOG(ERROR) << "GetRawInputData() failed"; | 530 PLOG(ERROR) << "GetRawInputData() failed"; |
| 454 return 0; | 531 return 0; |
| 455 } | 532 } |
| 456 DCHECK_EQ(size, result); | 533 DCHECK_EQ(size, result); |
| 457 | 534 |
| 458 // Notify the observer about events generated locally. | 535 // Notify the observer about events generated locally. |
| 459 if (input->header.dwType == RIM_TYPEHID && input->header.hDevice != NULL) { | 536 if (input->header.dwType == RIM_TYPEHID && input->header.hDevice != NULL) { |
| 460 RawGamepadInfo* gamepad = GetGamepadInfo(input->header.hDevice); | 537 ControllerMap::iterator it = controllers_.find(input->header.hDevice); |
| 461 if (gamepad) | 538 if (it != controllers_.end()) |
| 462 UpdateGamepad(input, gamepad); | 539 UpdateGamepad(input, it->second); |
| 463 } | 540 } |
| 464 | 541 |
| 465 return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER)); | 542 return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER)); |
| 466 } | 543 } |
| 467 | 544 |
| 468 bool RawInputDataFetcher::HandleMessage(UINT message, | 545 bool RawInputDataFetcher::HandleMessage(UINT message, |
| 469 WPARAM wparam, | 546 WPARAM wparam, |
| 470 LPARAM lparam, | 547 LPARAM lparam, |
| 471 LRESULT* result) { | 548 LRESULT* result) { |
| 472 switch (message) { | 549 switch (message) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 516 return false; | 593 return false; |
| 517 hidd_get_product_string_ = reinterpret_cast<HidDGetStringFunc>( | 594 hidd_get_product_string_ = reinterpret_cast<HidDGetStringFunc>( |
| 518 hid_dll_.GetFunctionPointer("HidD_GetProductString")); | 595 hid_dll_.GetFunctionPointer("HidD_GetProductString")); |
| 519 if (!hidd_get_product_string_) | 596 if (!hidd_get_product_string_) |
| 520 return false; | 597 return false; |
| 521 | 598 |
| 522 return true; | 599 return true; |
| 523 } | 600 } |
| 524 | 601 |
| 525 } // namespace content | 602 } // namespace content |
| OLD | NEW |