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

Side by Side Diff: device/gamepad/gamepad_platform_data_fetcher_mac.mm

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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/gamepad_platform_data_fetcher_mac.h" 5 #include "device/gamepad/gamepad_platform_data_fetcher_mac.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <string.h> 8 #include <string.h>
9 9
10 #include "base/mac/foundation_util.h" 10 #include "base/mac/foundation_util.h"
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 const uint32_t kJoystickUsageNumber = 0x04; 67 const uint32_t kJoystickUsageNumber = 0x04;
68 const uint32_t kGameUsageNumber = 0x05; 68 const uint32_t kGameUsageNumber = 0x05;
69 const uint32_t kMultiAxisUsageNumber = 0x08; 69 const uint32_t kMultiAxisUsageNumber = 0x08;
70 const uint32_t kAxisMinimumUsageNumber = 0x30; 70 const uint32_t kAxisMinimumUsageNumber = 0x30;
71 71
72 } // namespace 72 } // namespace
73 73
74 GamepadPlatformDataFetcherMac::GamepadPlatformDataFetcherMac() 74 GamepadPlatformDataFetcherMac::GamepadPlatformDataFetcherMac()
75 : enabled_(true), paused_(false) { 75 : enabled_(true), paused_(false) {
76 memset(associated_, 0, sizeof(associated_)); 76 memset(associated_, 0, sizeof(associated_));
77 }
77 78
78 xbox_fetcher_.reset(new XboxDataFetcher(this)); 79 GamepadSource GamepadPlatformDataFetcherMac::source() {
79 if (!xbox_fetcher_->RegisterForNotifications()) 80 return Factory::static_source();
80 xbox_fetcher_.reset(); 81 }
81 82
83 void GamepadPlatformDataFetcherMac::OnAddedToProvider() {
82 hid_manager_ref_.reset( 84 hid_manager_ref_.reset(
83 IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone)); 85 IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone));
84 if (CFGetTypeID(hid_manager_ref_) != IOHIDManagerGetTypeID()) { 86 if (CFGetTypeID(hid_manager_ref_) != IOHIDManagerGetTypeID()) {
85 enabled_ = false; 87 enabled_ = false;
86 return; 88 return;
87 } 89 }
88 90
89 base::scoped_nsobject<NSArray> criteria( 91 base::scoped_nsobject<NSArray> criteria(
90 [[NSArray alloc] initWithObjects:DeviceMatching(kGenericDesktopUsagePage, 92 [[NSArray alloc] initWithObjects:DeviceMatching(kGenericDesktopUsagePage,
91 kJoystickUsageNumber), 93 kJoystickUsageNumber),
(...skipping 17 matching lines...) Expand all
109 111
110 // Register for value change notifications. 112 // Register for value change notifications.
111 IOHIDManagerRegisterInputValueCallback(hid_manager_ref_, ValueChangedCallback, 113 IOHIDManagerRegisterInputValueCallback(hid_manager_ref_, ValueChangedCallback,
112 this); 114 this);
113 115
114 IOHIDManagerScheduleWithRunLoop(hid_manager_ref_, CFRunLoopGetMain(), 116 IOHIDManagerScheduleWithRunLoop(hid_manager_ref_, CFRunLoopGetMain(),
115 kCFRunLoopDefaultMode); 117 kCFRunLoopDefaultMode);
116 118
117 enabled_ = IOHIDManagerOpen(hid_manager_ref_, kIOHIDOptionsTypeNone) == 119 enabled_ = IOHIDManagerOpen(hid_manager_ref_, kIOHIDOptionsTypeNone) ==
118 kIOReturnSuccess; 120 kIOReturnSuccess;
119
120 if (xbox_fetcher_)
121 xbox_fetcher_->RegisterForNotifications();
122 } 121 }
123 122
124 void GamepadPlatformDataFetcherMac::UnregisterFromNotifications() { 123 void GamepadPlatformDataFetcherMac::UnregisterFromNotifications() {
125 IOHIDManagerUnscheduleFromRunLoop(hid_manager_ref_, CFRunLoopGetCurrent(), 124 IOHIDManagerUnscheduleFromRunLoop(hid_manager_ref_, CFRunLoopGetCurrent(),
126 kCFRunLoopDefaultMode); 125 kCFRunLoopDefaultMode);
127 IOHIDManagerClose(hid_manager_ref_, kIOHIDOptionsTypeNone); 126 IOHIDManagerClose(hid_manager_ref_, kIOHIDOptionsTypeNone);
128 if (xbox_fetcher_)
129 xbox_fetcher_->UnregisterFromNotifications();
130 } 127 }
131 128
132 void GamepadPlatformDataFetcherMac::PauseHint(bool pause) { 129 void GamepadPlatformDataFetcherMac::PauseHint(bool pause) {
133 paused_ = pause; 130 paused_ = pause;
134 } 131 }
135 132
136 GamepadPlatformDataFetcherMac::~GamepadPlatformDataFetcherMac() { 133 GamepadPlatformDataFetcherMac::~GamepadPlatformDataFetcherMac() {
137 UnregisterFromNotifications(); 134 UnregisterFromNotifications();
138 } 135 }
139 136
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 if (usage == kJoystickUsageNumber || usage == kGameUsageNumber || 170 if (usage == kJoystickUsageNumber || usage == kGameUsageNumber ||
174 usage == kMultiAxisUsageNumber) { 171 usage == kMultiAxisUsageNumber) {
175 return true; 172 return true;
176 } 173 }
177 } 174 }
178 } 175 }
179 return false; 176 return false;
180 } 177 }
181 178
182 bool GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements, 179 bool GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements,
180 PadState* state,
183 size_t slot) { 181 size_t slot) {
184 WebGamepad& pad = pad_state_[slot].data; 182 WebGamepad& pad = state->data;
185 AssociatedData& associated = associated_[slot]; 183 AssociatedData& associated = associated_[slot];
186 CHECK(!associated.is_xbox);
187 184
188 pad.axesLength = 0; 185 pad.axesLength = 0;
189 pad.buttonsLength = 0; 186 pad.buttonsLength = 0;
190 pad.timestamp = 0; 187 pad.timestamp = 0;
191 memset(pad.axes, 0, sizeof(pad.axes)); 188 memset(pad.axes, 0, sizeof(pad.axes));
192 memset(pad.buttons, 0, sizeof(pad.buttons)); 189 memset(pad.buttons, 0, sizeof(pad.buttons));
193 190
194 bool mapped_all_axes = true; 191 bool mapped_all_axes = true;
195 192
196 for (id elem in elements) { 193 for (id elem in elements) {
197 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem); 194 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem);
198 if (!CheckCollection(element)) 195 if (!CheckCollection(element))
199 continue; 196 continue;
200 197
201 uint32_t usage_page = IOHIDElementGetUsagePage(element); 198 uint32_t usage_page = IOHIDElementGetUsagePage(element);
202 uint32_t usage = IOHIDElementGetUsage(element); 199 uint32_t usage = IOHIDElementGetUsage(element);
203 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Button && 200 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Button &&
204 usage_page == kButtonUsagePage) { 201 usage_page == kButtonUsagePage) {
205 uint32_t button_index = usage - 1; 202 uint32_t button_index = usage - 1;
206 if (button_index < WebGamepad::buttonsLengthCap) { 203 if (button_index < WebGamepad::buttonsLengthCap) {
207 associated.hid.button_elements[button_index] = element; 204 associated.button_elements[button_index] = element;
208 pad.buttonsLength = std::max(pad.buttonsLength, button_index + 1); 205 pad.buttonsLength = std::max(pad.buttonsLength, button_index + 1);
209 } 206 }
210 } else if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc) { 207 } else if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc) {
211 uint32_t axis_index = usage - kAxisMinimumUsageNumber; 208 uint32_t axis_index = usage - kAxisMinimumUsageNumber;
212 if (axis_index < WebGamepad::axesLengthCap) { 209 if (axis_index < WebGamepad::axesLengthCap) {
213 associated.hid.axis_elements[axis_index] = element; 210 associated.axis_elements[axis_index] = element;
214 pad.axesLength = std::max(pad.axesLength, axis_index + 1); 211 pad.axesLength = std::max(pad.axesLength, axis_index + 1);
215 } else { 212 } else {
216 mapped_all_axes = false; 213 mapped_all_axes = false;
217 } 214 }
218 } 215 }
219 } 216 }
220 217
221 if (!mapped_all_axes) { 218 if (!mapped_all_axes) {
222 // For axes who's usage puts them outside the standard axesLengthCap range. 219 // For axes who's usage puts them outside the standard axesLengthCap range.
223 uint32_t next_index = 0; 220 uint32_t next_index = 0;
224 for (id elem in elements) { 221 for (id elem in elements) {
225 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem); 222 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem);
226 if (!CheckCollection(element)) 223 if (!CheckCollection(element))
227 continue; 224 continue;
228 225
229 uint32_t usage_page = IOHIDElementGetUsagePage(element); 226 uint32_t usage_page = IOHIDElementGetUsagePage(element);
230 uint32_t usage = IOHIDElementGetUsage(element); 227 uint32_t usage = IOHIDElementGetUsage(element);
231 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc && 228 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc &&
232 usage - kAxisMinimumUsageNumber >= WebGamepad::axesLengthCap && 229 usage - kAxisMinimumUsageNumber >= WebGamepad::axesLengthCap &&
233 usage_page <= kGameControlsUsagePage) { 230 usage_page <= kGameControlsUsagePage) {
234 for (; next_index < WebGamepad::axesLengthCap; ++next_index) { 231 for (; next_index < WebGamepad::axesLengthCap; ++next_index) {
235 if (associated.hid.axis_elements[next_index] == NULL) 232 if (associated.axis_elements[next_index] == NULL)
236 break; 233 break;
237 } 234 }
238 if (next_index < WebGamepad::axesLengthCap) { 235 if (next_index < WebGamepad::axesLengthCap) {
239 associated.hid.axis_elements[next_index] = element; 236 associated.axis_elements[next_index] = element;
240 pad.axesLength = std::max(pad.axesLength, next_index + 1); 237 pad.axesLength = std::max(pad.axesLength, next_index + 1);
241 } 238 }
242 } 239 }
243 240
244 if (next_index >= WebGamepad::axesLengthCap) 241 if (next_index >= WebGamepad::axesLengthCap)
245 break; 242 break;
246 } 243 }
247 } 244 }
248 245
249 for (uint32_t axis_index = 0; axis_index < pad.axesLength; ++axis_index) { 246 for (uint32_t axis_index = 0; axis_index < pad.axesLength; ++axis_index) {
250 IOHIDElementRef element = associated.hid.axis_elements[axis_index]; 247 IOHIDElementRef element = associated.axis_elements[axis_index];
251 if (element != NULL) { 248 if (element != NULL) {
252 CFIndex axis_min = IOHIDElementGetLogicalMin(element); 249 CFIndex axis_min = IOHIDElementGetLogicalMin(element);
253 CFIndex axis_max = IOHIDElementGetLogicalMax(element); 250 CFIndex axis_max = IOHIDElementGetLogicalMax(element);
254 251
255 // Some HID axes report a logical range of -1 to 0 signed, which must be 252 // Some HID axes report a logical range of -1 to 0 signed, which must be
256 // interpreted as 0 to -1 unsigned for correct normalization behavior. 253 // interpreted as 0 to -1 unsigned for correct normalization behavior.
257 if (axis_min == -1 && axis_max == 0) { 254 if (axis_min == -1 && axis_max == 0) {
258 axis_max = -1; 255 axis_max = -1;
259 axis_min = 0; 256 axis_min = 0;
260 } 257 }
261 258
262 associated.hid.axis_minimums[axis_index] = axis_min; 259 associated.axis_minimums[axis_index] = axis_min;
263 associated.hid.axis_maximums[axis_index] = axis_max; 260 associated.axis_maximums[axis_index] = axis_max;
264 associated.hid.axis_report_sizes[axis_index] = 261 associated.axis_report_sizes[axis_index] =
265 IOHIDElementGetReportSize(element); 262 IOHIDElementGetReportSize(element);
266 } 263 }
267 } 264 }
268 265
269 return (pad.axesLength > 0 || pad.buttonsLength > 0); 266 return (pad.axesLength > 0 || pad.buttonsLength > 0);
270 } 267 }
271 268
272 size_t GamepadPlatformDataFetcherMac::GetEmptySlot() { 269 size_t GamepadPlatformDataFetcherMac::GetEmptySlot() {
273 // Find a free slot for this device. 270 // Find a free slot for this device.
274 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { 271 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
275 if (!pad_state_[slot].data.connected) 272 if (associated_[slot].device_ref == nullptr)
276 return slot; 273 return slot;
277 } 274 }
278 return WebGamepads::itemsLengthCap; 275 return WebGamepads::itemsLengthCap;
279 } 276 }
280 277
281 size_t GamepadPlatformDataFetcherMac::GetSlotForDevice(IOHIDDeviceRef device) { 278 size_t GamepadPlatformDataFetcherMac::GetSlotForDevice(IOHIDDeviceRef device) {
282 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { 279 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
283 // If we already have this device, and it's already connected, don't do 280 // If we already have this device, and it's already connected, don't do
284 // anything now. 281 // anything now.
285 if (pad_state_[slot].data.connected && !associated_[slot].is_xbox && 282 if (associated_[slot].device_ref == device)
286 associated_[slot].hid.device_ref == device)
287 return WebGamepads::itemsLengthCap; 283 return WebGamepads::itemsLengthCap;
288 } 284 }
289 return GetEmptySlot(); 285 return GetEmptySlot();
290 } 286 }
291 287
292 size_t GamepadPlatformDataFetcherMac::GetSlotForXboxDevice(
293 XboxController* device) {
294 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
295 if (associated_[slot].is_xbox &&
296 associated_[slot].xbox.location_id == device->location_id()) {
297 if (pad_state_[slot].data.connected) {
298 // The device is already connected. No idea why we got a second "device
299 // added" call, but let's not add it twice.
300 DCHECK_EQ(associated_[slot].xbox.device, device);
301 return WebGamepads::itemsLengthCap;
302 } else {
303 // A device with the same location ID was previously connected, so put
304 // it in the same slot.
305 return slot;
306 }
307 }
308 }
309 return GetEmptySlot();
310 }
311
312 void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) { 288 void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
313 using base::mac::CFToNSCast; 289 using base::mac::CFToNSCast;
314 using base::mac::CFCastStrict; 290 using base::mac::CFCastStrict;
315 291
316 if (!enabled_) 292 if (!enabled_)
317 return; 293 return;
318 294
295 NSNumber* location_id = CFToNSCast(CFCastStrict<CFNumberRef>(
296 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey))));
297 int location_int = [location_id intValue];
298
319 // Find an index for this device. 299 // Find an index for this device.
320 size_t slot = GetSlotForDevice(device); 300 size_t slot = GetSlotForDevice(device);
321 301
322 // We can't handle this many connected devices. 302 // We can't handle this many connected devices.
323 if (slot == WebGamepads::itemsLengthCap) 303 if (slot == WebGamepads::itemsLengthCap)
324 return; 304 return;
325 305
326 // Clear some state that may have been left behind by previous gamepads 306 // Clear some state that may have been left behind by previous gamepads
327 memset(&associated_[slot], 0, sizeof(AssociatedData)); 307 memset(&associated_[slot], 0, sizeof(AssociatedData));
328 308
309 PadState* state = GetPadState(location_int);
310 if (!state)
311 return; // No available slot for this device
312
329 NSNumber* vendor_id = CFToNSCast(CFCastStrict<CFNumberRef>( 313 NSNumber* vendor_id = CFToNSCast(CFCastStrict<CFNumberRef>(
330 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)))); 314 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey))));
331 NSNumber* product_id = CFToNSCast(CFCastStrict<CFNumberRef>( 315 NSNumber* product_id = CFToNSCast(CFCastStrict<CFNumberRef>(
332 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)))); 316 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey))));
333 NSString* product = CFToNSCast(CFCastStrict<CFStringRef>( 317 NSString* product = CFToNSCast(CFCastStrict<CFStringRef>(
334 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)))); 318 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey))));
335 int vendor_int = [vendor_id intValue]; 319 int vendor_int = [vendor_id intValue];
336 int product_int = [product_id intValue]; 320 int product_int = [product_id intValue];
337 321
338 char vendor_as_str[5], product_as_str[5]; 322 char vendor_as_str[5], product_as_str[5];
339 snprintf(vendor_as_str, sizeof(vendor_as_str), "%04x", vendor_int); 323 snprintf(vendor_as_str, sizeof(vendor_as_str), "%04x", vendor_int);
340 snprintf(product_as_str, sizeof(product_as_str), "%04x", product_int); 324 snprintf(product_as_str, sizeof(product_as_str), "%04x", product_int);
341 pad_state_[slot].mapper = 325 state->mapper =
342 GetGamepadStandardMappingFunction(vendor_as_str, product_as_str); 326 GetGamepadStandardMappingFunction(vendor_as_str, product_as_str);
343 327
344 NSString* ident = [NSString 328 NSString* ident =
345 stringWithFormat:@"%@ (%sVendor: %04x Product: %04x)", product, 329 [NSString stringWithFormat:@"%@ (%sVendor: %04x Product: %04x)", product,
346 pad_state_[slot].mapper ? "STANDARD GAMEPAD " : "", 330 state->mapper ? "STANDARD GAMEPAD " : "",
347 vendor_int, product_int]; 331 vendor_int, product_int];
348 CopyNSStringAsUTF16LittleEndian(ident, pad_state_[slot].data.id, 332 CopyNSStringAsUTF16LittleEndian(ident, state->data.id,
349 sizeof(pad_state_[slot].data.id)); 333 sizeof(state->data.id));
350 334
351 if (pad_state_[slot].mapper) { 335 if (state->mapper) {
352 CopyNSStringAsUTF16LittleEndian(@"standard", pad_state_[slot].data.mapping, 336 CopyNSStringAsUTF16LittleEndian(@"standard", state->data.mapping,
353 sizeof(pad_state_[slot].data.mapping)); 337 sizeof(state->data.mapping));
354 } else { 338 } else {
355 pad_state_[slot].data.mapping[0] = 0; 339 state->data.mapping[0] = 0;
356 } 340 }
357 341
358 base::ScopedCFTypeRef<CFArrayRef> elements( 342 base::ScopedCFTypeRef<CFArrayRef> elements(
359 IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone)); 343 IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone));
360 344
361 if (!AddButtonsAndAxes(CFToNSCast(elements), slot)) 345 if (!AddButtonsAndAxes(CFToNSCast(elements), state, slot))
362 return; 346 return;
363 347
364 associated_[slot].hid.device_ref = device; 348 associated_[slot].location_id = location_int;
365 pad_state_[slot].data.connected = true; 349 associated_[slot].device_ref = device;
366 pad_state_[slot].axis_mask = 0; 350 state->data.connected = true;
367 pad_state_[slot].button_mask = 0;
368 } 351 }
369 352
370 void GamepadPlatformDataFetcherMac::DeviceRemove(IOHIDDeviceRef device) { 353 void GamepadPlatformDataFetcherMac::DeviceRemove(IOHIDDeviceRef device) {
371 if (!enabled_) 354 if (!enabled_)
372 return; 355 return;
373 356
374 // Find the index for this device. 357 // Find the index for this device.
375 size_t slot; 358 size_t slot;
376 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { 359 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
377 if (pad_state_[slot].data.connected && !associated_[slot].is_xbox && 360 if (associated_[slot].device_ref == device)
378 associated_[slot].hid.device_ref == device)
379 break; 361 break;
380 } 362 }
381 DCHECK(slot < WebGamepads::itemsLengthCap); 363 DCHECK(slot < WebGamepads::itemsLengthCap);
382 // Leave associated device_ref so that it will be reconnected in the same 364 // Leave associated device_ref so that it will be reconnected in the same
383 // location. Simply mark it as disconnected. 365 // location. Simply mark it as disconnected.
384 pad_state_[slot].data.connected = false; 366 associated_[slot].location_id = 0;
367 associated_[slot].device_ref = nullptr;
385 } 368 }
386 369
387 void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) { 370 void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) {
388 if (!enabled_ || paused_) 371 if (!enabled_ || paused_)
389 return; 372 return;
390 373
391 IOHIDElementRef element = IOHIDValueGetElement(value); 374 IOHIDElementRef element = IOHIDValueGetElement(value);
392 IOHIDDeviceRef device = IOHIDElementGetDevice(element); 375 IOHIDDeviceRef device = IOHIDElementGetDevice(element);
393 376
394 // Find device slot. 377 // Find device slot.
395 size_t slot; 378 size_t slot;
396 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { 379 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
397 if (pad_state_[slot].data.connected && !associated_[slot].is_xbox && 380 if (associated_[slot].device_ref == device)
398 associated_[slot].hid.device_ref == device)
399 break; 381 break;
400 } 382 }
401 if (slot == WebGamepads::itemsLengthCap) 383 if (slot == WebGamepads::itemsLengthCap)
402 return; 384 return;
403 385
404 WebGamepad& pad = pad_state_[slot].data; 386 PadState* state = GetPadState(associated_[slot].location_id);
387 if (!state)
388 return;
389
390 WebGamepad& pad = state->data;
405 AssociatedData& associated = associated_[slot]; 391 AssociatedData& associated = associated_[slot];
406 392
407 uint32_t value_length = IOHIDValueGetLength(value); 393 uint32_t value_length = IOHIDValueGetLength(value);
408 if (value_length > 4) { 394 if (value_length > 4) {
409 // Workaround for bizarre issue with PS3 controllers that try to return 395 // Workaround for bizarre issue with PS3 controllers that try to return
410 // massive (30+ byte) values and crash IOHIDValueGetIntegerValue 396 // massive (30+ byte) values and crash IOHIDValueGetIntegerValue
411 return; 397 return;
412 } 398 }
413 399
414 // Find and fill in the associated button event, if any. 400 // Find and fill in the associated button event, if any.
415 for (size_t i = 0; i < pad.buttonsLength; ++i) { 401 for (size_t i = 0; i < pad.buttonsLength; ++i) {
416 if (associated.hid.button_elements[i] == element) { 402 if (associated.button_elements[i] == element) {
417 pad.buttons[i].pressed = IOHIDValueGetIntegerValue(value); 403 pad.buttons[i].pressed = IOHIDValueGetIntegerValue(value);
418 pad.buttons[i].value = pad.buttons[i].pressed ? 1.f : 0.f; 404 pad.buttons[i].value = pad.buttons[i].pressed ? 1.f : 0.f;
419 pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value)); 405 pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value));
420 return; 406 return;
421 } 407 }
422 } 408 }
423 409
424 // Find and fill in the associated axis event, if any. 410 // Find and fill in the associated axis event, if any.
425 for (size_t i = 0; i < pad.axesLength; ++i) { 411 for (size_t i = 0; i < pad.axesLength; ++i) {
426 if (associated.hid.axis_elements[i] == element) { 412 if (associated.axis_elements[i] == element) {
427 CFIndex axis_min = associated.hid.axis_minimums[i]; 413 CFIndex axis_min = associated.axis_minimums[i];
428 CFIndex axis_max = associated.hid.axis_maximums[i]; 414 CFIndex axis_max = associated.axis_maximums[i];
429 CFIndex axis_value = IOHIDValueGetIntegerValue(value); 415 CFIndex axis_value = IOHIDValueGetIntegerValue(value);
430 416
431 if (axis_min > axis_max) { 417 if (axis_min > axis_max) {
432 // We'll need to interpret this axis as unsigned during normalization. 418 // We'll need to interpret this axis as unsigned during normalization.
433 switch (associated.hid.axis_report_sizes[i]) { 419 switch (associated.axis_report_sizes[i]) {
434 case 8: 420 case 8:
435 pad.axes[i] = NormalizeUInt8Axis(axis_value, axis_min, axis_max); 421 pad.axes[i] = NormalizeUInt8Axis(axis_value, axis_min, axis_max);
436 break; 422 break;
437 case 16: 423 case 16:
438 pad.axes[i] = NormalizeUInt16Axis(axis_value, axis_min, axis_max); 424 pad.axes[i] = NormalizeUInt16Axis(axis_value, axis_min, axis_max);
439 break; 425 break;
440 case 32: 426 case 32:
441 pad.axes[i] = NormalizeUInt32Axis(axis_value, axis_min, axis_max); 427 pad.axes[i] = NormalizeUInt32Axis(axis_value, axis_min, axis_max);
442 break; 428 break;
443 } 429 }
444 } else { 430 } else {
445 pad.axes[i] = NormalizeAxis(axis_value, axis_min, axis_max); 431 pad.axes[i] = NormalizeAxis(axis_value, axis_min, axis_max);
446 } 432 }
447 433
448 pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value)); 434 pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value));
449 return; 435 return;
450 } 436 }
451 } 437 }
452 } 438 }
453 439
454 void GamepadPlatformDataFetcherMac::XboxDeviceAdd(XboxController* device) { 440 void GamepadPlatformDataFetcherMac::GetGamepadData(bool) {
455 if (!enabled_) 441 if (!enabled_)
456 return; 442 return;
457 443
458 size_t slot = GetSlotForXboxDevice(device); 444 // Loop through and GetPadState to indicate the devices are still connected.
459 445 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
460 // We can't handle this many connected devices. 446 if (associated_[slot].device_ref != nullptr) {
461 if (slot == WebGamepads::itemsLengthCap) 447 GetPadState(associated_[slot].location_id);
462 return; 448 }
463
464 device->SetLEDPattern(
465 (XboxController::LEDPattern)(XboxController::LED_FLASH_TOP_LEFT + slot));
466
467 NSString* ident = [NSString
468 stringWithFormat:@"%@ (STANDARD GAMEPAD Vendor: %04x Product: %04x)",
469 device->GetControllerType() ==
470 XboxController::XBOX_360_CONTROLLER
471 ? @"Xbox 360 Controller"
472 : @"Xbox One Controller",
473 device->GetProductId(), device->GetVendorId()];
474 CopyNSStringAsUTF16LittleEndian(ident, pad_state_[slot].data.id,
475 sizeof(pad_state_[slot].data.id));
476
477 CopyNSStringAsUTF16LittleEndian(@"standard", pad_state_[slot].data.mapping,
478 sizeof(pad_state_[slot].data.mapping));
479
480 associated_[slot].is_xbox = true;
481 associated_[slot].xbox.device = device;
482 associated_[slot].xbox.location_id = device->location_id();
483 pad_state_[slot].data.connected = true;
484 pad_state_[slot].data.axesLength = 4;
485 pad_state_[slot].data.buttonsLength = 17;
486 pad_state_[slot].data.timestamp = 0;
487 pad_state_[slot].mapper = 0;
488 pad_state_[slot].axis_mask = 0;
489 pad_state_[slot].button_mask = 0;
490 }
491
492 void GamepadPlatformDataFetcherMac::XboxDeviceRemove(XboxController* device) {
493 if (!enabled_)
494 return;
495
496 // Find the index for this device.
497 size_t slot;
498 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
499 if (pad_state_[slot].data.connected && associated_[slot].is_xbox &&
500 associated_[slot].xbox.device == device)
501 break;
502 } 449 }
503 DCHECK(slot < WebGamepads::itemsLengthCap);
504 // Leave associated location id so that the controller will be reconnected in
505 // the same slot if it is plugged in again. Simply mark it as disconnected.
506 pad_state_[slot].data.connected = false;
507 }
508
509 void GamepadPlatformDataFetcherMac::XboxValueChanged(
510 XboxController* device,
511 const XboxController::Data& data) {
512 // Find device slot.
513 size_t slot;
514 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
515 if (pad_state_[slot].data.connected && associated_[slot].is_xbox &&
516 associated_[slot].xbox.device == device)
517 break;
518 }
519 if (slot == WebGamepads::itemsLengthCap)
520 return;
521
522 WebGamepad& pad = pad_state_[slot].data;
523
524 for (size_t i = 0; i < 6; i++) {
525 pad.buttons[i].pressed = data.buttons[i];
526 pad.buttons[i].value = data.buttons[i] ? 1.0f : 0.0f;
527 }
528 pad.buttons[6].pressed = data.triggers[0] > kDefaultButtonPressedThreshold;
529 pad.buttons[6].value = data.triggers[0];
530 pad.buttons[7].pressed = data.triggers[1] > kDefaultButtonPressedThreshold;
531 pad.buttons[7].value = data.triggers[1];
532 for (size_t i = 8; i < 17; i++) {
533 pad.buttons[i].pressed = data.buttons[i - 2];
534 pad.buttons[i].value = data.buttons[i - 2] ? 1.0f : 0.0f;
535 }
536 for (size_t i = 0; i < arraysize(data.axes); i++) {
537 pad.axes[i] = data.axes[i];
538 }
539
540 pad.timestamp = base::TimeTicks::Now().ToInternalValue();
541 }
542
543 void GamepadPlatformDataFetcherMac::GetGamepadData(WebGamepads* pads, bool) {
544 if (!enabled_ && !xbox_fetcher_) {
545 pads->length = 0;
546 return;
547 }
548
549 pads->length = WebGamepads::itemsLengthCap;
550 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i)
551 MapAndSanitizeGamepadData(&pad_state_[i], &pads->items[i]);
552 } 450 }
553 451
554 } // namespace device 452 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698