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 3 // found in the LICENSE file. 4 5 #ifndef CONTENT_BROWSER_GAMEPAD_XBOX_DATA_FETCHER_MAC_H_ 6 #define CONTENT_BROWSER_GAMEPAD_XBOX_DATA_FETCHER_MAC_H_ 7 8 #include <CoreFoundation/CoreFoundation.h> 9 #include <IOKit/IOKitLib.h> 10 11 #include <set> 12 13 #include "base/basictypes.h" 14 #include "base/mac/scoped_cftyperef.h" 15 #include "base/mac/scoped_ioobject.h" 16 #include "base/mac/scoped_ioplugininterface.h" 17 #include "base/memory/scoped_ptr.h" 18 19 class XboxController { 20 public: 21 enum ControllerType { 22 UNKNOWN_CONTROLLER, 23 XBOX_360_CONTROLLER, 24 XBOX_ONE_CONTROLLER 25 }; 26 27 enum LEDPattern { 28 LED_OFF = 0, 29 30 // 2 quick flashes, then a series of slow flashes (about 1 per second). 31 LED_FLASH = 1, 32 33 // Flash three times then hold the LED on. This is the standard way to tell 34 // the player which player number they are. 35 LED_FLASH_TOP_LEFT = 2, 36 LED_FLASH_TOP_RIGHT = 3, 37 LED_FLASH_BOTTOM_LEFT = 4, 38 LED_FLASH_BOTTOM_RIGHT = 5, 39 40 // Simply turn on the specified LED and turn all other LEDs off. 41 LED_HOLD_TOP_LEFT = 6, 42 LED_HOLD_TOP_RIGHT = 7, 43 LED_HOLD_BOTTOM_LEFT = 8, 44 LED_HOLD_BOTTOM_RIGHT = 9, 45 46 LED_ROTATE = 10, 47 48 LED_FLASH_FAST = 11, 49 LED_FLASH_SLOW = 12, // Flash about once per 3 seconds 50 51 // Flash alternating LEDs for a few seconds, then flash all LEDs about once 52 // per second 53 LED_ALTERNATE_PATTERN = 13, 54 55 // 14 is just another boring flashing speed. 56 57 // Flash all LEDs once then go black. 58 LED_FLASH_ONCE = 15, 59 60 LED_NUM_PATTERNS 61 }; 62 63 struct Data { 64 bool buttons[15]; 65 float triggers[2]; 66 float axes[4]; 67 }; 68 69 class Delegate { 70 public: 71 virtual void XboxControllerGotData(XboxController* controller, 72 const Data& data) = 0; 73 virtual void XboxControllerError(XboxController* controller) = 0; 74 }; 75 76 explicit XboxController(Delegate* delegate_); 77 virtual ~XboxController(); 78 79 bool OpenDevice(io_service_t service); 80 81 void SetLEDPattern(LEDPattern pattern); 82 location_id()83 UInt32 location_id() { return location_id_; } 84 int GetVendorId() const; 85 int GetProductId() const; 86 ControllerType GetControllerType() const; 87 88 private: 89 static void WriteComplete(void* context, IOReturn result, void* arg0); 90 static void GotData(void* context, IOReturn result, void* arg0); 91 92 void ProcessXbox360Packet(size_t length); 93 void ProcessXboxOnePacket(size_t length); 94 void QueueRead(); 95 96 void IOError(); 97 98 void WriteXboxOneInit(); 99 100 // Handle for the USB device. IOUSBDeviceStruct320 is the latest version of 101 // the device API that is supported on Mac OS 10.6. 102 base::mac::ScopedIOPluginInterface<struct IOUSBDeviceStruct320> device_; 103 104 // Handle for the interface on the device which sends button and analog data. 105 // The other interfaces (for the ChatPad and headset) are ignored. 106 base::mac::ScopedIOPluginInterface<struct IOUSBInterfaceStruct300> interface_; 107 108 bool device_is_open_; 109 bool interface_is_open_; 110 111 base::ScopedCFTypeRef<CFRunLoopSourceRef> source_; 112 113 // This will be set to the max packet size reported by the interface, which 114 // is 32 bytes. I would have expected USB to do message framing itself, but 115 // somehow we still sometimes (rarely!) get packets off the interface which 116 // aren't correctly framed. The 360 controller frames its packets with a 2 117 // byte header (type, total length) so we can reframe the packet data 118 // ourselves. 119 uint16 read_buffer_size_; 120 scoped_ptr<uint8[]> read_buffer_; 121 122 // The pattern that the LEDs on the device are currently displaying, or 123 // LED_NUM_PATTERNS if unknown. 124 LEDPattern led_pattern_; 125 126 UInt32 location_id_; 127 128 Delegate* delegate_; 129 130 ControllerType controller_type_; 131 int read_endpoint_; 132 int control_endpoint_; 133 134 DISALLOW_COPY_AND_ASSIGN(XboxController); 135 }; 136 137 class XboxDataFetcher : public XboxController::Delegate { 138 public: 139 class Delegate { 140 public: 141 virtual void XboxDeviceAdd(XboxController* device) = 0; 142 virtual void XboxDeviceRemove(XboxController* device) = 0; 143 virtual void XboxValueChanged(XboxController* device, 144 const XboxController::Data& data) = 0; 145 }; 146 147 explicit XboxDataFetcher(Delegate* delegate); 148 virtual ~XboxDataFetcher(); 149 150 bool RegisterForNotifications(); 151 bool RegisterForDeviceNotifications( 152 int vendor_id, 153 int product_id, 154 base::mac::ScopedIOObject<io_iterator_t>* added_iter, 155 base::mac::ScopedIOObject<io_iterator_t>* removed_iter); 156 void UnregisterFromNotifications(); 157 158 XboxController* ControllerForLocation(UInt32 location_id); 159 160 private: 161 static void DeviceAdded(void* context, io_iterator_t iterator); 162 static void DeviceRemoved(void* context, io_iterator_t iterator); 163 void AddController(XboxController* controller); 164 void RemoveController(XboxController* controller); 165 void RemoveControllerByLocationID(uint32 id); 166 virtual void XboxControllerGotData(XboxController* controller, 167 const XboxController::Data& data) OVERRIDE; 168 virtual void XboxControllerError(XboxController* controller) OVERRIDE; 169 170 Delegate* delegate_; 171 172 std::set<XboxController*> controllers_; 173 174 bool listening_; 175 176 // port_ owns source_, so this doesn't need to be a ScopedCFTypeRef, but we 177 // do need to maintain a reference to it so we can invalidate it. 178 CFRunLoopSourceRef source_; 179 IONotificationPortRef port_; 180 base::mac::ScopedIOObject<io_iterator_t> xbox_360_device_added_iter_; 181 base::mac::ScopedIOObject<io_iterator_t> xbox_360_device_removed_iter_; 182 base::mac::ScopedIOObject<io_iterator_t> xbox_one_device_added_iter_; 183 base::mac::ScopedIOObject<io_iterator_t> xbox_one_device_removed_iter_; 184 185 DISALLOW_COPY_AND_ASSIGN(XboxDataFetcher); 186 }; 187 188 #endif // CONTENT_BROWSER_GAMEPAD_XBOX_DATA_FETCHER_MAC_H_ 189