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

Side by Side Diff: content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm

Issue 1586663006: Refactoring gamepad polling to support dynamically added sources (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Avoid crash on Android content_unittests Created 4 years, 11 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 "content/browser/gamepad/gamepad_platform_data_fetcher_mac.h" 5 #include "content/browser/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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 const uint32_t kGameControlsUsagePage = 0x05; 50 const uint32_t kGameControlsUsagePage = 0x05;
51 const uint32_t kButtonUsagePage = 0x09; 51 const uint32_t kButtonUsagePage = 0x09;
52 const uint32_t kJoystickUsageNumber = 0x04; 52 const uint32_t kJoystickUsageNumber = 0x04;
53 const uint32_t kGameUsageNumber = 0x05; 53 const uint32_t kGameUsageNumber = 0x05;
54 const uint32_t kMultiAxisUsageNumber = 0x08; 54 const uint32_t kMultiAxisUsageNumber = 0x08;
55 const uint32_t kAxisMinimumUsageNumber = 0x30; 55 const uint32_t kAxisMinimumUsageNumber = 0x30;
56 56
57 } // namespace 57 } // namespace
58 58
59 GamepadPlatformDataFetcherMac::GamepadPlatformDataFetcherMac() 59 GamepadPlatformDataFetcherMac::GamepadPlatformDataFetcherMac()
60 : enabled_(true), paused_(false) { 60 : enabled_(true),
61 paused_(false) {
61 memset(associated_, 0, sizeof(associated_)); 62 memset(associated_, 0, sizeof(associated_));
63 }
62 64
63 xbox_fetcher_.reset(new XboxDataFetcher(this)); 65 void GamepadPlatformDataFetcherMac::OnAddedToProvider() {
64 if (!xbox_fetcher_->RegisterForNotifications())
65 xbox_fetcher_.reset();
66
67 hid_manager_ref_.reset(IOHIDManagerCreate(kCFAllocatorDefault, 66 hid_manager_ref_.reset(IOHIDManagerCreate(kCFAllocatorDefault,
68 kIOHIDOptionsTypeNone)); 67 kIOHIDOptionsTypeNone));
69 if (CFGetTypeID(hid_manager_ref_) != IOHIDManagerGetTypeID()) { 68 if (CFGetTypeID(hid_manager_ref_) != IOHIDManagerGetTypeID()) {
70 enabled_ = false; 69 enabled_ = false;
71 return; 70 return;
72 } 71 }
73 72
74 base::scoped_nsobject<NSArray> criteria([[NSArray alloc] initWithObjects: 73 base::scoped_nsobject<NSArray> criteria([[NSArray alloc] initWithObjects:
75 DeviceMatching(kGenericDesktopUsagePage, kJoystickUsageNumber), 74 DeviceMatching(kGenericDesktopUsagePage, kJoystickUsageNumber),
76 DeviceMatching(kGenericDesktopUsagePage, kGameUsageNumber), 75 DeviceMatching(kGenericDesktopUsagePage, kGameUsageNumber),
(...skipping 23 matching lines...) Expand all
100 ValueChangedCallback, 99 ValueChangedCallback,
101 this); 100 this);
102 101
103 IOHIDManagerScheduleWithRunLoop( 102 IOHIDManagerScheduleWithRunLoop(
104 hid_manager_ref_, 103 hid_manager_ref_,
105 CFRunLoopGetMain(), 104 CFRunLoopGetMain(),
106 kCFRunLoopDefaultMode); 105 kCFRunLoopDefaultMode);
107 106
108 enabled_ = IOHIDManagerOpen(hid_manager_ref_, 107 enabled_ = IOHIDManagerOpen(hid_manager_ref_,
109 kIOHIDOptionsTypeNone) == kIOReturnSuccess; 108 kIOHIDOptionsTypeNone) == kIOReturnSuccess;
110
111 if (xbox_fetcher_)
112 xbox_fetcher_->RegisterForNotifications();
113 } 109 }
114 110
115 void GamepadPlatformDataFetcherMac::UnregisterFromNotifications() { 111 void GamepadPlatformDataFetcherMac::UnregisterFromNotifications() {
116 IOHIDManagerUnscheduleFromRunLoop( 112 IOHIDManagerUnscheduleFromRunLoop(
117 hid_manager_ref_, 113 hid_manager_ref_,
118 CFRunLoopGetCurrent(), 114 CFRunLoopGetCurrent(),
119 kCFRunLoopDefaultMode); 115 kCFRunLoopDefaultMode);
120 IOHIDManagerClose(hid_manager_ref_, kIOHIDOptionsTypeNone); 116 IOHIDManagerClose(hid_manager_ref_, kIOHIDOptionsTypeNone);
121 if (xbox_fetcher_)
122 xbox_fetcher_->UnregisterFromNotifications();
123 } 117 }
124 118
125 void GamepadPlatformDataFetcherMac::PauseHint(bool pause) { 119 void GamepadPlatformDataFetcherMac::PauseHint(bool pause) {
126 paused_ = pause; 120 paused_ = pause;
127 } 121 }
128 122
129 GamepadPlatformDataFetcherMac::~GamepadPlatformDataFetcherMac() { 123 GamepadPlatformDataFetcherMac::~GamepadPlatformDataFetcherMac() {
130 UnregisterFromNotifications(); 124 UnregisterFromNotifications();
131 } 125 }
132 126
(...skipping 17 matching lines...) Expand all
150 } 144 }
151 145
152 void GamepadPlatformDataFetcherMac::ValueChangedCallback(void* context, 146 void GamepadPlatformDataFetcherMac::ValueChangedCallback(void* context,
153 IOReturn result, 147 IOReturn result,
154 void* sender, 148 void* sender,
155 IOHIDValueRef ref) { 149 IOHIDValueRef ref) {
156 InstanceFromContext(context)->ValueChanged(ref); 150 InstanceFromContext(context)->ValueChanged(ref);
157 } 151 }
158 152
159 bool GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements, 153 bool GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements,
154 PadState* state,
160 size_t slot) { 155 size_t slot) {
161 WebGamepad& pad = pad_state_[slot].data; 156 WebGamepad& pad = state->data;
162 AssociatedData& associated = associated_[slot]; 157 AssociatedData& associated = associated_[slot];
163 CHECK(!associated.is_xbox);
164 158
165 pad.axesLength = 0; 159 pad.axesLength = 0;
166 pad.buttonsLength = 0; 160 pad.buttonsLength = 0;
167 pad.timestamp = 0; 161 pad.timestamp = 0;
168 memset(pad.axes, 0, sizeof(pad.axes)); 162 memset(pad.axes, 0, sizeof(pad.axes));
169 memset(pad.buttons, 0, sizeof(pad.buttons)); 163 memset(pad.buttons, 0, sizeof(pad.buttons));
170 164
171 bool mapped_all_axes = true; 165 bool mapped_all_axes = true;
172 166
173 for (id elem in elements) { 167 for (id elem in elements) {
174 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem); 168 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem);
175 uint32_t usage_page = IOHIDElementGetUsagePage(element); 169 uint32_t usage_page = IOHIDElementGetUsagePage(element);
176 uint32_t usage = IOHIDElementGetUsage(element); 170 uint32_t usage = IOHIDElementGetUsage(element);
177 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Button && 171 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Button &&
178 usage_page == kButtonUsagePage) { 172 usage_page == kButtonUsagePage) {
179 uint32_t button_index = usage - 1; 173 uint32_t button_index = usage - 1;
180 if (button_index < WebGamepad::buttonsLengthCap) { 174 if (button_index < WebGamepad::buttonsLengthCap) {
181 associated.hid.button_elements[button_index] = element; 175 associated.button_elements[button_index] = element;
182 pad.buttonsLength = std::max(pad.buttonsLength, button_index + 1); 176 pad.buttonsLength = std::max(pad.buttonsLength, button_index + 1);
183 } 177 }
184 } 178 }
185 else if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc) { 179 else if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc) {
186 uint32_t axis_index = usage - kAxisMinimumUsageNumber; 180 uint32_t axis_index = usage - kAxisMinimumUsageNumber;
187 if (axis_index < WebGamepad::axesLengthCap) { 181 if (axis_index < WebGamepad::axesLengthCap) {
188 associated.hid.axis_minimums[axis_index] = 182 associated.axis_minimums[axis_index] =
189 IOHIDElementGetLogicalMin(element); 183 IOHIDElementGetLogicalMin(element);
190 associated.hid.axis_maximums[axis_index] = 184 associated.axis_maximums[axis_index] =
191 IOHIDElementGetLogicalMax(element); 185 IOHIDElementGetLogicalMax(element);
192 associated.hid.axis_elements[axis_index] = element; 186 associated.axis_elements[axis_index] = element;
193 pad.axesLength = std::max(pad.axesLength, axis_index + 1); 187 pad.axesLength = std::max(pad.axesLength, axis_index + 1);
194 } else { 188 } else {
195 mapped_all_axes = false; 189 mapped_all_axes = false;
196 } 190 }
197 } 191 }
198 } 192 }
199 193
200 if (!mapped_all_axes) { 194 if (!mapped_all_axes) {
201 // For axes who's usage puts them outside the standard axesLengthCap range. 195 // For axes who's usage puts them outside the standard axesLengthCap range.
202 uint32_t next_index = 0; 196 uint32_t next_index = 0;
203 for (id elem in elements) { 197 for (id elem in elements) {
204 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem); 198 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem);
205 uint32_t usage_page = IOHIDElementGetUsagePage(element); 199 uint32_t usage_page = IOHIDElementGetUsagePage(element);
206 uint32_t usage = IOHIDElementGetUsage(element); 200 uint32_t usage = IOHIDElementGetUsage(element);
207 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc && 201 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc &&
208 usage - kAxisMinimumUsageNumber >= WebGamepad::axesLengthCap && 202 usage - kAxisMinimumUsageNumber >= WebGamepad::axesLengthCap &&
209 usage_page <= kGameControlsUsagePage) { 203 usage_page <= kGameControlsUsagePage) {
210 for (; next_index < WebGamepad::axesLengthCap; ++next_index) { 204 for (; next_index < WebGamepad::axesLengthCap; ++next_index) {
211 if (associated.hid.axis_elements[next_index] == NULL) 205 if (associated.axis_elements[next_index] == NULL)
212 break; 206 break;
213 } 207 }
214 if (next_index < WebGamepad::axesLengthCap) { 208 if (next_index < WebGamepad::axesLengthCap) {
215 associated.hid.axis_minimums[next_index] = 209 associated.axis_minimums[next_index] =
216 IOHIDElementGetLogicalMin(element); 210 IOHIDElementGetLogicalMin(element);
217 associated.hid.axis_maximums[next_index] = 211 associated.axis_maximums[next_index] =
218 IOHIDElementGetLogicalMax(element); 212 IOHIDElementGetLogicalMax(element);
219 associated.hid.axis_elements[next_index] = element; 213 associated.axis_elements[next_index] = element;
220 pad.axesLength = std::max(pad.axesLength, next_index + 1); 214 pad.axesLength = std::max(pad.axesLength, next_index + 1);
221 } 215 }
222 } 216 }
223 217
224 if (next_index >= WebGamepad::axesLengthCap) 218 if (next_index >= WebGamepad::axesLengthCap)
225 break; 219 break;
226 } 220 }
227 } 221 }
228 222
229 return (pad.axesLength > 0 || pad.buttonsLength > 0); 223 return (pad.axesLength > 0 || pad.buttonsLength > 0);
230 } 224 }
231 225
232 size_t GamepadPlatformDataFetcherMac::GetEmptySlot() { 226 size_t GamepadPlatformDataFetcherMac::GetEmptySlot() {
233 // Find a free slot for this device. 227 // Find a free slot for this device.
234 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { 228 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
235 if (!pad_state_[slot].data.connected) 229 if (associated_[slot].device_ref == nullptr)
236 return slot; 230 return slot;
237 } 231 }
238 return WebGamepads::itemsLengthCap; 232 return WebGamepads::itemsLengthCap;
239 } 233 }
240 234
241 size_t GamepadPlatformDataFetcherMac::GetSlotForDevice(IOHIDDeviceRef device) { 235 size_t GamepadPlatformDataFetcherMac::GetSlotForDevice(IOHIDDeviceRef device) {
242 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { 236 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
243 // If we already have this device, and it's already connected, don't do 237 // If we already have this device, and it's already connected, don't do
244 // anything now. 238 // anything now.
245 if (pad_state_[slot].data.connected && 239 if (associated_[slot].device_ref == device)
246 !associated_[slot].is_xbox &&
247 associated_[slot].hid.device_ref == device)
248 return WebGamepads::itemsLengthCap; 240 return WebGamepads::itemsLengthCap;
249 } 241 }
250 return GetEmptySlot(); 242 return GetEmptySlot();
251 } 243 }
252 244
253 size_t GamepadPlatformDataFetcherMac::GetSlotForXboxDevice(
254 XboxController* device) {
255 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
256 if (associated_[slot].is_xbox &&
257 associated_[slot].xbox.location_id == device->location_id()) {
258 if (pad_state_[slot].data.connected) {
259 // The device is already connected. No idea why we got a second "device
260 // added" call, but let's not add it twice.
261 DCHECK_EQ(associated_[slot].xbox.device, device);
262 return WebGamepads::itemsLengthCap;
263 } else {
264 // A device with the same location ID was previously connected, so put
265 // it in the same slot.
266 return slot;
267 }
268 }
269 }
270 return GetEmptySlot();
271 }
272
273 void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) { 245 void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
274 using base::mac::CFToNSCast; 246 using base::mac::CFToNSCast;
275 using base::mac::CFCastStrict; 247 using base::mac::CFCastStrict;
276 248
277 if (!enabled_) 249 if (!enabled_)
278 return; 250 return;
279 251
252 NSNumber* location_id = CFToNSCast(CFCastStrict<CFNumberRef>(
253 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey))));
254 int location_int = [location_id intValue];
255
280 // Find an index for this device. 256 // Find an index for this device.
281 size_t slot = GetSlotForDevice(device); 257 size_t slot = GetSlotForDevice(device);
282
283 // We can't handle this many connected devices. 258 // We can't handle this many connected devices.
284 if (slot == WebGamepads::itemsLengthCap) 259 if (slot == WebGamepads::itemsLengthCap)
285 return; 260 return;
286 261
287 // Clear some state that may have been left behind by previous gamepads 262 // Clear some state that may have been left behind by previous gamepads
288 memset(&associated_[slot], 0, sizeof(AssociatedData)); 263 memset(&associated_[slot], 0, sizeof(AssociatedData));
289 264
265 PadState* state = provider()->GetPadState(GAMEPAD_SOURCE_MAC_HID,
266 location_int);
267 if (!state)
268 return; // No available slot for this device
269
290 NSNumber* vendor_id = CFToNSCast(CFCastStrict<CFNumberRef>( 270 NSNumber* vendor_id = CFToNSCast(CFCastStrict<CFNumberRef>(
291 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)))); 271 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey))));
292 NSNumber* product_id = CFToNSCast(CFCastStrict<CFNumberRef>( 272 NSNumber* product_id = CFToNSCast(CFCastStrict<CFNumberRef>(
293 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)))); 273 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey))));
274
294 NSString* product = CFToNSCast(CFCastStrict<CFStringRef>( 275 NSString* product = CFToNSCast(CFCastStrict<CFStringRef>(
295 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)))); 276 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey))));
296 int vendor_int = [vendor_id intValue]; 277 int vendor_int = [vendor_id intValue];
297 int product_int = [product_id intValue]; 278 int product_int = [product_id intValue];
298 279
299 char vendor_as_str[5], product_as_str[5]; 280 char vendor_as_str[5], product_as_str[5];
300 snprintf(vendor_as_str, sizeof(vendor_as_str), "%04x", vendor_int); 281 snprintf(vendor_as_str, sizeof(vendor_as_str), "%04x", vendor_int);
301 snprintf(product_as_str, sizeof(product_as_str), "%04x", product_int); 282 snprintf(product_as_str, sizeof(product_as_str), "%04x", product_int);
302 pad_state_[slot].mapper = 283 state->mapper =
303 GetGamepadStandardMappingFunction(vendor_as_str, product_as_str); 284 GetGamepadStandardMappingFunction(vendor_as_str, product_as_str);
304 285
305 NSString* ident = [NSString stringWithFormat: 286 NSString* ident = [NSString stringWithFormat:
306 @"%@ (%sVendor: %04x Product: %04x)", 287 @"%@ (%sVendor: %04x Product: %04x)",
307 product, 288 product,
308 pad_state_[slot].mapper ? "STANDARD GAMEPAD " : "", 289 state->mapper ? "STANDARD GAMEPAD " : "",
309 vendor_int, 290 vendor_int,
310 product_int]; 291 product_int];
311 CopyNSStringAsUTF16LittleEndian( 292 CopyNSStringAsUTF16LittleEndian(
312 ident, 293 ident,
313 pad_state_[slot].data.id, 294 state->data.id,
314 sizeof(pad_state_[slot].data.id)); 295 sizeof(state->data.id));
315 296
316 if (pad_state_[slot].mapper) { 297 if (state->mapper) {
317 CopyNSStringAsUTF16LittleEndian( 298 CopyNSStringAsUTF16LittleEndian(
318 @"standard", 299 @"standard",
319 pad_state_[slot].data.mapping, 300 state->data.mapping,
320 sizeof(pad_state_[slot].data.mapping)); 301 sizeof(state->data.mapping));
321 } else { 302 } else {
322 pad_state_[slot].data.mapping[0] = 0; 303 state->data.mapping[0] = 0;
323 } 304 }
324 305
325 base::ScopedCFTypeRef<CFArrayRef> elements( 306 base::ScopedCFTypeRef<CFArrayRef> elements(
326 IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone)); 307 IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone));
327 308
328 if (!AddButtonsAndAxes(CFToNSCast(elements), slot)) 309 if (!AddButtonsAndAxes(CFToNSCast(elements), state, slot))
329 return; 310 return;
330 311
331 associated_[slot].hid.device_ref = device; 312 associated_[slot].location_id = location_int;
332 pad_state_[slot].data.connected = true; 313 associated_[slot].device_ref = device;
333 pad_state_[slot].axis_mask = 0; 314 state->data.connected = true;
334 pad_state_[slot].button_mask = 0;
335 } 315 }
336 316
337 void GamepadPlatformDataFetcherMac::DeviceRemove(IOHIDDeviceRef device) { 317 void GamepadPlatformDataFetcherMac::DeviceRemove(IOHIDDeviceRef device) {
338 if (!enabled_) 318 if (!enabled_)
339 return; 319 return;
340 320
341 // Find the index for this device. 321 // Find the index for this device.
342 size_t slot; 322 size_t slot;
343 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { 323 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
344 if (pad_state_[slot].data.connected && 324 if (associated_[slot].device_ref == device)
345 !associated_[slot].is_xbox &&
346 associated_[slot].hid.device_ref == device)
347 break; 325 break;
348 } 326 }
349 DCHECK(slot < WebGamepads::itemsLengthCap); 327 DCHECK(slot < WebGamepads::itemsLengthCap);
350 // Leave associated device_ref so that it will be reconnected in the same 328 // Leave associated device_ref so that it will be reconnected in the same
351 // location. Simply mark it as disconnected. 329 // location. Simply mark it as disconnected.
352 pad_state_[slot].data.connected = false; 330 associated_[slot].location_id = 0;
331 associated_[slot].device_ref = nullptr;
353 } 332 }
354 333
355 void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) { 334 void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) {
356 if (!enabled_ || paused_) 335 if (!enabled_ || paused_)
357 return; 336 return;
358 337
359 IOHIDElementRef element = IOHIDValueGetElement(value); 338 IOHIDElementRef element = IOHIDValueGetElement(value);
360 IOHIDDeviceRef device = IOHIDElementGetDevice(element); 339 IOHIDDeviceRef device = IOHIDElementGetDevice(element);
361 340
362 // Find device slot. 341 // Find device slot.
363 size_t slot; 342 size_t slot;
364 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { 343 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
365 if (pad_state_[slot].data.connected && 344 if (associated_[slot].device_ref == device)
366 !associated_[slot].is_xbox &&
367 associated_[slot].hid.device_ref == device)
368 break; 345 break;
369 } 346 }
370 if (slot == WebGamepads::itemsLengthCap) 347 if (slot == WebGamepads::itemsLengthCap)
371 return; 348 return;
372 349
373 WebGamepad& pad = pad_state_[slot].data; 350 PadState* state = provider()->GetPadState(GAMEPAD_SOURCE_MAC_HID,
351 associated_[slot].location_id);
352 if (!state)
353 return;
354
355 WebGamepad& pad = state->data;
374 AssociatedData& associated = associated_[slot]; 356 AssociatedData& associated = associated_[slot];
375 357
376 uint32_t value_length = IOHIDValueGetLength(value); 358 uint32_t value_length = IOHIDValueGetLength(value);
377 if (value_length > 4) { 359 if (value_length > 4) {
378 // Workaround for bizarre issue with PS3 controllers that try to return 360 // Workaround for bizarre issue with PS3 controllers that try to return
379 // massive (30+ byte) values and crash IOHIDValueGetIntegerValue 361 // massive (30+ byte) values and crash IOHIDValueGetIntegerValue
380 return; 362 return;
381 } 363 }
382 364
383 // Find and fill in the associated button event, if any. 365 // Find and fill in the associated button event, if any.
384 for (size_t i = 0; i < pad.buttonsLength; ++i) { 366 for (size_t i = 0; i < pad.buttonsLength; ++i) {
385 if (associated.hid.button_elements[i] == element) { 367 if (associated.button_elements[i] == element) {
386 pad.buttons[i].pressed = IOHIDValueGetIntegerValue(value); 368 pad.buttons[i].pressed = IOHIDValueGetIntegerValue(value);
387 pad.buttons[i].value = pad.buttons[i].pressed ? 1.f : 0.f; 369 pad.buttons[i].value = pad.buttons[i].pressed ? 1.f : 0.f;
388 pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value)); 370 pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value));
389 return; 371 return;
390 } 372 }
391 } 373 }
392 374
393 // Find and fill in the associated axis event, if any. 375 // Find and fill in the associated axis event, if any.
394 for (size_t i = 0; i < pad.axesLength; ++i) { 376 for (size_t i = 0; i < pad.axesLength; ++i) {
395 if (associated.hid.axis_elements[i] == element) { 377 if (associated.axis_elements[i] == element) {
396 pad.axes[i] = NormalizeAxis(IOHIDValueGetIntegerValue(value), 378 pad.axes[i] = NormalizeAxis(IOHIDValueGetIntegerValue(value),
397 associated.hid.axis_minimums[i], 379 associated.axis_minimums[i],
398 associated.hid.axis_maximums[i]); 380 associated.axis_maximums[i]);
399 pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value)); 381 pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value));
400 return; 382 return;
401 } 383 }
402 } 384 }
403 } 385 }
404 386
405 void GamepadPlatformDataFetcherMac::XboxDeviceAdd(XboxController* device) { 387 void GamepadPlatformDataFetcherMac::GetGamepadData(bool) {
406 if (!enabled_) 388 if (!enabled_)
407 return; 389 return;
408 390
409 size_t slot = GetSlotForXboxDevice(device); 391 // Loop through and GetPadState to indicate the devices are still connected.
410 392 for (size_t slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
411 // We can't handle this many connected devices. 393 if (associated_[slot].device_ref != nullptr) {
412 if (slot == WebGamepads::itemsLengthCap) 394 provider()->GetPadState(GAMEPAD_SOURCE_MAC_HID,
413 return; 395 associated_[slot].location_id);
414 396 }
415 device->SetLEDPattern(
416 (XboxController::LEDPattern)(XboxController::LED_FLASH_TOP_LEFT + slot));
417
418 NSString* ident =
419 [NSString stringWithFormat:
420 @"%@ (STANDARD GAMEPAD Vendor: %04x Product: %04x)",
421 device->GetControllerType() == XboxController::XBOX_360_CONTROLLER
422 ? @"Xbox 360 Controller"
423 : @"Xbox One Controller",
424 device->GetProductId(), device->GetVendorId()];
425 CopyNSStringAsUTF16LittleEndian(
426 ident,
427 pad_state_[slot].data.id,
428 sizeof(pad_state_[slot].data.id));
429
430 CopyNSStringAsUTF16LittleEndian(
431 @"standard",
432 pad_state_[slot].data.mapping,
433 sizeof(pad_state_[slot].data.mapping));
434
435 associated_[slot].is_xbox = true;
436 associated_[slot].xbox.device = device;
437 associated_[slot].xbox.location_id = device->location_id();
438 pad_state_[slot].data.connected = true;
439 pad_state_[slot].data.axesLength = 4;
440 pad_state_[slot].data.buttonsLength = 17;
441 pad_state_[slot].data.timestamp = 0;
442 pad_state_[slot].mapper = 0;
443 pad_state_[slot].axis_mask = 0;
444 pad_state_[slot].button_mask = 0;
445 }
446
447 void GamepadPlatformDataFetcherMac::XboxDeviceRemove(XboxController* device) {
448 if (!enabled_)
449 return;
450
451 // Find the index for this device.
452 size_t slot;
453 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
454 if (pad_state_[slot].data.connected &&
455 associated_[slot].is_xbox &&
456 associated_[slot].xbox.device == device)
457 break;
458 } 397 }
459 DCHECK(slot < WebGamepads::itemsLengthCap);
460 // Leave associated location id so that the controller will be reconnected in
461 // the same slot if it is plugged in again. Simply mark it as disconnected.
462 pad_state_[slot].data.connected = false;
463 }
464
465 void GamepadPlatformDataFetcherMac::XboxValueChanged(
466 XboxController* device, const XboxController::Data& data) {
467 // Find device slot.
468 size_t slot;
469 for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) {
470 if (pad_state_[slot].data.connected &&
471 associated_[slot].is_xbox &&
472 associated_[slot].xbox.device == device)
473 break;
474 }
475 if (slot == WebGamepads::itemsLengthCap)
476 return;
477
478 WebGamepad& pad = pad_state_[slot].data;
479
480 for (size_t i = 0; i < 6; i++) {
481 pad.buttons[i].pressed = data.buttons[i];
482 pad.buttons[i].value = data.buttons[i] ? 1.0f : 0.0f;
483 }
484 pad.buttons[6].pressed = data.triggers[0] > kDefaultButtonPressedThreshold;
485 pad.buttons[6].value = data.triggers[0];
486 pad.buttons[7].pressed = data.triggers[1] > kDefaultButtonPressedThreshold;
487 pad.buttons[7].value = data.triggers[1];
488 for (size_t i = 8; i < 17; i++) {
489 pad.buttons[i].pressed = data.buttons[i - 2];
490 pad.buttons[i].value = data.buttons[i - 2] ? 1.0f : 0.0f;
491 }
492 for (size_t i = 0; i < arraysize(data.axes); i++) {
493 pad.axes[i] = data.axes[i];
494 }
495
496 pad.timestamp = base::TimeTicks::Now().ToInternalValue();
497 }
498
499 void GamepadPlatformDataFetcherMac::GetGamepadData(WebGamepads* pads, bool) {
500 if (!enabled_ && !xbox_fetcher_) {
501 pads->length = 0;
502 return;
503 }
504
505 pads->length = WebGamepads::itemsLengthCap;
506 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i)
507 MapAndSanitizeGamepadData(&pad_state_[i], &pads->items[i]);
508 } 398 }
509 399
510 } // namespace content 400 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698