Chromium Code Reviews| Index: content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm |
| diff --git a/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm |
| index 84bad06f7707fc730bcb13f1d79fb0478e03da46..3f3e1d77ec8c77cf0e3c0af811e5d5ba54dac09d 100644 |
| --- a/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm |
| +++ b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm |
| @@ -8,6 +8,7 @@ |
| #include "base/memory/scoped_nsobject.h" |
| #include "base/string16.h" |
| #include "base/string_util.h" |
| +#include "base/time.h" |
| #include "base/utf_string_conversions.h" |
| #include <IOKit/hid/IOHIDKeys.h> |
| @@ -60,6 +61,8 @@ GamepadPlatformDataFetcherMac::GamepadPlatformDataFetcherMac() |
| hid_manager_ref_, |
| base::mac::NSToCFCast(criteria)); |
| + xbox_fetcher_.reset(new XboxDataFetcher(this)); |
| + |
| RegisterForNotifications(); |
| } |
| @@ -87,6 +90,8 @@ void GamepadPlatformDataFetcherMac::RegisterForNotifications() { |
| enabled_ = IOHIDManagerOpen(hid_manager_ref_, |
| kIOHIDOptionsTypeNone) == kIOReturnSuccess; |
| + |
| + xbox_fetcher_->RegisterForNotifications(); |
| } |
| void GamepadPlatformDataFetcherMac::UnregisterFromNotifications() { |
| @@ -95,6 +100,7 @@ void GamepadPlatformDataFetcherMac::UnregisterFromNotifications() { |
| CFRunLoopGetCurrent(), |
| kCFRunLoopDefaultMode); |
| IOHIDManagerClose(hid_manager_ref_, kIOHIDOptionsTypeNone); |
| + xbox_fetcher_->UnregisterFromNotifications(); |
| } |
| void GamepadPlatformDataFetcherMac::PauseHint(bool pause) { |
| @@ -109,36 +115,36 @@ GamepadPlatformDataFetcherMac::~GamepadPlatformDataFetcherMac() { |
| } |
| GamepadPlatformDataFetcherMac* |
| -GamepadPlatformDataFetcherMac::InstanceFromContext( |
| - void* context) { |
| +GamepadPlatformDataFetcherMac::InstanceFromContext(void* context) { |
| return reinterpret_cast<GamepadPlatformDataFetcherMac*>(context); |
| } |
| void GamepadPlatformDataFetcherMac::DeviceAddCallback(void* context, |
| - IOReturn result, |
| - void* sender, |
| - IOHIDDeviceRef ref) { |
| + IOReturn result, |
| + void* sender, |
| + IOHIDDeviceRef ref) { |
| InstanceFromContext(context)->DeviceAdd(ref); |
| } |
| void GamepadPlatformDataFetcherMac::DeviceRemoveCallback(void* context, |
| - IOReturn result, |
| - void* sender, |
| - IOHIDDeviceRef ref) { |
| + IOReturn result, |
| + void* sender, |
| + IOHIDDeviceRef ref) { |
| InstanceFromContext(context)->DeviceRemove(ref); |
| } |
| void GamepadPlatformDataFetcherMac::ValueChangedCallback(void* context, |
| - IOReturn result, |
| - void* sender, |
| - IOHIDValueRef ref) { |
| + IOReturn result, |
| + void* sender, |
| + IOHIDValueRef ref) { |
| InstanceFromContext(context)->ValueChanged(ref); |
| } |
| void GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements, |
| - size_t slot) { |
| + size_t slot) { |
| WebKit::WebGamepad& pad = data_.items[slot]; |
| AssociatedData& associated = associated_[slot]; |
| + CHECK(!associated.is_xbox); |
| pad.axesLength = 0; |
| pad.buttonsLength = 0; |
| @@ -154,18 +160,18 @@ void GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements, |
| usagePage == kButtonUsagePage) { |
| uint32_t button_index = usage - 1; |
| if (button_index < WebKit::WebGamepad::buttonsLengthCap) { |
| - associated.button_elements[button_index] = element; |
| + associated.hid.button_elements[button_index] = element; |
| pad.buttonsLength = std::max(pad.buttonsLength, button_index + 1); |
| } |
| } |
| else if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc) { |
| uint32_t axis_index = usage - kAxisMinimumUsageNumber; |
| if (axis_index < WebKit::WebGamepad::axesLengthCap) { |
| - associated.axis_minimums[axis_index] = |
| + associated.hid.axis_minimums[axis_index] = |
| IOHIDElementGetLogicalMin(element); |
| - associated.axis_maximums[axis_index] = |
| + associated.hid.axis_maximums[axis_index] = |
| IOHIDElementGetLogicalMax(element); |
| - associated.axis_elements[axis_index] = element; |
| + associated.hid.axis_elements[axis_index] = element; |
| pad.axesLength = std::max(pad.axesLength, axis_index + 1); |
| } |
| } |
| @@ -186,7 +192,9 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) { |
| for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { |
| // If we already have this device, and it's already connected, don't do |
| // anything now. |
| - if (associated_[slot].device_ref == device && data_.items[slot].connected) |
| + if (data_.items[slot].connected && |
| + !associated_[slot].is_xbox && |
| + associated_[slot].hid.device_ref == device) |
| return; |
| if (!data_.items[slot].connected) |
| break; |
| @@ -208,13 +216,13 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) { |
| char vendor_as_str[5], product_as_str[5]; |
| snprintf(vendor_as_str, sizeof(vendor_as_str), "%04x", vendor_int); |
| snprintf(product_as_str, sizeof(product_as_str), "%04x", product_int); |
| - associated_[slot].mapper = |
| + associated_[slot].hid.mapper = |
| GetGamepadStandardMappingFunction(vendor_as_str, product_as_str); |
| NSString* ident = [NSString stringWithFormat: |
| @"%@ (%sVendor: %04x Product: %04x)", |
| product, |
| - associated_[slot].mapper ? "STANDARD GAMEPAD " : "", |
| + associated_[slot].hid.mapper ? "STANDARD GAMEPAD " : "", |
| vendor_int, |
| product_int]; |
| NSData* as16 = [ident dataUsingEncoding:NSUTF16StringEncoding]; |
| @@ -228,7 +236,7 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) { |
| IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone)); |
| AddButtonsAndAxes(CFToNSCast(elements), slot); |
| - associated_[slot].device_ref = device; |
| + associated_[slot].hid.device_ref = device; |
| data_.items[slot].connected = true; |
| if (slot >= data_.length) |
| data_.length = slot + 1; |
| @@ -242,7 +250,9 @@ void GamepadPlatformDataFetcherMac::DeviceRemove(IOHIDDeviceRef device) { |
| // Find the index for this device. |
| for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { |
| - if (associated_[slot].device_ref == device && data_.items[slot].connected) |
| + if (data_.items[slot].connected && |
| + !associated_[slot].is_xbox && |
| + associated_[slot].hid.device_ref == device) |
| break; |
| } |
| DCHECK(slot < WebGamepads::itemsLengthCap); |
| @@ -261,7 +271,9 @@ void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) { |
| // Find device slot. |
| size_t slot; |
| for (slot = 0; slot < data_.length; ++slot) { |
| - if (data_.items[slot].connected && associated_[slot].device_ref == device) |
| + if (data_.items[slot].connected && |
| + !associated_[slot].is_xbox && |
| + associated_[slot].hid.device_ref == device) |
| break; |
| } |
| if (slot == data_.length) |
| @@ -272,7 +284,7 @@ void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) { |
| // Find and fill in the associated button event, if any. |
| for (size_t i = 0; i < pad.buttonsLength; ++i) { |
| - if (associated.button_elements[i] == element) { |
| + if (associated.hid.button_elements[i] == element) { |
| pad.buttons[i] = IOHIDValueGetIntegerValue(value) ? 1.f : 0.f; |
| pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value)); |
| return; |
| @@ -281,16 +293,123 @@ void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) { |
| // Find and fill in the associated axis event, if any. |
| for (size_t i = 0; i < pad.axesLength; ++i) { |
| - if (associated.axis_elements[i] == element) { |
| + if (associated.hid.axis_elements[i] == element) { |
| pad.axes[i] = NormalizeAxis(IOHIDValueGetIntegerValue(value), |
| - associated.axis_minimums[i], |
| - associated.axis_maximums[i]); |
| + associated.hid.axis_minimums[i], |
| + associated.hid.axis_maximums[i]); |
| pad.timestamp = std::max(pad.timestamp, IOHIDValueGetTimeStamp(value)); |
| return; |
| } |
| } |
| } |
| +void GamepadPlatformDataFetcherMac::XboxDeviceAdd(XboxController* device) { |
| + using WebKit::WebGamepad; |
| + using WebKit::WebGamepads; |
|
Avi (use Gerrit)
2013/04/22 21:00:51
It seems a bit silly that every function puts thes
jeremya
2013/04/23 04:38:25
Done.
|
| + size_t slot; |
|
Mark Mentovai
2013/04/23 19:46:59
Don’t declare stuff ’til you use it. You can decla
jeremya
2013/04/24 00:18:51
Done.
|
| + |
| + if (!enabled_) |
| + return; |
| + |
| + for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { |
| + if (associated_[slot].is_xbox && |
| + !data_.items[slot].connected && |
| + associated_[slot].xbox.location_id == device->location_id()) { |
| + break; |
| + } |
| + } |
| + |
| + if (slot == WebGamepads::itemsLengthCap) { |
| + // Find an index for this device. |
| + for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { |
| + // If we already have this device, and it's already connected, don't do |
| + // anything now. |
| + if (associated_[slot].is_xbox && |
| + data_.items[slot].connected && |
| + associated_[slot].xbox.device == device) |
| + return; |
| + // XXX looks like there's a bug here? what if the first slot is empty, |
| + // but the device is connected in slot 3? hm. also in DeviceAdd. |
|
scottmg
2013/04/19 17:03:50
yup, you're right :(
jeremya
2013/04/21 00:33:09
Cool, I'll fix up this logic (and maybe see if I c
|
| + if (!data_.items[slot].connected) |
| + break; |
| + } |
| + } |
| + |
| + // We can't handle this many connected devices. |
| + if (slot == WebGamepads::itemsLengthCap) |
| + return; |
| + |
| + device->SetLEDPattern( |
| + (XboxController::LEDPattern)(XboxController::LED_FLASH_1 + slot)); |
| + |
| + NSString* ident = |
| + @"Xbox360 Controller (STANDARD GAMEPAD Vendor: 045e Product: 028e)"; |
|
scottmg
2013/04/19 17:03:50
space after Xbox to match https://code.google.com/
jeremya
2013/04/23 04:38:25
Done, also changed to not duplicate the vendor/pro
|
| + NSData* as16 = [ident dataUsingEncoding:NSUTF16StringEncoding]; |
| + const size_t kOutputLengthBytes = sizeof(data_.items[slot].id); |
| + memset(&data_.items[slot].id, 0, kOutputLengthBytes); |
| + [as16 getBytes:data_.items[slot].id |
| + length:kOutputLengthBytes - sizeof(WebKit::WebUChar)]; |
| + |
| + associated_[slot].is_xbox = true; |
| + associated_[slot].xbox.device = device; |
| + associated_[slot].xbox.location_id = device->location_id(); |
| + data_.items[slot].connected = true; |
| + data_.items[slot].axesLength = 4; |
| + data_.items[slot].buttonsLength = 17; |
| + data_.items[slot].timestamp = 0; |
| + if (slot >= data_.length) |
| + data_.length = slot + 1; |
| +} |
| + |
| +void GamepadPlatformDataFetcherMac::XboxDeviceRemove(XboxController* device) { |
| + using WebKit::WebGamepads; |
| + size_t slot; |
| + if (!enabled_) |
| + return; |
| + |
| + // Find the index for this device. |
| + for (slot = 0; slot < WebGamepads::itemsLengthCap; ++slot) { |
| + if (data_.items[slot].connected && |
| + associated_[slot].is_xbox && |
| + associated_[slot].xbox.device == device) |
| + break; |
| + } |
| + DCHECK(slot < WebGamepads::itemsLengthCap); |
| + // Leave associated device_ref so that it will be reconnected in the same |
| + // location. Simply mark it as disconnected. |
| + // TODO(jeremya): use location id to match replugged controllers. |
| + data_.items[slot].connected = false; |
| +} |
| + |
| +void GamepadPlatformDataFetcherMac::XboxValueChanged( |
| + XboxController* device, const XboxController::Data& data) { |
| + // XXX should have xbox_enabled_ too. |
| + if (!enabled_) |
| + return; |
| + |
| + // Find device slot. |
| + size_t slot; |
| + for (slot = 0; slot < data_.length; ++slot) { |
| + if (data_.items[slot].connected && |
| + associated_[slot].is_xbox && |
| + associated_[slot].xbox.device == device) |
| + break; |
| + } |
| + if (slot == data_.length) |
| + return; |
| + |
| + WebKit::WebGamepad& pad = data_.items[slot]; |
| + |
| + // Find and fill in the associated button event, if any. |
| + for (size_t i = 0; i < arraysize(data.buttons); i++) { |
| + pad.buttons[i] = data.buttons[i]; |
| + } |
| + for (size_t i = 0; i < arraysize(data.axes); i++) { |
| + pad.axes[i] = data.axes[i]; |
| + } |
| + pad.timestamp = base::TimeTicks::Now().ToInternalValue(); |
| +} |
| + |
| void GamepadPlatformDataFetcherMac::GetGamepadData( |
| WebKit::WebGamepads* pads, |
| bool) { |
| @@ -303,8 +422,8 @@ void GamepadPlatformDataFetcherMac::GetGamepadData( |
| // function, if there is one available. |
| pads->length = WebKit::WebGamepads::itemsLengthCap; |
| for (size_t i = 0; i < WebKit::WebGamepads::itemsLengthCap; ++i) { |
| - if (associated_[i].mapper) |
| - associated_[i].mapper(data_.items[i], &pads->items[i]); |
| + if (!associated_[i].is_xbox && associated_[i].hid.mapper) |
| + associated_[i].hid.mapper(data_.items[i], &pads->items[i]); |
| else |
| pads->items[i] = data_.items[i]; |
| } |