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]; |
} |