Chromium Code Reviews| 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 |