Home | History | Annotate | Download | only in gamepad
      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 
     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