• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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