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