| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "content/browser/gamepad/xbox_data_fetcher_mac.h" | 5 #include "content/browser/gamepad/xbox_data_fetcher_mac.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <limits> | 9 #include <limits> |
| 10 | 10 |
| 11 #include <CoreFoundation/CoreFoundation.h> | 11 #include <CoreFoundation/CoreFoundation.h> |
| 12 #include <IOKit/IOCFPlugIn.h> | 12 #include <IOKit/IOCFPlugIn.h> |
| 13 #include <IOKit/IOKitLib.h> | 13 #include <IOKit/IOKitLib.h> |
| 14 #include <IOKit/usb/IOUSBLib.h> | 14 #include <IOKit/usb/IOUSBLib.h> |
| 15 #include <IOKit/usb/USB.h> | 15 #include <IOKit/usb/USB.h> |
| 16 | 16 |
| 17 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/mac/foundation_util.h" | 18 #include "base/mac/foundation_util.h" |
| 19 | 19 |
| 20 namespace { | 20 namespace { |
| 21 const int kVendorMicrosoft = 0x045e; | 21 const int kVendorMicrosoft = 0x045e; |
| 22 const int kProduct360Controller = 0x028e; | 22 const int kProductXbox360Controller = 0x028e; |
| 23 const int kProductXboxOneController = 0x02d1; |
| 23 | 24 |
| 24 const int kReadEndpoint = 1; | 25 const int kXbox360ReadEndpoint = 1; |
| 25 const int kControlEndpoint = 2; | 26 const int kXbox360ControlEndpoint = 2; |
| 27 |
| 28 const int kXboxOneReadEndpoint = 2; |
| 29 const int kXboxOneControlEndpoint = 1; |
| 26 | 30 |
| 27 enum { | 31 enum { |
| 28 STATUS_MESSAGE_BUTTONS = 0, | 32 STATUS_MESSAGE_BUTTONS = 0, |
| 29 STATUS_MESSAGE_LED = 1, | 33 STATUS_MESSAGE_LED = 1, |
| 30 | 34 |
| 31 // Apparently this message tells you if the rumble pack is disabled in the | 35 // Apparently this message tells you if the rumble pack is disabled in the |
| 32 // controller. If the rumble pack is disabled, vibration control messages | 36 // controller. If the rumble pack is disabled, vibration control messages |
| 33 // have no effect. | 37 // have no effect. |
| 34 STATUS_MESSAGE_RUMBLE = 3, | 38 STATUS_MESSAGE_RUMBLE = 3, |
| 35 }; | 39 }; |
| 36 | 40 |
| 37 enum { | 41 enum { |
| 42 XBOX_ONE_STATUS_MESSAGE_BUTTONS = 0x20, |
| 43 }; |
| 44 |
| 45 enum { |
| 38 CONTROL_MESSAGE_SET_RUMBLE = 0, | 46 CONTROL_MESSAGE_SET_RUMBLE = 0, |
| 39 CONTROL_MESSAGE_SET_LED = 1, | 47 CONTROL_MESSAGE_SET_LED = 1, |
| 40 }; | 48 }; |
| 41 | 49 |
| 42 #pragma pack(push, 1) | 50 #pragma pack(push, 1) |
| 43 struct ButtonData { | 51 struct Xbox360ButtonData { |
| 44 bool dpad_up : 1; | 52 bool dpad_up : 1; |
| 45 bool dpad_down : 1; | 53 bool dpad_down : 1; |
| 46 bool dpad_left : 1; | 54 bool dpad_left : 1; |
| 47 bool dpad_right : 1; | 55 bool dpad_right : 1; |
| 48 | 56 |
| 49 bool start : 1; | 57 bool start : 1; |
| 50 bool back : 1; | 58 bool back : 1; |
| 51 bool stick_left_click : 1; | 59 bool stick_left_click : 1; |
| 52 bool stick_right_click : 1; | 60 bool stick_right_click : 1; |
| 53 | 61 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 66 | 74 |
| 67 int16 stick_left_x; | 75 int16 stick_left_x; |
| 68 int16 stick_left_y; | 76 int16 stick_left_y; |
| 69 int16 stick_right_x; | 77 int16 stick_right_x; |
| 70 int16 stick_right_y; | 78 int16 stick_right_y; |
| 71 | 79 |
| 72 // Always 0. | 80 // Always 0. |
| 73 uint32 dummy2; | 81 uint32 dummy2; |
| 74 uint16 dummy3; | 82 uint16 dummy3; |
| 75 }; | 83 }; |
| 84 |
| 85 struct XboxOneButtonData { |
| 86 bool sync : 1; |
| 87 bool dummy1 : 1; // Always 0. |
| 88 bool start : 1; |
| 89 bool back : 1; |
| 90 |
| 91 bool a : 1; |
| 92 bool b : 1; |
| 93 bool x : 1; |
| 94 bool y : 1; |
| 95 |
| 96 bool dpad_up : 1; |
| 97 bool dpad_down : 1; |
| 98 bool dpad_left : 1; |
| 99 bool dpad_right : 1; |
| 100 |
| 101 bool bumper_left : 1; |
| 102 bool bumper_right : 1; |
| 103 bool stick_left_click : 1; |
| 104 bool stick_right_click : 1; |
| 105 |
| 106 uint16 trigger_left; |
| 107 uint16 trigger_right; |
| 108 |
| 109 int16 stick_left_x; |
| 110 int16 stick_left_y; |
| 111 int16 stick_right_x; |
| 112 int16 stick_right_y; |
| 113 }; |
| 76 #pragma pack(pop) | 114 #pragma pack(pop) |
| 77 | 115 |
| 78 COMPILE_ASSERT(sizeof(ButtonData) == 0x12, xbox_button_data_wrong_size); | 116 COMPILE_ASSERT(sizeof(Xbox360ButtonData) == 18, xbox_button_data_wrong_size); |
| 117 COMPILE_ASSERT(sizeof(XboxOneButtonData) == 14, xbox_button_data_wrong_size); |
| 79 | 118 |
| 80 // From MSDN: | 119 // From MSDN: |
| 81 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee417001(v=vs.85).asp
x#dead_zone | 120 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee417001(v=vs.85).asp
x#dead_zone |
| 82 const int16 kLeftThumbDeadzone = 7849; | 121 const int16 kLeftThumbDeadzone = 7849; |
| 83 const int16 kRightThumbDeadzone = 8689; | 122 const int16 kRightThumbDeadzone = 8689; |
| 84 const uint8 kTriggerDeadzone = 30; | 123 const uint8 kXbox360TriggerDeadzone = 30; |
| 124 const uint16 kXboxOneTriggerMax = 1023; |
| 125 const uint16 kXboxOneTriggerDeadzone = 120; |
| 85 | 126 |
| 86 void NormalizeAxis(int16 x, | 127 void NormalizeAxis(int16 x, |
| 87 int16 y, | 128 int16 y, |
| 88 int16 deadzone, | 129 int16 deadzone, |
| 89 float* x_out, | 130 float* x_out, |
| 90 float* y_out) { | 131 float* y_out) { |
| 91 float x_val = x; | 132 float x_val = x; |
| 92 float y_val = y; | 133 float y_val = y; |
| 93 | 134 |
| 94 // Determine how far the stick is pushed. | 135 // Determine how far the stick is pushed. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 110 // the 'standard controller' recommendations. | 151 // the 'standard controller' recommendations. |
| 111 *x_out = x_val * ratio; | 152 *x_out = x_val * ratio; |
| 112 *y_out = -y_val * ratio; | 153 *y_out = -y_val * ratio; |
| 113 } else { | 154 } else { |
| 114 // If the controller is in the deadzone zero out the magnitude. | 155 // If the controller is in the deadzone zero out the magnitude. |
| 115 *x_out = *y_out = 0.0f; | 156 *x_out = *y_out = 0.0f; |
| 116 } | 157 } |
| 117 } | 158 } |
| 118 | 159 |
| 119 float NormalizeTrigger(uint8 value) { | 160 float NormalizeTrigger(uint8 value) { |
| 120 return value < kTriggerDeadzone ? 0 : | 161 return value < kXbox360TriggerDeadzone ? 0 : |
| 121 static_cast<float>(value - kTriggerDeadzone) / | 162 static_cast<float>(value - kXbox360TriggerDeadzone) / |
| 122 (std::numeric_limits<uint8>::max() - kTriggerDeadzone); | 163 (std::numeric_limits<uint8>::max() - kXbox360TriggerDeadzone); |
| 123 } | 164 } |
| 124 | 165 |
| 125 void NormalizeButtonData(const ButtonData& data, | 166 float NormalizeXboxOneTrigger(uint16 value) { |
| 126 XboxController::Data* normalized_data) { | 167 return value < kXboxOneTriggerDeadzone ? 0 : |
| 168 static_cast<float>(value - kXboxOneTriggerDeadzone) / |
| 169 (kXboxOneTriggerMax - kXboxOneTriggerDeadzone); |
| 170 } |
| 171 |
| 172 void NormalizeXbox360ButtonData(const Xbox360ButtonData& data, |
| 173 XboxController::Data* normalized_data) { |
| 127 normalized_data->buttons[0] = data.a; | 174 normalized_data->buttons[0] = data.a; |
| 128 normalized_data->buttons[1] = data.b; | 175 normalized_data->buttons[1] = data.b; |
| 129 normalized_data->buttons[2] = data.x; | 176 normalized_data->buttons[2] = data.x; |
| 130 normalized_data->buttons[3] = data.y; | 177 normalized_data->buttons[3] = data.y; |
| 131 normalized_data->buttons[4] = data.bumper_left; | 178 normalized_data->buttons[4] = data.bumper_left; |
| 132 normalized_data->buttons[5] = data.bumper_right; | 179 normalized_data->buttons[5] = data.bumper_right; |
| 133 normalized_data->buttons[6] = data.back; | 180 normalized_data->buttons[6] = data.back; |
| 134 normalized_data->buttons[7] = data.start; | 181 normalized_data->buttons[7] = data.start; |
| 135 normalized_data->buttons[8] = data.stick_left_click; | 182 normalized_data->buttons[8] = data.stick_left_click; |
| 136 normalized_data->buttons[9] = data.stick_right_click; | 183 normalized_data->buttons[9] = data.stick_right_click; |
| 137 normalized_data->buttons[10] = data.dpad_up; | 184 normalized_data->buttons[10] = data.dpad_up; |
| 138 normalized_data->buttons[11] = data.dpad_down; | 185 normalized_data->buttons[11] = data.dpad_down; |
| 139 normalized_data->buttons[12] = data.dpad_left; | 186 normalized_data->buttons[12] = data.dpad_left; |
| 140 normalized_data->buttons[13] = data.dpad_right; | 187 normalized_data->buttons[13] = data.dpad_right; |
| 141 normalized_data->buttons[14] = data.guide; | 188 normalized_data->buttons[14] = data.guide; |
| 142 normalized_data->triggers[0] = NormalizeTrigger(data.trigger_left); | 189 normalized_data->triggers[0] = NormalizeTrigger(data.trigger_left); |
| 143 normalized_data->triggers[1] = NormalizeTrigger(data.trigger_right); | 190 normalized_data->triggers[1] = NormalizeTrigger(data.trigger_right); |
| 144 NormalizeAxis(data.stick_left_x, | 191 NormalizeAxis(data.stick_left_x, |
| 145 data.stick_left_y, | 192 data.stick_left_y, |
| 146 kLeftThumbDeadzone, | 193 kLeftThumbDeadzone, |
| 147 &normalized_data->axes[0], | 194 &normalized_data->axes[0], |
| 148 &normalized_data->axes[1]); | 195 &normalized_data->axes[1]); |
| 149 NormalizeAxis(data.stick_right_x, | 196 NormalizeAxis(data.stick_right_x, |
| 150 data.stick_right_y, | 197 data.stick_right_y, |
| 151 kRightThumbDeadzone, | 198 kRightThumbDeadzone, |
| 152 &normalized_data->axes[2], | 199 &normalized_data->axes[2], |
| 153 &normalized_data->axes[3]); | 200 &normalized_data->axes[3]); |
| 154 } | 201 } |
| 155 | 202 |
| 203 void NormalizeXboxOneButtonData(const XboxOneButtonData& data, |
| 204 XboxController::Data* normalized_data) { |
| 205 normalized_data->buttons[0] = data.a; |
| 206 normalized_data->buttons[1] = data.b; |
| 207 normalized_data->buttons[2] = data.x; |
| 208 normalized_data->buttons[3] = data.y; |
| 209 normalized_data->buttons[4] = data.bumper_left; |
| 210 normalized_data->buttons[5] = data.bumper_right; |
| 211 normalized_data->buttons[6] = data.back; |
| 212 normalized_data->buttons[7] = data.start; |
| 213 normalized_data->buttons[8] = data.stick_left_click; |
| 214 normalized_data->buttons[9] = data.stick_right_click; |
| 215 normalized_data->buttons[10] = data.dpad_up; |
| 216 normalized_data->buttons[11] = data.dpad_down; |
| 217 normalized_data->buttons[12] = data.dpad_left; |
| 218 normalized_data->buttons[13] = data.dpad_right; |
| 219 normalized_data->buttons[14] = data.sync; |
| 220 normalized_data->triggers[0] = NormalizeXboxOneTrigger(data.trigger_left); |
| 221 normalized_data->triggers[1] = NormalizeXboxOneTrigger(data.trigger_right); |
| 222 NormalizeAxis(data.stick_left_x, |
| 223 data.stick_left_y, |
| 224 kLeftThumbDeadzone, |
| 225 &normalized_data->axes[0], |
| 226 &normalized_data->axes[1]); |
| 227 NormalizeAxis(data.stick_right_x, |
| 228 data.stick_right_y, |
| 229 kRightThumbDeadzone, |
| 230 &normalized_data->axes[2], |
| 231 &normalized_data->axes[3]); |
| 232 } |
| 233 |
| 156 } // namespace | 234 } // namespace |
| 157 | 235 |
| 158 XboxController::XboxController(Delegate* delegate) | 236 XboxController::XboxController(Delegate* delegate) |
| 159 : device_(NULL), | 237 : device_(NULL), |
| 160 interface_(NULL), | 238 interface_(NULL), |
| 161 device_is_open_(false), | 239 device_is_open_(false), |
| 162 interface_is_open_(false), | 240 interface_is_open_(false), |
| 163 read_buffer_size_(0), | 241 read_buffer_size_(0), |
| 164 led_pattern_(LED_NUM_PATTERNS), | 242 led_pattern_(LED_NUM_PATTERNS), |
| 165 location_id_(0), | 243 location_id_(0), |
| 166 delegate_(delegate) { | 244 delegate_(delegate), |
| 245 controller_type_(UNKNOWN_CONTROLLER), |
| 246 read_endpoint_(0), |
| 247 control_endpoint_(0) { |
| 167 } | 248 } |
| 168 | 249 |
| 169 XboxController::~XboxController() { | 250 XboxController::~XboxController() { |
| 170 if (source_) | 251 if (source_) |
| 171 CFRunLoopSourceInvalidate(source_); | 252 CFRunLoopSourceInvalidate(source_); |
| 172 if (interface_ && interface_is_open_) | 253 if (interface_ && interface_is_open_) |
| 173 (*interface_)->USBInterfaceClose(interface_); | 254 (*interface_)->USBInterfaceClose(interface_); |
| 174 if (device_ && device_is_open_) | 255 if (device_ && device_is_open_) |
| 175 (*device_)->USBDeviceClose(device_); | 256 (*device_)->USBDeviceClose(device_); |
| 176 } | 257 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 190 | 271 |
| 191 HRESULT res = | 272 HRESULT res = |
| 192 (*plugin)->QueryInterface(plugin, | 273 (*plugin)->QueryInterface(plugin, |
| 193 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID320), | 274 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID320), |
| 194 (LPVOID *)&device_); | 275 (LPVOID *)&device_); |
| 195 if (!SUCCEEDED(res) || !device_) | 276 if (!SUCCEEDED(res) || !device_) |
| 196 return false; | 277 return false; |
| 197 | 278 |
| 198 UInt16 vendor_id; | 279 UInt16 vendor_id; |
| 199 kr = (*device_)->GetDeviceVendor(device_, &vendor_id); | 280 kr = (*device_)->GetDeviceVendor(device_, &vendor_id); |
| 200 if (kr != KERN_SUCCESS) | 281 if (kr != KERN_SUCCESS || vendor_id != kVendorMicrosoft) |
| 201 return false; | 282 return false; |
| 283 |
| 202 UInt16 product_id; | 284 UInt16 product_id; |
| 203 kr = (*device_)->GetDeviceProduct(device_, &product_id); | 285 kr = (*device_)->GetDeviceProduct(device_, &product_id); |
| 204 if (kr != KERN_SUCCESS) | 286 if (kr != KERN_SUCCESS) |
| 205 return false; | 287 return false; |
| 206 if (vendor_id != kVendorMicrosoft || product_id != kProduct360Controller) | 288 |
| 207 return false; | 289 IOUSBFindInterfaceRequest request; |
| 290 switch (product_id) { |
| 291 case kProductXbox360Controller: |
| 292 controller_type_ = XBOX_360_CONTROLLER; |
| 293 read_endpoint_ = kXbox360ReadEndpoint; |
| 294 control_endpoint_ = kXbox360ControlEndpoint; |
| 295 request.bInterfaceClass = 255; |
| 296 request.bInterfaceSubClass = 93; |
| 297 request.bInterfaceProtocol = 1; |
| 298 request.bAlternateSetting = kIOUSBFindInterfaceDontCare; |
| 299 break; |
| 300 case kProductXboxOneController: |
| 301 controller_type_ = XBOX_ONE_CONTROLLER; |
| 302 read_endpoint_ = kXboxOneReadEndpoint; |
| 303 control_endpoint_ = kXboxOneControlEndpoint; |
| 304 request.bInterfaceClass = 255; |
| 305 request.bInterfaceSubClass = 71; |
| 306 request.bInterfaceProtocol = 208; |
| 307 request.bAlternateSetting = kIOUSBFindInterfaceDontCare; |
| 308 break; |
| 309 default: |
| 310 return false; |
| 311 } |
| 208 | 312 |
| 209 // Open the device and configure it. | 313 // Open the device and configure it. |
| 210 kr = (*device_)->USBDeviceOpen(device_); | 314 kr = (*device_)->USBDeviceOpen(device_); |
| 211 if (kr != KERN_SUCCESS) | 315 if (kr != KERN_SUCCESS) |
| 212 return false; | 316 return false; |
| 213 device_is_open_ = true; | 317 device_is_open_ = true; |
| 214 | 318 |
| 215 // Xbox controllers have one configuration option which has configuration | 319 // Xbox controllers have one configuration option which has configuration |
| 216 // value 1. Try to set it and fail if it couldn't be configured. | 320 // value 1. Try to set it and fail if it couldn't be configured. |
| 217 IOUSBConfigurationDescriptorPtr config_desc; | 321 IOUSBConfigurationDescriptorPtr config_desc; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 229 // Protocol 2 has a single endpoint to read from a connected ChatPad device. | 333 // Protocol 2 has a single endpoint to read from a connected ChatPad device. |
| 230 // Protocol 3 is used by a connected headset device. | 334 // Protocol 3 is used by a connected headset device. |
| 231 // The device also has an interface on subclass 253, protocol 10 with no | 335 // The device also has an interface on subclass 253, protocol 10 with no |
| 232 // endpoints. It is unused. | 336 // endpoints. It is unused. |
| 233 // | 337 // |
| 234 // We don't currently support the ChatPad or headset, so protocol 1 is the | 338 // We don't currently support the ChatPad or headset, so protocol 1 is the |
| 235 // only protocol we care about. | 339 // only protocol we care about. |
| 236 // | 340 // |
| 237 // For more detail, see | 341 // For more detail, see |
| 238 // https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL | 342 // https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL |
| 239 IOUSBFindInterfaceRequest request; | |
| 240 request.bInterfaceClass = 255; | |
| 241 request.bInterfaceSubClass = 93; | |
| 242 request.bInterfaceProtocol = 1; | |
| 243 request.bAlternateSetting = kIOUSBFindInterfaceDontCare; | |
| 244 io_iterator_t iter; | 343 io_iterator_t iter; |
| 245 kr = (*device_)->CreateInterfaceIterator(device_, &request, &iter); | 344 kr = (*device_)->CreateInterfaceIterator(device_, &request, &iter); |
| 246 if (kr != KERN_SUCCESS) | 345 if (kr != KERN_SUCCESS) |
| 247 return false; | 346 return false; |
| 248 base::mac::ScopedIOObject<io_iterator_t> iter_ref(iter); | 347 base::mac::ScopedIOObject<io_iterator_t> iter_ref(iter); |
| 249 | 348 |
| 250 // There should be exactly one USB interface which matches the requested | 349 // There should be exactly one USB interface which matches the requested |
| 251 // settings. | 350 // settings. |
| 252 io_service_t usb_interface = IOIteratorNext(iter); | 351 io_service_t usb_interface = IOIteratorNext(iter); |
| 253 if (!usb_interface) | 352 if (!usb_interface) |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 uint16 max_packet_size; | 410 uint16 max_packet_size; |
| 312 uint8 interval; | 411 uint8 interval; |
| 313 | 412 |
| 314 kr = (*interface_)->GetPipeProperties(interface_, | 413 kr = (*interface_)->GetPipeProperties(interface_, |
| 315 i, | 414 i, |
| 316 &direction, | 415 &direction, |
| 317 &number, | 416 &number, |
| 318 &transfer_type, | 417 &transfer_type, |
| 319 &max_packet_size, | 418 &max_packet_size, |
| 320 &interval); | 419 &interval); |
| 321 if (kr != KERN_SUCCESS || transfer_type != kUSBInterrupt) | 420 if (kr != KERN_SUCCESS || transfer_type != kUSBInterrupt) { |
| 322 return false; | 421 return false; |
| 323 if (i == kReadEndpoint) { | 422 } |
| 423 if (i == read_endpoint_) { |
| 324 if (direction != kUSBIn) | 424 if (direction != kUSBIn) |
| 325 return false; | 425 return false; |
| 326 if (max_packet_size > 32) | |
| 327 return false; | |
| 328 read_buffer_.reset(new uint8[max_packet_size]); | 426 read_buffer_.reset(new uint8[max_packet_size]); |
| 329 read_buffer_size_ = max_packet_size; | 427 read_buffer_size_ = max_packet_size; |
| 330 QueueRead(); | 428 QueueRead(); |
| 331 } else if (i == kControlEndpoint) { | 429 } else if (i == control_endpoint_) { |
| 332 if (direction != kUSBOut) | 430 if (direction != kUSBOut) |
| 333 return false; | 431 return false; |
| 432 if (controller_type_ == XBOX_ONE_CONTROLLER) |
| 433 WriteXboxOneInit(); |
| 334 } | 434 } |
| 335 } | 435 } |
| 336 | 436 |
| 337 // The location ID is unique per controller, and can be used to track | 437 // The location ID is unique per controller, and can be used to track |
| 338 // controllers through reconnections (though if a controller is detached from | 438 // controllers through reconnections (though if a controller is detached from |
| 339 // one USB hub and attached to another, the location ID will change). | 439 // one USB hub and attached to another, the location ID will change). |
| 340 kr = (*device_)->GetLocationID(device_, &location_id_); | 440 kr = (*device_)->GetLocationID(device_, &location_id_); |
| 341 if (kr != KERN_SUCCESS) | 441 if (kr != KERN_SUCCESS) |
| 342 return false; | 442 return false; |
| 343 | 443 |
| 344 return true; | 444 return true; |
| 345 } | 445 } |
| 346 | 446 |
| 347 void XboxController::SetLEDPattern(LEDPattern pattern) { | 447 void XboxController::SetLEDPattern(LEDPattern pattern) { |
| 348 led_pattern_ = pattern; | 448 led_pattern_ = pattern; |
| 349 const UInt8 length = 3; | 449 const UInt8 length = 3; |
| 350 | 450 |
| 351 // This buffer will be released in WriteComplete when WritePipeAsync | 451 // This buffer will be released in WriteComplete when WritePipeAsync |
| 352 // finishes. | 452 // finishes. |
| 353 UInt8* buffer = new UInt8[length]; | 453 UInt8* buffer = new UInt8[length]; |
| 354 buffer[0] = static_cast<UInt8>(CONTROL_MESSAGE_SET_LED); | 454 buffer[0] = static_cast<UInt8>(CONTROL_MESSAGE_SET_LED); |
| 355 buffer[1] = length; | 455 buffer[1] = length; |
| 356 buffer[2] = static_cast<UInt8>(pattern); | 456 buffer[2] = static_cast<UInt8>(pattern); |
| 357 kern_return_t kr = (*interface_)->WritePipeAsync(interface_, | 457 kern_return_t kr = (*interface_)->WritePipeAsync(interface_, |
| 358 kControlEndpoint, | 458 control_endpoint_, |
| 359 buffer, | 459 buffer, |
| 360 (UInt32)length, | 460 (UInt32)length, |
| 361 WriteComplete, | 461 WriteComplete, |
| 362 buffer); | 462 buffer); |
| 363 if (kr != KERN_SUCCESS) { | 463 if (kr != KERN_SUCCESS) { |
| 364 delete[] buffer; | 464 delete[] buffer; |
| 365 IOError(); | 465 IOError(); |
| 366 return; | 466 return; |
| 367 } | 467 } |
| 368 } | 468 } |
| 369 | 469 |
| 370 int XboxController::GetVendorId() const { | 470 int XboxController::GetVendorId() const { |
| 371 return kVendorMicrosoft; | 471 return kVendorMicrosoft; |
| 372 } | 472 } |
| 373 | 473 |
| 374 int XboxController::GetProductId() const { | 474 int XboxController::GetProductId() const { |
| 375 return kProduct360Controller; | 475 if (controller_type_ == XBOX_360_CONTROLLER) |
| 476 return kProductXbox360Controller; |
| 477 else |
| 478 return kProductXboxOneController; |
| 479 } |
| 480 |
| 481 XboxController::ControllerType XboxController::GetControllerType() const { |
| 482 return controller_type_; |
| 376 } | 483 } |
| 377 | 484 |
| 378 void XboxController::WriteComplete(void* context, IOReturn result, void* arg0) { | 485 void XboxController::WriteComplete(void* context, IOReturn result, void* arg0) { |
| 379 UInt8* buffer = static_cast<UInt8*>(context); | 486 UInt8* buffer = static_cast<UInt8*>(context); |
| 380 delete[] buffer; | 487 delete[] buffer; |
| 381 | 488 |
| 382 // Ignoring any errors sending data, because they will usually only occur | 489 // Ignoring any errors sending data, because they will usually only occur |
| 383 // when the device is disconnected, in which case it really doesn't matter if | 490 // when the device is disconnected, in which case it really doesn't matter if |
| 384 // the data got to the controller or not. | 491 // the data got to the controller or not. |
| 385 if (result != kIOReturnSuccess) | 492 if (result != kIOReturnSuccess) |
| 386 return; | 493 return; |
| 387 } | 494 } |
| 388 | 495 |
| 389 void XboxController::GotData(void* context, IOReturn result, void* arg0) { | 496 void XboxController::GotData(void* context, IOReturn result, void* arg0) { |
| 390 size_t bytes_read = reinterpret_cast<size_t>(arg0); | 497 size_t bytes_read = reinterpret_cast<size_t>(arg0); |
| 391 XboxController* controller = static_cast<XboxController*>(context); | 498 XboxController* controller = static_cast<XboxController*>(context); |
| 392 | 499 |
| 393 if (result != kIOReturnSuccess) { | 500 if (result != kIOReturnSuccess) { |
| 394 // This will happen if the device was disconnected. The gamepad has | 501 // This will happen if the device was disconnected. The gamepad has |
| 395 // probably been destroyed by a meteorite. | 502 // probably been destroyed by a meteorite. |
| 396 controller->IOError(); | 503 controller->IOError(); |
| 397 return; | 504 return; |
| 398 } | 505 } |
| 399 | 506 |
| 400 controller->ProcessPacket(bytes_read); | 507 if (controller->GetControllerType() == XBOX_360_CONTROLLER) |
| 508 controller->ProcessXbox360Packet(bytes_read); |
| 509 else |
| 510 controller->ProcessXboxOnePacket(bytes_read); |
| 401 | 511 |
| 402 // Queue up another read. | 512 // Queue up another read. |
| 403 controller->QueueRead(); | 513 controller->QueueRead(); |
| 404 } | 514 } |
| 405 | 515 |
| 406 void XboxController::ProcessPacket(size_t length) { | 516 void XboxController::ProcessXbox360Packet(size_t length) { |
| 407 if (length < 2) return; | 517 if (length < 2) |
| 518 return; |
| 408 DCHECK(length <= read_buffer_size_); | 519 DCHECK(length <= read_buffer_size_); |
| 409 if (length > read_buffer_size_) { | 520 if (length > read_buffer_size_) { |
| 410 IOError(); | 521 IOError(); |
| 411 return; | 522 return; |
| 412 } | 523 } |
| 413 uint8* buffer = read_buffer_.get(); | 524 uint8* buffer = read_buffer_.get(); |
| 414 | 525 |
| 415 if (buffer[1] != length) | 526 if (buffer[1] != length) |
| 416 // Length in packet doesn't match length reported by USB. | 527 // Length in packet doesn't match length reported by USB. |
| 417 return; | 528 return; |
| 418 | 529 |
| 419 uint8 type = buffer[0]; | 530 uint8 type = buffer[0]; |
| 420 buffer += 2; | 531 buffer += 2; |
| 421 length -= 2; | 532 length -= 2; |
| 422 switch (type) { | 533 switch (type) { |
| 423 case STATUS_MESSAGE_BUTTONS: { | 534 case STATUS_MESSAGE_BUTTONS: { |
| 424 if (length != sizeof(ButtonData)) | 535 if (length != sizeof(Xbox360ButtonData)) |
| 425 return; | 536 return; |
| 426 ButtonData* data = reinterpret_cast<ButtonData*>(buffer); | 537 Xbox360ButtonData* data = reinterpret_cast<Xbox360ButtonData*>(buffer); |
| 427 Data normalized_data; | 538 Data normalized_data; |
| 428 NormalizeButtonData(*data, &normalized_data); | 539 NormalizeXbox360ButtonData(*data, &normalized_data); |
| 429 delegate_->XboxControllerGotData(this, normalized_data); | 540 delegate_->XboxControllerGotData(this, normalized_data); |
| 430 break; | 541 break; |
| 431 } | 542 } |
| 432 case STATUS_MESSAGE_LED: | 543 case STATUS_MESSAGE_LED: |
| 433 if (length != 3) | 544 if (length != 3) |
| 434 return; | 545 return; |
| 435 // The controller sends one of these messages every time the LED pattern | 546 // The controller sends one of these messages every time the LED pattern |
| 436 // is set, as well as once when it is plugged in. | 547 // is set, as well as once when it is plugged in. |
| 437 if (led_pattern_ == LED_NUM_PATTERNS && buffer[0] < LED_NUM_PATTERNS) | 548 if (led_pattern_ == LED_NUM_PATTERNS && buffer[0] < LED_NUM_PATTERNS) |
| 438 led_pattern_ = static_cast<LEDPattern>(buffer[0]); | 549 led_pattern_ = static_cast<LEDPattern>(buffer[0]); |
| 439 break; | 550 break; |
| 440 default: | 551 default: |
| 441 // Unknown packet: ignore! | 552 // Unknown packet: ignore! |
| 442 break; | 553 break; |
| 443 } | 554 } |
| 444 } | 555 } |
| 445 | 556 |
| 557 void XboxController::ProcessXboxOnePacket(size_t length) { |
| 558 if (length < 2) |
| 559 return; |
| 560 DCHECK(length <= read_buffer_size_); |
| 561 if (length > read_buffer_size_) { |
| 562 IOError(); |
| 563 return; |
| 564 } |
| 565 uint8* buffer = read_buffer_.get(); |
| 566 |
| 567 uint8 type = buffer[0]; |
| 568 buffer += 4; |
| 569 length -= 4; |
| 570 switch (type) { |
| 571 case XBOX_ONE_STATUS_MESSAGE_BUTTONS: { |
| 572 if (length != sizeof(XboxOneButtonData)) |
| 573 return; |
| 574 XboxOneButtonData* data = reinterpret_cast<XboxOneButtonData*>(buffer); |
| 575 Data normalized_data; |
| 576 NormalizeXboxOneButtonData(*data, &normalized_data); |
| 577 delegate_->XboxControllerGotData(this, normalized_data); |
| 578 break; |
| 579 } |
| 580 default: |
| 581 // Unknown packet: ignore! |
| 582 break; |
| 583 } |
| 584 } |
| 585 |
| 446 void XboxController::QueueRead() { | 586 void XboxController::QueueRead() { |
| 447 kern_return_t kr = (*interface_)->ReadPipeAsync(interface_, | 587 kern_return_t kr = (*interface_)->ReadPipeAsync(interface_, |
| 448 kReadEndpoint, | 588 read_endpoint_, |
| 449 read_buffer_.get(), | 589 read_buffer_.get(), |
| 450 read_buffer_size_, | 590 read_buffer_size_, |
| 451 GotData, | 591 GotData, |
| 452 this); | 592 this); |
| 453 if (kr != KERN_SUCCESS) | 593 if (kr != KERN_SUCCESS) |
| 454 IOError(); | 594 IOError(); |
| 455 } | 595 } |
| 456 | 596 |
| 457 void XboxController::IOError() { | 597 void XboxController::IOError() { |
| 458 delegate_->XboxControllerError(this); | 598 delegate_->XboxControllerError(this); |
| 459 } | 599 } |
| 460 | 600 |
| 601 void XboxController::WriteXboxOneInit() { |
| 602 const UInt8 length = 2; |
| 603 |
| 604 // This buffer will be released in WriteComplete when WritePipeAsync |
| 605 // finishes. |
| 606 UInt8* buffer = new UInt8[length]; |
| 607 buffer[0] = 0x05; |
| 608 buffer[1] = 0x20; |
| 609 kern_return_t kr = (*interface_)->WritePipeAsync(interface_, |
| 610 control_endpoint_, |
| 611 buffer, |
| 612 (UInt32)length, |
| 613 WriteComplete, |
| 614 buffer); |
| 615 if (kr != KERN_SUCCESS) { |
| 616 delete[] buffer; |
| 617 IOError(); |
| 618 return; |
| 619 } |
| 620 } |
| 621 |
| 461 //----------------------------------------------------------------------------- | 622 //----------------------------------------------------------------------------- |
| 462 | 623 |
| 463 XboxDataFetcher::XboxDataFetcher(Delegate* delegate) | 624 XboxDataFetcher::XboxDataFetcher(Delegate* delegate) |
| 464 : delegate_(delegate), | 625 : delegate_(delegate), |
| 465 listening_(false), | 626 listening_(false), |
| 466 source_(NULL), | 627 source_(NULL), |
| 467 port_(NULL) { | 628 port_(NULL) { |
| 468 } | 629 } |
| 469 | 630 |
| 470 XboxDataFetcher::~XboxDataFetcher() { | 631 XboxDataFetcher::~XboxDataFetcher() { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 kNilOptions))); | 664 kNilOptions))); |
| 504 UInt32 location_id = 0; | 665 UInt32 location_id = 0; |
| 505 CFNumberGetValue(number, kCFNumberSInt32Type, &location_id); | 666 CFNumberGetValue(number, kCFNumberSInt32Type, &location_id); |
| 506 fetcher->RemoveControllerByLocationID(location_id); | 667 fetcher->RemoveControllerByLocationID(location_id); |
| 507 } | 668 } |
| 508 } | 669 } |
| 509 | 670 |
| 510 bool XboxDataFetcher::RegisterForNotifications() { | 671 bool XboxDataFetcher::RegisterForNotifications() { |
| 511 if (listening_) | 672 if (listening_) |
| 512 return true; | 673 return true; |
| 513 base::ScopedCFTypeRef<CFNumberRef> vendor_cf(CFNumberCreate( | |
| 514 kCFAllocatorDefault, kCFNumberSInt32Type, &kVendorMicrosoft)); | |
| 515 base::ScopedCFTypeRef<CFNumberRef> product_cf(CFNumberCreate( | |
| 516 kCFAllocatorDefault, kCFNumberSInt32Type, &kProduct360Controller)); | |
| 517 base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict( | |
| 518 IOServiceMatching(kIOUSBDeviceClassName)); | |
| 519 if (!matching_dict) | |
| 520 return false; | |
| 521 CFDictionarySetValue(matching_dict, CFSTR(kUSBVendorID), vendor_cf); | |
| 522 CFDictionarySetValue(matching_dict, CFSTR(kUSBProductID), product_cf); | |
| 523 port_ = IONotificationPortCreate(kIOMasterPortDefault); | 674 port_ = IONotificationPortCreate(kIOMasterPortDefault); |
| 524 if (!port_) | 675 if (!port_) |
| 525 return false; | 676 return false; |
| 526 source_ = IONotificationPortGetRunLoopSource(port_); | 677 source_ = IONotificationPortGetRunLoopSource(port_); |
| 527 if (!source_) | 678 if (!source_) |
| 528 return false; | 679 return false; |
| 529 CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopDefaultMode); | 680 CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopDefaultMode); |
| 530 | 681 |
| 531 listening_ = true; | 682 listening_ = true; |
| 532 | 683 |
| 684 if (!RegisterForDeviceNotifications( |
| 685 kVendorMicrosoft, kProductXboxOneController, |
| 686 &xbox_one_device_added_iter_, |
| 687 &xbox_one_device_removed_iter_)) |
| 688 return false; |
| 689 |
| 690 if (!RegisterForDeviceNotifications( |
| 691 kVendorMicrosoft, kProductXbox360Controller, |
| 692 &xbox_360_device_added_iter_, |
| 693 &xbox_360_device_removed_iter_)) |
| 694 return false; |
| 695 |
| 696 return true; |
| 697 } |
| 698 |
| 699 bool XboxDataFetcher::RegisterForDeviceNotifications( |
| 700 int vendor_id, |
| 701 int product_id, |
| 702 base::mac::ScopedIOObject<io_iterator_t>* added_iter, |
| 703 base::mac::ScopedIOObject<io_iterator_t>* removed_iter) { |
| 704 base::ScopedCFTypeRef<CFNumberRef> vendor_cf(CFNumberCreate( |
| 705 kCFAllocatorDefault, kCFNumberSInt32Type, &vendor_id)); |
| 706 base::ScopedCFTypeRef<CFNumberRef> product_cf(CFNumberCreate( |
| 707 kCFAllocatorDefault, kCFNumberSInt32Type, &product_id)); |
| 708 base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict( |
| 709 IOServiceMatching(kIOUSBDeviceClassName)); |
| 710 if (!matching_dict) |
| 711 return false; |
| 712 CFDictionarySetValue(matching_dict, CFSTR(kUSBVendorID), vendor_cf); |
| 713 CFDictionarySetValue(matching_dict, CFSTR(kUSBProductID), product_cf); |
| 714 |
| 533 // IOServiceAddMatchingNotification() releases the dictionary when it's done. | 715 // IOServiceAddMatchingNotification() releases the dictionary when it's done. |
| 534 // Retain it before each call to IOServiceAddMatchingNotification to keep | 716 // Retain it before each call to IOServiceAddMatchingNotification to keep |
| 535 // things balanced. | 717 // things balanced. |
| 536 CFRetain(matching_dict); | 718 CFRetain(matching_dict); |
| 537 io_iterator_t device_added_iter; | 719 io_iterator_t device_added_iter; |
| 538 IOReturn ret; | 720 IOReturn ret; |
| 539 ret = IOServiceAddMatchingNotification(port_, | 721 ret = IOServiceAddMatchingNotification(port_, |
| 540 kIOFirstMatchNotification, | 722 kIOFirstMatchNotification, |
| 541 matching_dict, | 723 matching_dict, |
| 542 DeviceAdded, | 724 DeviceAdded, |
| 543 this, | 725 this, |
| 544 &device_added_iter); | 726 &device_added_iter); |
| 545 device_added_iter_.reset(device_added_iter); | 727 added_iter->reset(device_added_iter); |
| 546 if (ret != kIOReturnSuccess) { | 728 if (ret != kIOReturnSuccess) { |
| 547 LOG(ERROR) << "Error listening for Xbox controller add events: " << ret; | 729 LOG(ERROR) << "Error listening for Xbox controller add events: " << ret; |
| 548 return false; | 730 return false; |
| 549 } | 731 } |
| 550 DeviceAdded(this, device_added_iter_.get()); | 732 DeviceAdded(this, added_iter->get()); |
| 551 | 733 |
| 552 CFRetain(matching_dict); | 734 CFRetain(matching_dict); |
| 553 io_iterator_t device_removed_iter; | 735 io_iterator_t device_removed_iter; |
| 554 ret = IOServiceAddMatchingNotification(port_, | 736 ret = IOServiceAddMatchingNotification(port_, |
| 555 kIOTerminatedNotification, | 737 kIOTerminatedNotification, |
| 556 matching_dict, | 738 matching_dict, |
| 557 DeviceRemoved, | 739 DeviceRemoved, |
| 558 this, | 740 this, |
| 559 &device_removed_iter); | 741 &device_removed_iter); |
| 560 device_removed_iter_.reset(device_removed_iter); | 742 removed_iter->reset(device_removed_iter); |
| 561 if (ret != kIOReturnSuccess) { | 743 if (ret != kIOReturnSuccess) { |
| 562 LOG(ERROR) << "Error listening for Xbox controller remove events: " << ret; | 744 LOG(ERROR) << "Error listening for Xbox controller remove events: " << ret; |
| 563 return false; | 745 return false; |
| 564 } | 746 } |
| 565 DeviceRemoved(this, device_removed_iter_.get()); | 747 DeviceRemoved(this, removed_iter->get()); |
| 566 return true; | 748 return true; |
| 567 } | 749 } |
| 568 | 750 |
| 569 void XboxDataFetcher::UnregisterFromNotifications() { | 751 void XboxDataFetcher::UnregisterFromNotifications() { |
| 570 if (!listening_) | 752 if (!listening_) |
| 571 return; | 753 return; |
| 572 listening_ = false; | 754 listening_ = false; |
| 573 if (source_) | 755 if (source_) |
| 574 CFRunLoopSourceInvalidate(source_); | 756 CFRunLoopSourceInvalidate(source_); |
| 575 if (port_) | 757 if (port_) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 } | 798 } |
| 617 | 799 |
| 618 void XboxDataFetcher::XboxControllerGotData(XboxController* controller, | 800 void XboxDataFetcher::XboxControllerGotData(XboxController* controller, |
| 619 const XboxController::Data& data) { | 801 const XboxController::Data& data) { |
| 620 delegate_->XboxValueChanged(controller, data); | 802 delegate_->XboxValueChanged(controller, data); |
| 621 } | 803 } |
| 622 | 804 |
| 623 void XboxDataFetcher::XboxControllerError(XboxController* controller) { | 805 void XboxDataFetcher::XboxControllerError(XboxController* controller) { |
| 624 RemoveController(controller); | 806 RemoveController(controller); |
| 625 } | 807 } |
| OLD | NEW |