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 |