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