OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h" | 5 #include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
49 case kDeviceSubTypeDrumKit: return L"DRUM_KIT"; | 49 case kDeviceSubTypeDrumKit: return L"DRUM_KIT"; |
50 case kDeviceSubTypeGuitarBass: return L"GUITAR_BASS"; | 50 case kDeviceSubTypeGuitarBass: return L"GUITAR_BASS"; |
51 case kDeviceSubTypeArcadePad: return L"ARCADE_PAD"; | 51 case kDeviceSubTypeArcadePad: return L"ARCADE_PAD"; |
52 default: return L"<UNKNOWN>"; | 52 default: return L"<UNKNOWN>"; |
53 } | 53 } |
54 } | 54 } |
55 | 55 |
56 } // namespace | 56 } // namespace |
57 | 57 |
58 GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin() | 58 GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin() |
59 : xinput_dll_(base::FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))), | 59 : xinput_available_(false) { |
scottmg
2016/01/18 22:54:51
Initialize xinput_connected_ array here.
| |
60 xinput_available_(GetXInputDllFunctions()) { | |
61 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | |
62 platform_pad_state_[i].status = DISCONNECTED; | |
63 pad_state_[i].mapper = NULL; | |
64 pad_state_[i].axis_mask = 0; | |
65 pad_state_[i].button_mask = 0; | |
66 } | |
67 | |
68 raw_input_fetcher_.reset(new RawInputDataFetcher()); | |
69 raw_input_fetcher_->StartMonitor(); | |
70 } | 60 } |
71 | 61 |
72 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() { | 62 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() { |
73 raw_input_fetcher_->StopMonitor(); | |
74 } | 63 } |
75 | 64 |
76 int GamepadPlatformDataFetcherWin::FirstAvailableGamepadId() const { | 65 void GamepadPlatformDataFetcherWin::OnAddedToProvider() { |
77 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | 66 xinput_dll_.Reset(base::LoadNativeLibrary( |
78 if (platform_pad_state_[i].status == DISCONNECTED) | 67 base::FilePath(FILE_PATH_LITERAL("xinput1_3.dll")), nullptr)); |
79 return i; | 68 xinput_available_ = GetXInputDllFunctions(); |
80 } | |
81 return -1; | |
82 } | |
83 | |
84 bool GamepadPlatformDataFetcherWin::HasXInputGamepad(int index) const { | |
85 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | |
86 if (platform_pad_state_[i].status == XINPUT_CONNECTED && | |
87 platform_pad_state_[i].xinput_index == index) | |
88 return true; | |
89 } | |
90 return false; | |
91 } | |
92 | |
93 bool GamepadPlatformDataFetcherWin::HasRawInputGamepad( | |
94 const HANDLE handle) const { | |
95 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | |
96 if (platform_pad_state_[i].status == RAWINPUT_CONNECTED && | |
97 platform_pad_state_[i].raw_input_handle == handle) | |
98 return true; | |
99 } | |
100 return false; | |
101 } | 69 } |
102 | 70 |
103 void GamepadPlatformDataFetcherWin::EnumerateDevices() { | 71 void GamepadPlatformDataFetcherWin::EnumerateDevices() { |
104 TRACE_EVENT0("GAMEPAD", "EnumerateDevices"); | 72 TRACE_EVENT0("GAMEPAD", "EnumerateDevices"); |
105 | 73 |
106 // Mark all disconnected pads DISCONNECTED. | 74 if (xinput_available_) { |
107 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | 75 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) { |
108 if (!pad_state_[i].data.connected) | 76 // Check to see if the xinput device is connected |
109 platform_pad_state_[i].status = DISCONNECTED; | 77 XINPUT_CAPABILITIES caps; |
110 } | 78 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps); |
79 xinuput_connected_[i] = (res == ERROR_SUCCESS); | |
80 if (!xinuput_connected_[i]) | |
81 continue; | |
111 | 82 |
112 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) { | 83 PadState* state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_XINPUT, i); |
113 if (HasXInputGamepad(i)) | 84 if (!state) |
114 continue; | 85 continue; // No slot available for this gamepad. |
115 int pad_index = FirstAvailableGamepadId(); | |
116 if (pad_index == -1) | |
117 return; // We can't add any more gamepads. | |
118 WebGamepad& pad = pad_state_[pad_index].data; | |
119 if (xinput_available_ && GetXInputPadConnectivity(i, &pad)) { | |
120 platform_pad_state_[pad_index].status = XINPUT_CONNECTED; | |
121 platform_pad_state_[pad_index].xinput_index = i; | |
122 pad_state_[pad_index].mapper = NULL; | |
123 pad_state_[pad_index].axis_mask = 0; | |
124 pad_state_[pad_index].button_mask = 0; | |
125 } | |
126 } | |
127 | 86 |
128 if (raw_input_fetcher_->Available()) { | 87 WebGamepad& pad = state->data; |
129 std::vector<RawGamepadInfo*> raw_inputs = | |
130 raw_input_fetcher_->EnumerateDevices(); | |
131 for (size_t i = 0; i < raw_inputs.size(); ++i) { | |
132 RawGamepadInfo* gamepad = raw_inputs[i]; | |
133 if (gamepad->buttons_length == 0 && gamepad->axes_length == 0) | |
134 continue; | |
135 if (HasRawInputGamepad(gamepad->handle)) | |
136 continue; | |
137 int pad_index = FirstAvailableGamepadId(); | |
138 if (pad_index == -1) | |
139 return; | |
140 WebGamepad& pad = pad_state_[pad_index].data; | |
141 pad.connected = true; | |
142 PadState& state = pad_state_[pad_index]; | |
143 PlatformPadState& platform_state = platform_pad_state_[pad_index]; | |
144 platform_state.status = RAWINPUT_CONNECTED; | |
145 platform_state.raw_input_handle = gamepad->handle; | |
146 | 88 |
147 std::string vendor = base::StringPrintf("%04x", gamepad->vendor_id); | 89 if (state->active_state == GAMEPAD_NEWLY_ACTIVE) { |
148 std::string product = base::StringPrintf("%04x", gamepad->product_id); | 90 // This is the first time we've seen this device, so do some one-time |
149 state.mapper = GetGamepadStandardMappingFunction(vendor, product); | 91 // initialization |
150 state.axis_mask = 0; | 92 pad.connected = true; |
151 state.button_mask = 0; | 93 swprintf(pad.id, |
152 | 94 WebGamepad::idLengthCap, |
153 swprintf(pad.id, WebGamepad::idLengthCap, | 95 L"Xbox 360 Controller (XInput STANDARD %ls)", |
154 L"%ls (%lsVendor: %04x Product: %04x)", | 96 GamepadSubTypeName(caps.SubType)); |
155 gamepad->id, state.mapper ? L"STANDARD GAMEPAD " : L"", | |
156 gamepad->vendor_id, gamepad->product_id); | |
157 | |
158 if (state.mapper) | |
159 swprintf(pad.mapping, WebGamepad::mappingLengthCap, L"standard"); | 97 swprintf(pad.mapping, WebGamepad::mappingLengthCap, L"standard"); |
160 else | 98 } |
161 pad.mapping[0] = 0; | |
162 } | 99 } |
163 } | 100 } |
164 } | 101 } |
165 | 102 |
166 void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads, | 103 void GamepadPlatformDataFetcherWin::GetGamepadData(bool devices_changed_hint) { |
167 bool devices_changed_hint) { | |
168 TRACE_EVENT0("GAMEPAD", "GetGamepadData"); | 104 TRACE_EVENT0("GAMEPAD", "GetGamepadData"); |
169 | 105 |
170 if (!xinput_available_ && | 106 if (!xinput_available_) |
171 !raw_input_fetcher_->Available()) { | |
172 pads->length = 0; | |
173 return; | 107 return; |
174 } | |
175 | 108 |
176 // A note on XInput devices: | 109 // A note on XInput devices: |
177 // If we got notification that system devices have been updated, then | 110 // If we got notification that system devices have been updated, then |
178 // run GetCapabilities to update the connected status and the device | 111 // run GetCapabilities to update the connected status and the device |
179 // identifier. It can be slow to do to both GetCapabilities and | 112 // identifier. It can be slow to do to both GetCapabilities and |
180 // GetState on unconnected devices, so we want to avoid a 2-5ms pause | 113 // GetState on unconnected devices, so we want to avoid a 2-5ms pause |
181 // here by only doing this when the devices are updated (despite | 114 // here by only doing this when the devices are updated (despite |
182 // documentation claiming it's OK to call it any time). | 115 // documentation claiming it's OK to call it any time). |
183 if (devices_changed_hint) | 116 if (devices_changed_hint) |
184 EnumerateDevices(); | 117 EnumerateDevices(); |
185 | 118 |
186 pads->length = 0; | 119 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) { |
187 | 120 if (xinuput_connected_[i]) |
188 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | 121 GetXInputPadData(i); |
189 // We rely on device_changed and GetCapabilities to tell us that | |
190 // something's been connected, but we will mark as disconnected if | |
191 // Get___PadState returns that we've lost the pad. | |
192 if (!pad_state_[i].data.connected) | |
193 continue; | |
194 | |
195 if (platform_pad_state_[i].status == XINPUT_CONNECTED) | |
196 GetXInputPadData(i, &pad_state_[i].data); | |
197 else if (platform_pad_state_[i].status == RAWINPUT_CONNECTED) | |
198 GetRawInputPadData(i, &pad_state_[i].data); | |
199 | |
200 MapAndSanitizeGamepadData(&pad_state_[i], &pads->items[i]); | |
201 | |
202 if (pads->items[i].connected) | |
203 pads->length++; | |
204 } | 122 } |
205 } | 123 } |
206 | 124 |
207 void GamepadPlatformDataFetcherWin::PauseHint(bool pause) { | 125 void GamepadPlatformDataFetcherWin::GetXInputPadData(int i) { |
208 if (pause) | |
209 raw_input_fetcher_->StopMonitor(); | |
210 else | |
211 raw_input_fetcher_->StartMonitor(); | |
212 } | |
213 | 126 |
scottmg
2016/01/18 22:54:51
Extra blank line.
| |
214 bool GamepadPlatformDataFetcherWin::GetXInputPadConnectivity( | 127 PadState* pad_state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_XINPUT, i); |
215 int i, | 128 if (!pad_state) |
216 WebGamepad* pad) const { | 129 return; |
217 DCHECK(pad); | |
218 TRACE_EVENT1("GAMEPAD", "GetXInputPadConnectivity", "id", i); | |
219 XINPUT_CAPABILITIES caps; | |
220 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps); | |
221 if (res == ERROR_DEVICE_NOT_CONNECTED) { | |
222 pad->connected = false; | |
223 return false; | |
224 } else { | |
225 pad->connected = true; | |
226 swprintf(pad->id, | |
227 WebGamepad::idLengthCap, | |
228 L"Xbox 360 Controller (XInput STANDARD %ls)", | |
229 GamepadSubTypeName(caps.SubType)); | |
230 swprintf(pad->mapping, WebGamepad::mappingLengthCap, L"standard"); | |
231 return true; | |
232 } | |
233 } | |
234 | 130 |
235 void GamepadPlatformDataFetcherWin::GetXInputPadData( | 131 WebGamepad& pad = pad_state->data; |
236 int i, | 132 |
237 WebGamepad* pad) { | |
238 XINPUT_STATE state; | 133 XINPUT_STATE state; |
239 memset(&state, 0, sizeof(XINPUT_STATE)); | 134 memset(&state, 0, sizeof(XINPUT_STATE)); |
240 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i); | 135 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i); |
241 DWORD dwResult = xinput_get_state_(platform_pad_state_[i].xinput_index, | 136 DWORD dwResult = xinput_get_state_(i, &state); |
242 &state); | |
243 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i); | 137 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i); |
244 | 138 |
245 if (dwResult == ERROR_SUCCESS) { | 139 if (dwResult == ERROR_SUCCESS) { |
246 pad->timestamp = state.dwPacketNumber; | 140 pad.timestamp = state.dwPacketNumber; |
247 pad->buttonsLength = 0; | 141 pad.buttonsLength = 0; |
248 WORD val = state.Gamepad.wButtons; | 142 WORD val = state.Gamepad.wButtons; |
249 #define ADD(b) pad->buttons[pad->buttonsLength].pressed = (val & (b)) != 0; \ | 143 #define ADD(b) pad.buttons[pad.buttonsLength].pressed = (val & (b)) != 0; \ |
250 pad->buttons[pad->buttonsLength++].value = ((val & (b)) ? 1.f : 0.f); | 144 pad.buttons[pad.buttonsLength++].value = ((val & (b)) ? 1.f : 0.f); |
251 ADD(XINPUT_GAMEPAD_A); | 145 ADD(XINPUT_GAMEPAD_A); |
252 ADD(XINPUT_GAMEPAD_B); | 146 ADD(XINPUT_GAMEPAD_B); |
253 ADD(XINPUT_GAMEPAD_X); | 147 ADD(XINPUT_GAMEPAD_X); |
254 ADD(XINPUT_GAMEPAD_Y); | 148 ADD(XINPUT_GAMEPAD_Y); |
255 ADD(XINPUT_GAMEPAD_LEFT_SHOULDER); | 149 ADD(XINPUT_GAMEPAD_LEFT_SHOULDER); |
256 ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER); | 150 ADD(XINPUT_GAMEPAD_RIGHT_SHOULDER); |
257 | 151 |
258 pad->buttons[pad->buttonsLength].pressed = | 152 pad.buttons[pad.buttonsLength].pressed = |
259 state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; | 153 state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; |
260 pad->buttons[pad->buttonsLength++].value = | 154 pad.buttons[pad.buttonsLength++].value = |
261 state.Gamepad.bLeftTrigger / 255.f; | 155 state.Gamepad.bLeftTrigger / 255.f; |
262 | 156 |
263 pad->buttons[pad->buttonsLength].pressed = | 157 pad.buttons[pad.buttonsLength].pressed = |
264 state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; | 158 state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; |
265 pad->buttons[pad->buttonsLength++].value = | 159 pad.buttons[pad.buttonsLength++].value = |
266 state.Gamepad.bRightTrigger / 255.f; | 160 state.Gamepad.bRightTrigger / 255.f; |
267 | 161 |
268 ADD(XINPUT_GAMEPAD_BACK); | 162 ADD(XINPUT_GAMEPAD_BACK); |
269 ADD(XINPUT_GAMEPAD_START); | 163 ADD(XINPUT_GAMEPAD_START); |
270 ADD(XINPUT_GAMEPAD_LEFT_THUMB); | 164 ADD(XINPUT_GAMEPAD_LEFT_THUMB); |
271 ADD(XINPUT_GAMEPAD_RIGHT_THUMB); | 165 ADD(XINPUT_GAMEPAD_RIGHT_THUMB); |
272 ADD(XINPUT_GAMEPAD_DPAD_UP); | 166 ADD(XINPUT_GAMEPAD_DPAD_UP); |
273 ADD(XINPUT_GAMEPAD_DPAD_DOWN); | 167 ADD(XINPUT_GAMEPAD_DPAD_DOWN); |
274 ADD(XINPUT_GAMEPAD_DPAD_LEFT); | 168 ADD(XINPUT_GAMEPAD_DPAD_LEFT); |
275 ADD(XINPUT_GAMEPAD_DPAD_RIGHT); | 169 ADD(XINPUT_GAMEPAD_DPAD_RIGHT); |
276 #undef ADD | 170 #undef ADD |
277 pad->axesLength = 0; | 171 pad.axesLength = 0; |
278 | 172 |
279 float value = 0.0; | 173 float value = 0.0; |
280 #define ADD(a, factor) value = factor * NormalizeXInputAxis(a); \ | 174 #define ADD(a, factor) value = factor * NormalizeXInputAxis(a); \ |
281 pad->axes[pad->axesLength++] = value; | 175 pad.axes[pad.axesLength++] = value; |
282 | 176 |
283 // XInput are +up/+right, -down/-left, we want -up/-left. | 177 // XInput are +up/+right, -down/-left, we want -up/-left. |
284 ADD(state.Gamepad.sThumbLX, 1); | 178 ADD(state.Gamepad.sThumbLX, 1); |
285 ADD(state.Gamepad.sThumbLY, -1); | 179 ADD(state.Gamepad.sThumbLY, -1); |
286 ADD(state.Gamepad.sThumbRX, 1); | 180 ADD(state.Gamepad.sThumbRX, 1); |
287 ADD(state.Gamepad.sThumbRY, -1); | 181 ADD(state.Gamepad.sThumbRY, -1); |
288 #undef ADD | 182 #undef ADD |
289 } else { | |
290 pad->connected = false; | |
291 } | 183 } |
292 } | 184 } |
293 | 185 |
294 void GamepadPlatformDataFetcherWin::GetRawInputPadData( | |
295 int index, | |
296 WebGamepad* pad) { | |
297 RawGamepadInfo* gamepad = raw_input_fetcher_->GetGamepadInfo( | |
298 platform_pad_state_[index].raw_input_handle); | |
299 if (!gamepad) { | |
300 pad->connected = false; | |
301 return; | |
302 } | |
303 | |
304 pad->timestamp = gamepad->report_id; | |
305 pad->buttonsLength = gamepad->buttons_length; | |
306 pad->axesLength = gamepad->axes_length; | |
307 | |
308 for (unsigned int i = 0; i < pad->buttonsLength; i++) { | |
309 pad->buttons[i].pressed = gamepad->buttons[i]; | |
310 pad->buttons[i].value = gamepad->buttons[i] ? 1.0 : 0.0; | |
311 } | |
312 | |
313 for (unsigned int i = 0; i < pad->axesLength; i++) | |
314 pad->axes[i] = gamepad->axes[i].value; | |
315 } | |
316 | |
317 bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() { | 186 bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() { |
318 xinput_get_capabilities_ = NULL; | 187 xinput_get_capabilities_ = NULL; |
319 xinput_get_state_ = NULL; | 188 xinput_get_state_ = NULL; |
320 xinput_enable_ = reinterpret_cast<XInputEnableFunc>( | 189 xinput_enable_ = reinterpret_cast<XInputEnableFunc>( |
321 xinput_dll_.GetFunctionPointer("XInputEnable")); | 190 xinput_dll_.GetFunctionPointer("XInputEnable")); |
322 if (!xinput_enable_) | 191 if (!xinput_enable_) |
323 return false; | 192 return false; |
324 xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>( | 193 xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>( |
325 xinput_dll_.GetFunctionPointer("XInputGetCapabilities")); | 194 xinput_dll_.GetFunctionPointer("XInputGetCapabilities")); |
326 if (!xinput_get_capabilities_) | 195 if (!xinput_get_capabilities_) |
327 return false; | 196 return false; |
328 xinput_get_state_ = reinterpret_cast<XInputGetStateFunc>( | 197 xinput_get_state_ = reinterpret_cast<XInputGetStateFunc>( |
329 xinput_dll_.GetFunctionPointer("XInputGetState")); | 198 xinput_dll_.GetFunctionPointer("XInputGetState")); |
330 if (!xinput_get_state_) | 199 if (!xinput_get_state_) |
331 return false; | 200 return false; |
332 xinput_enable_(true); | 201 xinput_enable_(true); |
333 return true; | 202 return true; |
334 } | 203 } |
335 | 204 |
336 } // namespace content | 205 } // namespace content |
OLD | NEW |