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) { |
167 return value < kXboxOneTriggerDeadzone ? 0 : | |
168 static_cast<float>(value - kXboxOneTriggerDeadzone) / | |
169 (kXboxOneTriggerMax - kXboxOneTriggerDeadzone); | |
170 } | |
171 | |
172 void NormalizeXbox360ButtonData(const Xbox360ButtonData& data, | |
126 XboxController::Data* normalized_data) { | 173 XboxController::Data* normalized_data) { |
scottmg
2014/02/24 17:37:22
nit; indent
| |
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) { | |
scottmg
2014/02/24 17:37:22
nit; indent
| |
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) return; |
408 DCHECK(length <= read_buffer_size_); | 518 DCHECK(length <= read_buffer_size_); |
409 if (length > read_buffer_size_) { | 519 if (length > read_buffer_size_) { |
410 IOError(); | 520 IOError(); |
411 return; | 521 return; |
412 } | 522 } |
413 uint8* buffer = read_buffer_.get(); | 523 uint8* buffer = read_buffer_.get(); |
414 | 524 |
415 if (buffer[1] != length) | 525 if (buffer[1] != length) |
416 // Length in packet doesn't match length reported by USB. | 526 // Length in packet doesn't match length reported by USB. |
417 return; | 527 return; |
418 | 528 |
419 uint8 type = buffer[0]; | 529 uint8 type = buffer[0]; |
420 buffer += 2; | 530 buffer += 2; |
421 length -= 2; | 531 length -= 2; |
422 switch (type) { | 532 switch (type) { |
423 case STATUS_MESSAGE_BUTTONS: { | 533 case STATUS_MESSAGE_BUTTONS: { |
424 if (length != sizeof(ButtonData)) | 534 if (length != sizeof(Xbox360ButtonData)) |
425 return; | 535 return; |
426 ButtonData* data = reinterpret_cast<ButtonData*>(buffer); | 536 Xbox360ButtonData* data = reinterpret_cast<Xbox360ButtonData*>(buffer); |
427 Data normalized_data; | 537 Data normalized_data; |
428 NormalizeButtonData(*data, &normalized_data); | 538 NormalizeXbox360ButtonData(*data, &normalized_data); |
429 delegate_->XboxControllerGotData(this, normalized_data); | 539 delegate_->XboxControllerGotData(this, normalized_data); |
430 break; | 540 break; |
431 } | 541 } |
432 case STATUS_MESSAGE_LED: | 542 case STATUS_MESSAGE_LED: |
433 if (length != 3) | 543 if (length != 3) |
434 return; | 544 return; |
435 // The controller sends one of these messages every time the LED pattern | 545 // The controller sends one of these messages every time the LED pattern |
436 // is set, as well as once when it is plugged in. | 546 // is set, as well as once when it is plugged in. |
437 if (led_pattern_ == LED_NUM_PATTERNS && buffer[0] < LED_NUM_PATTERNS) | 547 if (led_pattern_ == LED_NUM_PATTERNS && buffer[0] < LED_NUM_PATTERNS) |
438 led_pattern_ = static_cast<LEDPattern>(buffer[0]); | 548 led_pattern_ = static_cast<LEDPattern>(buffer[0]); |
439 break; | 549 break; |
440 default: | 550 default: |
441 // Unknown packet: ignore! | 551 // Unknown packet: ignore! |
442 break; | 552 break; |
443 } | 553 } |
444 } | 554 } |
445 | 555 |
556 void XboxController::ProcessXboxOnePacket(size_t length) { | |
557 if (length < 2) return; | |
scottmg
2014/02/24 17:37:22
nit; return on next line
| |
558 DCHECK(length <= read_buffer_size_); | |
559 if (length > read_buffer_size_) { | |
560 IOError(); | |
561 return; | |
562 } | |
563 uint8* buffer = read_buffer_.get(); | |
564 | |
565 uint8 type = buffer[0]; | |
566 buffer += 4; | |
567 length -= 4; | |
568 switch (type) { | |
569 case XBOX_ONE_STATUS_MESSAGE_BUTTONS: { | |
570 if (length != sizeof(XboxOneButtonData)) | |
571 return; | |
scottmg
2014/02/24 17:37:22
does this return ever get hit? does it send partia
| |
572 XboxOneButtonData* data = reinterpret_cast<XboxOneButtonData*>(buffer); | |
573 Data normalized_data; | |
574 NormalizeXboxOneButtonData(*data, &normalized_data); | |
575 delegate_->XboxControllerGotData(this, normalized_data); | |
576 break; | |
577 } | |
578 default: | |
579 // Unknown packet: ignore! | |
580 break; | |
581 } | |
582 } | |
583 | |
446 void XboxController::QueueRead() { | 584 void XboxController::QueueRead() { |
447 kern_return_t kr = (*interface_)->ReadPipeAsync(interface_, | 585 kern_return_t kr = (*interface_)->ReadPipeAsync(interface_, |
448 kReadEndpoint, | 586 read_endpoint_, |
449 read_buffer_.get(), | 587 read_buffer_.get(), |
450 read_buffer_size_, | 588 read_buffer_size_, |
451 GotData, | 589 GotData, |
452 this); | 590 this); |
453 if (kr != KERN_SUCCESS) | 591 if (kr != KERN_SUCCESS) |
454 IOError(); | 592 IOError(); |
455 } | 593 } |
456 | 594 |
457 void XboxController::IOError() { | 595 void XboxController::IOError() { |
458 delegate_->XboxControllerError(this); | 596 delegate_->XboxControllerError(this); |
459 } | 597 } |
460 | 598 |
599 void XboxController::WriteXboxOneInit() { | |
600 const UInt8 length = 2; | |
601 | |
602 // This buffer will be released in WriteComplete when WritePipeAsync | |
603 // finishes. | |
604 UInt8* buffer = new UInt8[length]; | |
605 buffer[0] = 0x05; | |
606 buffer[1] = 0x20; | |
607 kern_return_t kr = (*interface_)->WritePipeAsync(interface_, | |
608 control_endpoint_, | |
609 buffer, | |
610 (UInt32)length, | |
611 WriteComplete, | |
612 buffer); | |
613 if (kr != KERN_SUCCESS) { | |
614 delete[] buffer; | |
615 IOError(); | |
616 return; | |
617 } | |
618 } | |
619 | |
461 //----------------------------------------------------------------------------- | 620 //----------------------------------------------------------------------------- |
462 | 621 |
463 XboxDataFetcher::XboxDataFetcher(Delegate* delegate) | 622 XboxDataFetcher::XboxDataFetcher(Delegate* delegate) |
464 : delegate_(delegate), | 623 : delegate_(delegate), |
465 listening_(false), | 624 listening_(false), |
466 source_(NULL), | 625 source_(NULL), |
467 port_(NULL) { | 626 port_(NULL) { |
468 } | 627 } |
469 | 628 |
470 XboxDataFetcher::~XboxDataFetcher() { | 629 XboxDataFetcher::~XboxDataFetcher() { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
503 kNilOptions))); | 662 kNilOptions))); |
504 UInt32 location_id = 0; | 663 UInt32 location_id = 0; |
505 CFNumberGetValue(number, kCFNumberSInt32Type, &location_id); | 664 CFNumberGetValue(number, kCFNumberSInt32Type, &location_id); |
506 fetcher->RemoveControllerByLocationID(location_id); | 665 fetcher->RemoveControllerByLocationID(location_id); |
507 } | 666 } |
508 } | 667 } |
509 | 668 |
510 bool XboxDataFetcher::RegisterForNotifications() { | 669 bool XboxDataFetcher::RegisterForNotifications() { |
511 if (listening_) | 670 if (listening_) |
512 return true; | 671 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); | 672 port_ = IONotificationPortCreate(kIOMasterPortDefault); |
524 if (!port_) | 673 if (!port_) |
525 return false; | 674 return false; |
526 source_ = IONotificationPortGetRunLoopSource(port_); | 675 source_ = IONotificationPortGetRunLoopSource(port_); |
527 if (!source_) | 676 if (!source_) |
528 return false; | 677 return false; |
529 CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopDefaultMode); | 678 CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopDefaultMode); |
530 | 679 |
531 listening_ = true; | 680 listening_ = true; |
532 | 681 |
682 if (!RegisterForDeviceNotifications( | |
683 kVendorMicrosoft, kProductXboxOneController, | |
684 &xbox_one_device_added_iter_, | |
685 &xbox_one_device_removed_iter_)) | |
686 return false; | |
687 | |
688 if (!RegisterForDeviceNotifications( | |
689 kVendorMicrosoft, kProductXbox360Controller, | |
690 &xbox_360_device_added_iter_, | |
691 &xbox_360_device_removed_iter_)) | |
692 return false; | |
693 | |
694 return true; | |
695 } | |
696 | |
697 bool XboxDataFetcher::RegisterForDeviceNotifications( | |
698 int vendor_id, | |
699 int product_id, | |
700 base::mac::ScopedIOObject<io_iterator_t>* added_iter, | |
701 base::mac::ScopedIOObject<io_iterator_t>* removed_iter) { | |
702 base::ScopedCFTypeRef<CFNumberRef> vendor_cf(CFNumberCreate( | |
703 kCFAllocatorDefault, kCFNumberSInt32Type, &vendor_id)); | |
704 base::ScopedCFTypeRef<CFNumberRef> product_cf(CFNumberCreate( | |
705 kCFAllocatorDefault, kCFNumberSInt32Type, &product_id)); | |
706 base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict( | |
707 IOServiceMatching(kIOUSBDeviceClassName)); | |
708 if (!matching_dict) | |
709 return false; | |
710 CFDictionarySetValue(matching_dict, CFSTR(kUSBVendorID), vendor_cf); | |
711 CFDictionarySetValue(matching_dict, CFSTR(kUSBProductID), product_cf); | |
712 | |
533 // IOServiceAddMatchingNotification() releases the dictionary when it's done. | 713 // IOServiceAddMatchingNotification() releases the dictionary when it's done. |
534 // Retain it before each call to IOServiceAddMatchingNotification to keep | 714 // Retain it before each call to IOServiceAddMatchingNotification to keep |
535 // things balanced. | 715 // things balanced. |
536 CFRetain(matching_dict); | 716 CFRetain(matching_dict); |
537 io_iterator_t device_added_iter; | 717 io_iterator_t device_added_iter; |
538 IOReturn ret; | 718 IOReturn ret; |
539 ret = IOServiceAddMatchingNotification(port_, | 719 ret = IOServiceAddMatchingNotification(port_, |
540 kIOFirstMatchNotification, | 720 kIOFirstMatchNotification, |
541 matching_dict, | 721 matching_dict, |
542 DeviceAdded, | 722 DeviceAdded, |
543 this, | 723 this, |
544 &device_added_iter); | 724 &device_added_iter); |
545 device_added_iter_.reset(device_added_iter); | 725 added_iter->reset(device_added_iter); |
546 if (ret != kIOReturnSuccess) { | 726 if (ret != kIOReturnSuccess) { |
547 LOG(ERROR) << "Error listening for Xbox controller add events: " << ret; | 727 LOG(ERROR) << "Error listening for Xbox controller add events: " << ret; |
548 return false; | 728 return false; |
549 } | 729 } |
550 DeviceAdded(this, device_added_iter_.get()); | 730 DeviceAdded(this, added_iter->get()); |
551 | 731 |
552 CFRetain(matching_dict); | 732 CFRetain(matching_dict); |
553 io_iterator_t device_removed_iter; | 733 io_iterator_t device_removed_iter; |
554 ret = IOServiceAddMatchingNotification(port_, | 734 ret = IOServiceAddMatchingNotification(port_, |
555 kIOTerminatedNotification, | 735 kIOTerminatedNotification, |
556 matching_dict, | 736 matching_dict, |
557 DeviceRemoved, | 737 DeviceRemoved, |
558 this, | 738 this, |
559 &device_removed_iter); | 739 &device_removed_iter); |
560 device_removed_iter_.reset(device_removed_iter); | 740 removed_iter->reset(device_removed_iter); |
561 if (ret != kIOReturnSuccess) { | 741 if (ret != kIOReturnSuccess) { |
562 LOG(ERROR) << "Error listening for Xbox controller remove events: " << ret; | 742 LOG(ERROR) << "Error listening for Xbox controller remove events: " << ret; |
563 return false; | 743 return false; |
564 } | 744 } |
565 DeviceRemoved(this, device_removed_iter_.get()); | 745 DeviceRemoved(this, removed_iter->get()); |
566 return true; | 746 return true; |
567 } | 747 } |
568 | 748 |
569 void XboxDataFetcher::UnregisterFromNotifications() { | 749 void XboxDataFetcher::UnregisterFromNotifications() { |
570 if (!listening_) | 750 if (!listening_) |
571 return; | 751 return; |
572 listening_ = false; | 752 listening_ = false; |
573 if (source_) | 753 if (source_) |
574 CFRunLoopSourceInvalidate(source_); | 754 CFRunLoopSourceInvalidate(source_); |
575 if (port_) | 755 if (port_) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
616 } | 796 } |
617 | 797 |
618 void XboxDataFetcher::XboxControllerGotData(XboxController* controller, | 798 void XboxDataFetcher::XboxControllerGotData(XboxController* controller, |
619 const XboxController::Data& data) { | 799 const XboxController::Data& data) { |
620 delegate_->XboxValueChanged(controller, data); | 800 delegate_->XboxValueChanged(controller, data); |
621 } | 801 } |
622 | 802 |
623 void XboxDataFetcher::XboxControllerError(XboxController* controller) { | 803 void XboxDataFetcher::XboxControllerError(XboxController* controller) { |
624 RemoveController(controller); | 804 RemoveController(controller); |
625 } | 805 } |
OLD | NEW |