| 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 "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
| 8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
| 9 #include "base/win/windows_version.h" | 9 #include "base/win/windows_version.h" |
| 10 #include "content/common/gamepad_hardware_buffer.h" | 10 #include "content/common/gamepad_hardware_buffer.h" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 } | 50 } |
| 51 } | 51 } |
| 52 | 52 |
| 53 } // namespace | 53 } // namespace |
| 54 | 54 |
| 55 GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin() | 55 GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin() |
| 56 : xinput_dll_(base::FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))), | 56 : xinput_dll_(base::FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))), |
| 57 xinput_available_(GetXInputDllFunctions()) { | 57 xinput_available_(GetXInputDllFunctions()) { |
| 58 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) | 58 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) |
| 59 pad_state_[i].status = DISCONNECTED; | 59 pad_state_[i].status = DISCONNECTED; |
| 60 |
| 61 raw_input_fetcher_.reset(new RawInputDataFetcher()); |
| 62 raw_input_fetcher_->StartMonitor(); |
| 60 } | 63 } |
| 61 | 64 |
| 62 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() { | 65 GamepadPlatformDataFetcherWin::~GamepadPlatformDataFetcherWin() { |
| 63 | 66 raw_input_fetcher_->StopMonitor(); |
| 64 } | 67 } |
| 65 | 68 |
| 66 int GamepadPlatformDataFetcherWin::FirstAvailableGamepadId() const { | 69 int GamepadPlatformDataFetcherWin::FirstAvailableGamepadId() const { |
| 67 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | 70 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { |
| 68 if (pad_state_[i].status == DISCONNECTED) | 71 if (pad_state_[i].status == DISCONNECTED) |
| 69 return i; | 72 return i; |
| 70 } | 73 } |
| 71 return -1; | 74 return -1; |
| 72 } | 75 } |
| 73 | 76 |
| 74 bool GamepadPlatformDataFetcherWin::HasXInputGamepad(int index) const { | 77 bool GamepadPlatformDataFetcherWin::HasXInputGamepad(int index) const { |
| 75 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | 78 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { |
| 76 if (pad_state_[i].status == XINPUT_CONNECTED && | 79 if (pad_state_[i].status == XINPUT_CONNECTED && |
| 77 pad_state_[i].xinput_index == index) | 80 pad_state_[i].xinput_index == index) |
| 78 return true; | 81 return true; |
| 79 } | 82 } |
| 80 return false; | 83 return false; |
| 81 } | 84 } |
| 82 | 85 |
| 86 bool GamepadPlatformDataFetcherWin::HasRawInputGamepad( |
| 87 const HANDLE handle) const { |
| 88 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { |
| 89 if (pad_state_[i].status == RAWINPUT_CONNECTED && |
| 90 pad_state_[i].raw_input_handle == handle) |
| 91 return true; |
| 92 } |
| 93 return false; |
| 94 } |
| 95 |
| 83 void GamepadPlatformDataFetcherWin::EnumerateDevices( | 96 void GamepadPlatformDataFetcherWin::EnumerateDevices( |
| 84 WebGamepads* pads) { | 97 WebGamepads* pads) { |
| 85 TRACE_EVENT0("GAMEPAD", "EnumerateDevices"); | 98 TRACE_EVENT0("GAMEPAD", "EnumerateDevices"); |
| 86 | 99 |
| 87 // Mark all disconnected pads DISCONNECTED. | 100 // Mark all disconnected pads DISCONNECTED. |
| 88 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | 101 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { |
| 89 if (!pads->items[i].connected) | 102 if (!pads->items[i].connected) |
| 90 pad_state_[i].status = DISCONNECTED; | 103 pad_state_[i].status = DISCONNECTED; |
| 91 } | 104 } |
| 92 | 105 |
| 93 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) { | 106 for (size_t i = 0; i < XUSER_MAX_COUNT; ++i) { |
| 94 if (HasXInputGamepad(i)) | 107 if (HasXInputGamepad(i)) |
| 95 continue; | 108 continue; |
| 96 int pad_index = FirstAvailableGamepadId(); | 109 int pad_index = FirstAvailableGamepadId(); |
| 97 if (pad_index == -1) | 110 if (pad_index == -1) |
| 98 return; // We can't add any more gamepads. | 111 return; // We can't add any more gamepads. |
| 99 WebGamepad& pad = pads->items[pad_index]; | 112 WebGamepad& pad = pads->items[pad_index]; |
| 100 if (xinput_available_ && GetXInputPadConnectivity(i, &pad)) { | 113 if (xinput_available_ && GetXInputPadConnectivity(i, &pad)) { |
| 101 pad_state_[pad_index].status = XINPUT_CONNECTED; | 114 pad_state_[pad_index].status = XINPUT_CONNECTED; |
| 102 pad_state_[pad_index].xinput_index = i; | 115 pad_state_[pad_index].xinput_index = i; |
| 116 pad_state_[pad_index].mapper = NULL; |
| 117 pads->length++; |
| 118 } |
| 119 } |
| 120 |
| 121 if (raw_input_fetcher_->Available()) { |
| 122 std::vector<RawGamepadInfo*> raw_inputs = |
| 123 raw_input_fetcher_->EnumerateDevices(); |
| 124 for (size_t i = 0; i < raw_inputs.size(); ++i) { |
| 125 RawGamepadInfo* gamepad = raw_inputs[i]; |
| 126 if (HasRawInputGamepad(gamepad->handle)) |
| 127 continue; |
| 128 int pad_index = FirstAvailableGamepadId(); |
| 129 if (pad_index == -1) |
| 130 return; |
| 131 WebGamepad& pad = pads->items[pad_index]; |
| 132 pad.connected = true; |
| 133 PadState& state = pad_state_[pad_index]; |
| 134 state.status = RAWINPUT_CONNECTED; |
| 135 state.raw_input_handle = gamepad->handle; |
| 136 |
| 137 std::string vendor = base::StringPrintf("%04x", gamepad->vendor_id); |
| 138 std::string product = base::StringPrintf("%04x", gamepad->product_id); |
| 139 state.mapper = GetGamepadStandardMappingFunction(vendor, product); |
| 140 |
| 141 swprintf(pad.id, WebGamepad::idLengthCap, |
| 142 L"%ls (%lsVendor: %04x Product: %04x)", |
| 143 gamepad->id, state.mapper ? L"STANDARD GAMEPAD " : L"", |
| 144 gamepad->vendor_id, gamepad->product_id); |
| 145 pads->length++; |
| 103 } | 146 } |
| 104 } | 147 } |
| 105 } | 148 } |
| 106 | 149 |
| 107 | 150 |
| 108 void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads, | 151 void GamepadPlatformDataFetcherWin::GetGamepadData(WebGamepads* pads, |
| 109 bool devices_changed_hint) { | 152 bool devices_changed_hint) { |
| 110 TRACE_EVENT0("GAMEPAD", "GetGamepadData"); | 153 TRACE_EVENT0("GAMEPAD", "GetGamepadData"); |
| 111 | 154 |
| 112 if (!xinput_available_) { | 155 if (!xinput_available_ && |
| 156 !raw_input_fetcher_->Available()) { |
| 113 pads->length = 0; | 157 pads->length = 0; |
| 114 return; | 158 return; |
| 115 } | 159 } |
| 116 | 160 |
| 117 // A note on XInput devices: | 161 // A note on XInput devices: |
| 118 // If we got notification that system devices have been updated, then | 162 // If we got notification that system devices have been updated, then |
| 119 // run GetCapabilities to update the connected status and the device | 163 // run GetCapabilities to update the connected status and the device |
| 120 // identifier. It can be slow to do to both GetCapabilities and | 164 // identifier. It can be slow to do to both GetCapabilities and |
| 121 // GetState on unconnected devices, so we want to avoid a 2-5ms pause | 165 // GetState on unconnected devices, so we want to avoid a 2-5ms pause |
| 122 // here by only doing this when the devices are updated (despite | 166 // here by only doing this when the devices are updated (despite |
| 123 // documentation claiming it's OK to call it any time). | 167 // documentation claiming it's OK to call it any time). |
| 124 if (devices_changed_hint) | 168 if (devices_changed_hint) |
| 125 EnumerateDevices(pads); | 169 EnumerateDevices(pads); |
| 126 | 170 |
| 127 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { | 171 for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { |
| 128 WebGamepad& pad = pads->items[i]; | 172 // We rely on device_changed and GetCapabilities to tell us that |
| 173 // something's been connected, but we will mark as disconnected if |
| 174 // Get___PadState returns that we've lost the pad. |
| 175 if (!pads->items[i].connected) |
| 176 continue; |
| 177 |
| 129 if (pad_state_[i].status == XINPUT_CONNECTED) | 178 if (pad_state_[i].status == XINPUT_CONNECTED) |
| 130 GetXInputPadData(i, &pad); | 179 GetXInputPadData(i, &pads->items[i]); |
| 180 else if (pad_state_[i].status == RAWINPUT_CONNECTED) |
| 181 GetRawInputPadData(i, &pads->items[i]); |
| 131 } | 182 } |
| 132 pads->length = WebGamepads::itemsLengthCap; | 183 } |
| 184 |
| 185 void GamepadPlatformDataFetcherWin::PauseHint(bool pause) { |
| 186 if (pause) |
| 187 raw_input_fetcher_->StopMonitor(); |
| 188 else |
| 189 raw_input_fetcher_->StartMonitor(); |
| 133 } | 190 } |
| 134 | 191 |
| 135 bool GamepadPlatformDataFetcherWin::GetXInputPadConnectivity( | 192 bool GamepadPlatformDataFetcherWin::GetXInputPadConnectivity( |
| 136 int i, | 193 int i, |
| 137 WebGamepad* pad) const { | 194 WebGamepad* pad) const { |
| 138 DCHECK(pad); | 195 DCHECK(pad); |
| 139 TRACE_EVENT1("GAMEPAD", "GetXInputPadConnectivity", "id", i); | 196 TRACE_EVENT1("GAMEPAD", "GetXInputPadConnectivity", "id", i); |
| 140 XINPUT_CAPABILITIES caps; | 197 XINPUT_CAPABILITIES caps; |
| 141 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps); | 198 DWORD res = xinput_get_capabilities_(i, XINPUT_FLAG_GAMEPAD, &caps); |
| 142 if (res == ERROR_DEVICE_NOT_CONNECTED) { | 199 if (res == ERROR_DEVICE_NOT_CONNECTED) { |
| 143 pad->connected = false; | 200 pad->connected = false; |
| 144 return false; | 201 return false; |
| 145 } else { | 202 } else { |
| 146 pad->connected = true; | 203 pad->connected = true; |
| 147 swprintf(pad->id, | 204 swprintf(pad->id, |
| 148 WebGamepad::idLengthCap, | 205 WebGamepad::idLengthCap, |
| 149 L"Xbox 360 Controller (XInput STANDARD %ls)", | 206 L"Xbox 360 Controller (XInput STANDARD %ls)", |
| 150 GamepadSubTypeName(caps.SubType)); | 207 GamepadSubTypeName(caps.SubType)); |
| 151 return true; | 208 return true; |
| 152 } | 209 } |
| 153 } | 210 } |
| 154 | 211 |
| 155 void GamepadPlatformDataFetcherWin::GetXInputPadData( | 212 void GamepadPlatformDataFetcherWin::GetXInputPadData( |
| 156 int i, | 213 int i, |
| 157 WebGamepad* pad) { | 214 WebGamepad* pad) { |
| 158 // We rely on device_changed and GetCapabilities to tell us that | |
| 159 // something's been connected, but we will mark as disconnected if | |
| 160 // GetState returns that we've lost the pad. | |
| 161 if (!pad->connected) | |
| 162 return; | |
| 163 | |
| 164 XINPUT_STATE state; | 215 XINPUT_STATE state; |
| 165 memset(&state, 0, sizeof(XINPUT_STATE)); | 216 memset(&state, 0, sizeof(XINPUT_STATE)); |
| 166 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i); | 217 TRACE_EVENT_BEGIN1("GAMEPAD", "XInputGetState", "id", i); |
| 167 DWORD dwResult = xinput_get_state_(pad_state_[i].xinput_index, &state); | 218 DWORD dwResult = xinput_get_state_(pad_state_[i].xinput_index, &state); |
| 168 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i); | 219 TRACE_EVENT_END1("GAMEPAD", "XInputGetState", "id", i); |
| 169 | 220 |
| 170 if (dwResult == ERROR_SUCCESS) { | 221 if (dwResult == ERROR_SUCCESS) { |
| 171 pad->timestamp = state.dwPacketNumber; | 222 pad->timestamp = state.dwPacketNumber; |
| 172 pad->buttonsLength = 0; | 223 pad->buttonsLength = 0; |
| 173 #define ADD(b) pad->buttons[pad->buttonsLength++] = \ | 224 #define ADD(b) pad->buttons[pad->buttonsLength++] = \ |
| (...skipping 19 matching lines...) Expand all Loading... |
| 193 // XInput are +up/+right, -down/-left, we want -up/-left. | 244 // XInput are +up/+right, -down/-left, we want -up/-left. |
| 194 pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbLX); | 245 pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbLX); |
| 195 pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbLY); | 246 pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbLY); |
| 196 pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbRX); | 247 pad->axes[pad->axesLength++] = NormalizeXInputAxis(state.Gamepad.sThumbRX); |
| 197 pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbRY); | 248 pad->axes[pad->axesLength++] = -NormalizeXInputAxis(state.Gamepad.sThumbRY); |
| 198 } else { | 249 } else { |
| 199 pad->connected = false; | 250 pad->connected = false; |
| 200 } | 251 } |
| 201 } | 252 } |
| 202 | 253 |
| 254 void GamepadPlatformDataFetcherWin::GetRawInputPadData( |
| 255 int index, |
| 256 WebGamepad* pad) { |
| 257 RawGamepadInfo* gamepad = raw_input_fetcher_->GetGamepadInfo( |
| 258 pad_state_[index].raw_input_handle); |
| 259 if (!gamepad) { |
| 260 pad->connected = false; |
| 261 return; |
| 262 } |
| 263 |
| 264 WebGamepad raw_pad = *pad; |
| 265 |
| 266 raw_pad.timestamp = gamepad->report_id; |
| 267 raw_pad.buttonsLength = gamepad->buttons_length; |
| 268 raw_pad.axesLength = gamepad->axes_length; |
| 269 |
| 270 for (unsigned int i = 0; i < raw_pad.buttonsLength; i++) |
| 271 raw_pad.buttons[i] = gamepad->buttons[i] ? 1.0 : 0.0; |
| 272 |
| 273 for (unsigned int i = 0; i < raw_pad.axesLength; i++) |
| 274 raw_pad.axes[i] = gamepad->axes[i].value; |
| 275 |
| 276 // Copy to the current state to the output buffer, using the mapping |
| 277 // function, if there is one available. |
| 278 if (pad_state_[index].mapper) |
| 279 pad_state_[index].mapper(raw_pad, pad); |
| 280 else |
| 281 *pad = raw_pad; |
| 282 } |
| 283 |
| 203 bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() { | 284 bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() { |
| 204 xinput_get_capabilities_ = NULL; | 285 xinput_get_capabilities_ = NULL; |
| 205 xinput_get_state_ = NULL; | 286 xinput_get_state_ = NULL; |
| 206 xinput_enable_ = reinterpret_cast<XInputEnableFunc>( | 287 xinput_enable_ = reinterpret_cast<XInputEnableFunc>( |
| 207 xinput_dll_.GetFunctionPointer("XInputEnable")); | 288 xinput_dll_.GetFunctionPointer("XInputEnable")); |
| 208 if (!xinput_enable_) | 289 if (!xinput_enable_) |
| 209 return false; | 290 return false; |
| 210 xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>( | 291 xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>( |
| 211 xinput_dll_.GetFunctionPointer("XInputGetCapabilities")); | 292 xinput_dll_.GetFunctionPointer("XInputGetCapabilities")); |
| 212 if (!xinput_get_capabilities_) | 293 if (!xinput_get_capabilities_) |
| 213 return false; | 294 return false; |
| 214 xinput_get_state_ = reinterpret_cast<XInputGetStateFunc>( | 295 xinput_get_state_ = reinterpret_cast<XInputGetStateFunc>( |
| 215 xinput_dll_.GetFunctionPointer("XInputGetState")); | 296 xinput_dll_.GetFunctionPointer("XInputGetState")); |
| 216 if (!xinput_get_state_) | 297 if (!xinput_get_state_) |
| 217 return false; | 298 return false; |
| 218 xinput_enable_(true); | 299 xinput_enable_(true); |
| 219 return true; | 300 return true; |
| 220 } | 301 } |
| 221 | 302 |
| 222 } // namespace content | 303 } // namespace content |
| OLD | NEW |