Chromium Code Reviews| 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 |