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

Side by Side Diff: device/gamepad/raw_input_data_fetcher_win.cc

Issue 2129003002: Refactored gamepad polling to support dynamic sources (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed unit test issue and Mac XBoxDataFetcher constructor Created 4 years, 5 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 unified diff | Download patch
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698