OLD | NEW |
---|---|
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" |
11 #include "base/mac/scoped_nsobject.h" | 11 #include "base/mac/scoped_nsobject.h" |
12 #include "base/macros.h" | 12 #include "base/macros.h" |
13 #include "base/strings/string16.h" | 13 #include "base/strings/string16.h" |
14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
16 #include "base/time/time.h" | 16 #include "base/time/time.h" |
17 | 17 |
18 #import <Foundation/Foundation.h> | 18 #import <Foundation/Foundation.h> |
19 #include <IOKit/hid/IOHIDKeys.h> | 19 #include <IOKit/hid/IOHIDKeys.h> |
20 | 20 |
21 using blink::WebGamepad; | |
22 using blink::WebGamepads; | |
23 | |
24 namespace device { | 21 namespace device { |
25 | 22 |
26 namespace { | 23 namespace { |
27 | 24 |
28 void CopyNSStringAsUTF16LittleEndian(NSString* src, | 25 void CopyNSStringAsUTF16LittleEndian(NSString* src, |
29 blink::WebUChar* dest, | 26 UChar* dest, |
dcheng
2017/04/12 23:33:27
Nit: do we need to include a header for this type?
juncai
2017/04/13 23:55:52
It is from:
//device/gamepad/public/cpp/gamepad.h
| |
30 size_t dest_len) { | 27 size_t dest_len) { |
31 NSData* as16 = [src dataUsingEncoding:NSUTF16LittleEndianStringEncoding]; | 28 NSData* as16 = [src dataUsingEncoding:NSUTF16LittleEndianStringEncoding]; |
32 memset(dest, 0, dest_len); | 29 memset(dest, 0, dest_len); |
33 [as16 getBytes:dest length:dest_len - sizeof(blink::WebUChar)]; | 30 [as16 getBytes:dest length:dest_len - sizeof(UChar)]; |
34 } | 31 } |
35 | 32 |
36 NSDictionary* DeviceMatching(uint32_t usage_page, uint32_t usage) { | 33 NSDictionary* DeviceMatching(uint32_t usage_page, uint32_t usage) { |
37 return [NSDictionary | 34 return [NSDictionary |
38 dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:usage_page], | 35 dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:usage_page], |
39 base::mac::CFToNSCast( | 36 base::mac::CFToNSCast( |
40 CFSTR(kIOHIDDeviceUsagePageKey)), | 37 CFSTR(kIOHIDDeviceUsagePageKey)), |
41 [NSNumber numberWithUnsignedInt:usage], | 38 [NSNumber numberWithUnsignedInt:usage], |
42 base::mac::CFToNSCast( | 39 base::mac::CFToNSCast( |
43 CFSTR(kIOHIDDeviceUsageKey)), | 40 CFSTR(kIOHIDDeviceUsageKey)), |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
172 return true; | 169 return true; |
173 } | 170 } |
174 } | 171 } |
175 } | 172 } |
176 return false; | 173 return false; |
177 } | 174 } |
178 | 175 |
179 bool GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements, | 176 bool GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements, |
180 PadState* state, | 177 PadState* state, |
181 size_t slot) { | 178 size_t slot) { |
182 WebGamepad& pad = state->data; | 179 Gamepad& pad = state->data; |
183 AssociatedData& associated = associated_[slot]; | 180 AssociatedData& associated = associated_[slot]; |
184 | 181 |
185 pad.axes_length = 0; | 182 pad.axes_length = 0; |
186 pad.buttons_length = 0; | 183 pad.buttons_length = 0; |
187 pad.timestamp = 0; | 184 pad.timestamp = 0; |
188 memset(pad.axes, 0, sizeof(pad.axes)); | 185 memset(pad.axes, 0, sizeof(pad.axes)); |
189 memset(pad.buttons, 0, sizeof(pad.buttons)); | 186 memset(pad.buttons, 0, sizeof(pad.buttons)); |
190 | 187 |
191 bool mapped_all_axes = true; | 188 bool mapped_all_axes = true; |
192 | 189 |
193 for (id elem in elements) { | 190 for (id elem in elements) { |
194 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem); | 191 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem); |
195 if (!CheckCollection(element)) | 192 if (!CheckCollection(element)) |
196 continue; | 193 continue; |
197 | 194 |
198 uint32_t usage_page = IOHIDElementGetUsagePage(element); | 195 uint32_t usage_page = IOHIDElementGetUsagePage(element); |
199 uint32_t usage = IOHIDElementGetUsage(element); | 196 uint32_t usage = IOHIDElementGetUsage(element); |
200 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Button && | 197 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Button && |
201 usage_page == kButtonUsagePage) { | 198 usage_page == kButtonUsagePage) { |
202 uint32_t button_index = usage - 1; | 199 uint32_t button_index = usage - 1; |
203 if (button_index < WebGamepad::kButtonsLengthCap) { | 200 if (button_index < Gamepad::kButtonsLengthCap) { |
204 associated.button_elements[button_index] = element; | 201 associated.button_elements[button_index] = element; |
205 pad.buttons_length = std::max(pad.buttons_length, button_index + 1); | 202 pad.buttons_length = std::max(pad.buttons_length, button_index + 1); |
206 } | 203 } |
207 } else if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc) { | 204 } else if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc) { |
208 uint32_t axis_index = usage - kAxisMinimumUsageNumber; | 205 uint32_t axis_index = usage - kAxisMinimumUsageNumber; |
209 if (axis_index < WebGamepad::kAxesLengthCap) { | 206 if (axis_index < Gamepad::kAxesLengthCap) { |
210 associated.axis_elements[axis_index] = element; | 207 associated.axis_elements[axis_index] = element; |
211 pad.axes_length = std::max(pad.axes_length, axis_index + 1); | 208 pad.axes_length = std::max(pad.axes_length, axis_index + 1); |
212 } else { | 209 } else { |
213 mapped_all_axes = false; | 210 mapped_all_axes = false; |
214 } | 211 } |
215 } | 212 } |
216 } | 213 } |
217 | 214 |
218 if (!mapped_all_axes) { | 215 if (!mapped_all_axes) { |
219 // For axes who's usage puts them outside the standard axesLengthCap range. | 216 // For axes who's usage puts them outside the standard axesLengthCap range. |
220 uint32_t next_index = 0; | 217 uint32_t next_index = 0; |
221 for (id elem in elements) { | 218 for (id elem in elements) { |
222 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem); | 219 IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem); |
223 if (!CheckCollection(element)) | 220 if (!CheckCollection(element)) |
224 continue; | 221 continue; |
225 | 222 |
226 uint32_t usage_page = IOHIDElementGetUsagePage(element); | 223 uint32_t usage_page = IOHIDElementGetUsagePage(element); |
227 uint32_t usage = IOHIDElementGetUsage(element); | 224 uint32_t usage = IOHIDElementGetUsage(element); |
228 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc && | 225 if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc && |
229 usage - kAxisMinimumUsageNumber >= WebGamepad::kAxesLengthCap && | 226 usage - kAxisMinimumUsageNumber >= Gamepad::kAxesLengthCap && |
230 usage_page <= kGameControlsUsagePage) { | 227 usage_page <= kGameControlsUsagePage) { |
231 for (; next_index < WebGamepad::kAxesLengthCap; ++next_index) { | 228 for (; next_index < Gamepad::kAxesLengthCap; ++next_index) { |
232 if (associated.axis_elements[next_index] == NULL) | 229 if (associated.axis_elements[next_index] == NULL) |
233 break; | 230 break; |
234 } | 231 } |
235 if (next_index < WebGamepad::kAxesLengthCap) { | 232 if (next_index < Gamepad::kAxesLengthCap) { |
236 associated.axis_elements[next_index] = element; | 233 associated.axis_elements[next_index] = element; |
237 pad.axes_length = std::max(pad.axes_length, next_index + 1); | 234 pad.axes_length = std::max(pad.axes_length, next_index + 1); |
238 } | 235 } |
239 } | 236 } |
240 | 237 |
241 if (next_index >= WebGamepad::kAxesLengthCap) | 238 if (next_index >= Gamepad::kAxesLengthCap) |
242 break; | 239 break; |
243 } | 240 } |
244 } | 241 } |
245 | 242 |
246 for (uint32_t axis_index = 0; axis_index < pad.axes_length; ++axis_index) { | 243 for (uint32_t axis_index = 0; axis_index < pad.axes_length; ++axis_index) { |
247 IOHIDElementRef element = associated.axis_elements[axis_index]; | 244 IOHIDElementRef element = associated.axis_elements[axis_index]; |
248 if (element != NULL) { | 245 if (element != NULL) { |
249 CFIndex axis_min = IOHIDElementGetLogicalMin(element); | 246 CFIndex axis_min = IOHIDElementGetLogicalMin(element); |
250 CFIndex axis_max = IOHIDElementGetLogicalMax(element); | 247 CFIndex axis_max = IOHIDElementGetLogicalMax(element); |
251 | 248 |
252 // Some HID axes report a logical range of -1 to 0 signed, which must be | 249 // Some HID axes report a logical range of -1 to 0 signed, which must be |
253 // interpreted as 0 to -1 unsigned for correct normalization behavior. | 250 // interpreted as 0 to -1 unsigned for correct normalization behavior. |
254 if (axis_min == -1 && axis_max == 0) { | 251 if (axis_min == -1 && axis_max == 0) { |
255 axis_max = -1; | 252 axis_max = -1; |
256 axis_min = 0; | 253 axis_min = 0; |
257 } | 254 } |
258 | 255 |
259 associated.axis_minimums[axis_index] = axis_min; | 256 associated.axis_minimums[axis_index] = axis_min; |
260 associated.axis_maximums[axis_index] = axis_max; | 257 associated.axis_maximums[axis_index] = axis_max; |
261 associated.axis_report_sizes[axis_index] = | 258 associated.axis_report_sizes[axis_index] = |
262 IOHIDElementGetReportSize(element); | 259 IOHIDElementGetReportSize(element); |
263 } | 260 } |
264 } | 261 } |
265 | 262 |
266 return (pad.axes_length > 0 || pad.buttons_length > 0); | 263 return (pad.axes_length > 0 || pad.buttons_length > 0); |
267 } | 264 } |
268 | 265 |
269 size_t GamepadPlatformDataFetcherMac::GetEmptySlot() { | 266 size_t GamepadPlatformDataFetcherMac::GetEmptySlot() { |
270 // Find a free slot for this device. | 267 // Find a free slot for this device. |
271 for (size_t slot = 0; slot < WebGamepads::kItemsLengthCap; ++slot) { | 268 for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) { |
272 if (associated_[slot].device_ref == nullptr) | 269 if (associated_[slot].device_ref == nullptr) |
273 return slot; | 270 return slot; |
274 } | 271 } |
275 return WebGamepads::kItemsLengthCap; | 272 return Gamepads::kItemsLengthCap; |
276 } | 273 } |
277 | 274 |
278 size_t GamepadPlatformDataFetcherMac::GetSlotForDevice(IOHIDDeviceRef device) { | 275 size_t GamepadPlatformDataFetcherMac::GetSlotForDevice(IOHIDDeviceRef device) { |
279 for (size_t slot = 0; slot < WebGamepads::kItemsLengthCap; ++slot) { | 276 for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) { |
280 // If we already have this device, and it's already connected, don't do | 277 // If we already have this device, and it's already connected, don't do |
281 // anything now. | 278 // anything now. |
282 if (associated_[slot].device_ref == device) | 279 if (associated_[slot].device_ref == device) |
283 return WebGamepads::kItemsLengthCap; | 280 return Gamepads::kItemsLengthCap; |
284 } | 281 } |
285 return GetEmptySlot(); | 282 return GetEmptySlot(); |
286 } | 283 } |
287 | 284 |
288 void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) { | 285 void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) { |
289 using base::mac::CFToNSCast; | 286 using base::mac::CFToNSCast; |
290 using base::mac::CFCastStrict; | 287 using base::mac::CFCastStrict; |
291 | 288 |
292 if (!enabled_) | 289 if (!enabled_) |
293 return; | 290 return; |
294 | 291 |
295 NSNumber* location_id = CFToNSCast(CFCastStrict<CFNumberRef>( | 292 NSNumber* location_id = CFToNSCast(CFCastStrict<CFNumberRef>( |
296 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey)))); | 293 IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey)))); |
297 int location_int = [location_id intValue]; | 294 int location_int = [location_id intValue]; |
298 | 295 |
299 // Find an index for this device. | 296 // Find an index for this device. |
300 size_t slot = GetSlotForDevice(device); | 297 size_t slot = GetSlotForDevice(device); |
301 | 298 |
302 // We can't handle this many connected devices. | 299 // We can't handle this many connected devices. |
303 if (slot == WebGamepads::kItemsLengthCap) | 300 if (slot == Gamepads::kItemsLengthCap) |
304 return; | 301 return; |
305 | 302 |
306 // Clear some state that may have been left behind by previous gamepads | 303 // Clear some state that may have been left behind by previous gamepads |
307 memset(&associated_[slot], 0, sizeof(AssociatedData)); | 304 memset(&associated_[slot], 0, sizeof(AssociatedData)); |
308 | 305 |
309 PadState* state = GetPadState(location_int); | 306 PadState* state = GetPadState(location_int); |
310 if (!state) | 307 if (!state) |
311 return; // No available slot for this device | 308 return; // No available slot for this device |
312 | 309 |
313 NSNumber* vendor_id = CFToNSCast(CFCastStrict<CFNumberRef>( | 310 NSNumber* vendor_id = CFToNSCast(CFCastStrict<CFNumberRef>( |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
349 associated_[slot].device_ref = device; | 346 associated_[slot].device_ref = device; |
350 state->data.connected = true; | 347 state->data.connected = true; |
351 } | 348 } |
352 | 349 |
353 void GamepadPlatformDataFetcherMac::DeviceRemove(IOHIDDeviceRef device) { | 350 void GamepadPlatformDataFetcherMac::DeviceRemove(IOHIDDeviceRef device) { |
354 if (!enabled_) | 351 if (!enabled_) |
355 return; | 352 return; |
356 | 353 |
357 // Find the index for this device. | 354 // Find the index for this device. |
358 size_t slot; | 355 size_t slot; |
359 for (slot = 0; slot < WebGamepads::kItemsLengthCap; ++slot) { | 356 for (slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) { |
360 if (associated_[slot].device_ref == device) | 357 if (associated_[slot].device_ref == device) |
361 break; | 358 break; |
362 } | 359 } |
363 DCHECK(slot < WebGamepads::kItemsLengthCap); | 360 DCHECK(slot < Gamepads::kItemsLengthCap); |
364 // Leave associated device_ref so that it will be reconnected in the same | 361 // Leave associated device_ref so that it will be reconnected in the same |
365 // location. Simply mark it as disconnected. | 362 // location. Simply mark it as disconnected. |
366 associated_[slot].location_id = 0; | 363 associated_[slot].location_id = 0; |
367 associated_[slot].device_ref = nullptr; | 364 associated_[slot].device_ref = nullptr; |
368 } | 365 } |
369 | 366 |
370 void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) { | 367 void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) { |
371 if (!enabled_ || paused_) | 368 if (!enabled_ || paused_) |
372 return; | 369 return; |
373 | 370 |
374 IOHIDElementRef element = IOHIDValueGetElement(value); | 371 IOHIDElementRef element = IOHIDValueGetElement(value); |
375 IOHIDDeviceRef device = IOHIDElementGetDevice(element); | 372 IOHIDDeviceRef device = IOHIDElementGetDevice(element); |
376 | 373 |
377 // Find device slot. | 374 // Find device slot. |
378 size_t slot; | 375 size_t slot; |
379 for (slot = 0; slot < WebGamepads::kItemsLengthCap; ++slot) { | 376 for (slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) { |
380 if (associated_[slot].device_ref == device) | 377 if (associated_[slot].device_ref == device) |
381 break; | 378 break; |
382 } | 379 } |
383 if (slot == WebGamepads::kItemsLengthCap) | 380 if (slot == Gamepads::kItemsLengthCap) |
384 return; | 381 return; |
385 | 382 |
386 PadState* state = GetPadState(associated_[slot].location_id); | 383 PadState* state = GetPadState(associated_[slot].location_id); |
387 if (!state) | 384 if (!state) |
388 return; | 385 return; |
389 | 386 |
390 WebGamepad& pad = state->data; | 387 Gamepad& pad = state->data; |
391 AssociatedData& associated = associated_[slot]; | 388 AssociatedData& associated = associated_[slot]; |
392 | 389 |
393 uint32_t value_length = IOHIDValueGetLength(value); | 390 uint32_t value_length = IOHIDValueGetLength(value); |
394 if (value_length > 4) { | 391 if (value_length > 4) { |
395 // Workaround for bizarre issue with PS3 controllers that try to return | 392 // Workaround for bizarre issue with PS3 controllers that try to return |
396 // massive (30+ byte) values and crash IOHIDValueGetIntegerValue | 393 // massive (30+ byte) values and crash IOHIDValueGetIntegerValue |
397 return; | 394 return; |
398 } | 395 } |
399 | 396 |
400 // Find and fill in the associated button event, if any. | 397 // Find and fill in the associated button event, if any. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
435 return; | 432 return; |
436 } | 433 } |
437 } | 434 } |
438 } | 435 } |
439 | 436 |
440 void GamepadPlatformDataFetcherMac::GetGamepadData(bool) { | 437 void GamepadPlatformDataFetcherMac::GetGamepadData(bool) { |
441 if (!enabled_) | 438 if (!enabled_) |
442 return; | 439 return; |
443 | 440 |
444 // Loop through and GetPadState to indicate the devices are still connected. | 441 // Loop through and GetPadState to indicate the devices are still connected. |
445 for (size_t slot = 0; slot < WebGamepads::kItemsLengthCap; ++slot) { | 442 for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) { |
446 if (associated_[slot].device_ref != nullptr) { | 443 if (associated_[slot].device_ref != nullptr) { |
447 GetPadState(associated_[slot].location_id); | 444 GetPadState(associated_[slot].location_id); |
448 } | 445 } |
449 } | 446 } |
450 } | 447 } |
451 | 448 |
452 } // namespace device | 449 } // namespace device |
OLD | NEW |