| 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" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |