raw_input_data_fetcher_win.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/gamepad/raw_input_data_fetcher_win.h"
  5. #include <stddef.h>
  6. #include <memory>
  7. #include "base/bind.h"
  8. #include "base/strings/sys_string_conversions.h"
  9. #include "base/trace_event/trace_event.h"
  10. #include "device/gamepad/gamepad_standard_mappings.h"
  11. #include "device/gamepad/gamepad_uma.h"
  12. #include "device/gamepad/nintendo_controller.h"
  13. namespace device {
  14. namespace {
  15. const uint16_t DeviceUsages[] = {
  16. RawInputGamepadDeviceWin::kGenericDesktopJoystick,
  17. RawInputGamepadDeviceWin::kGenericDesktopGamePad,
  18. RawInputGamepadDeviceWin::kGenericDesktopMultiAxisController,
  19. };
  20. } // namespace
  21. RawInputDataFetcher::RawInputDataFetcher() = default;
  22. RawInputDataFetcher::~RawInputDataFetcher() {
  23. StopMonitor();
  24. ClearControllers();
  25. DCHECK(!window_);
  26. DCHECK(!events_monitored_);
  27. }
  28. GamepadSource RawInputDataFetcher::source() {
  29. return Factory::static_source();
  30. }
  31. RAWINPUTDEVICE* RawInputDataFetcher::GetRawInputDevices(DWORD flags) {
  32. size_t usage_count = std::size(DeviceUsages);
  33. std::unique_ptr<RAWINPUTDEVICE[]> devices(new RAWINPUTDEVICE[usage_count]);
  34. for (size_t i = 0; i < usage_count; ++i) {
  35. devices[i].dwFlags = flags;
  36. devices[i].usUsagePage = 1;
  37. devices[i].usUsage = DeviceUsages[i];
  38. devices[i].hwndTarget = (flags & RIDEV_REMOVE) ? 0 : window_->hwnd();
  39. }
  40. return devices.release();
  41. }
  42. void RawInputDataFetcher::PauseHint(bool pause) {
  43. if (pause)
  44. StopMonitor();
  45. else
  46. StartMonitor();
  47. }
  48. void RawInputDataFetcher::StartMonitor() {
  49. if (events_monitored_)
  50. return;
  51. if (!window_) {
  52. window_ = std::make_unique<base::win::MessageWindow>();
  53. if (!window_->Create(base::BindRepeating(
  54. &RawInputDataFetcher::HandleMessage, base::Unretained(this)))) {
  55. PLOG(ERROR) << "Failed to create the raw input window";
  56. window_.reset();
  57. return;
  58. }
  59. }
  60. // Register to receive raw HID input.
  61. std::unique_ptr<RAWINPUTDEVICE[]> devices(
  62. GetRawInputDevices(RIDEV_INPUTSINK));
  63. if (!::RegisterRawInputDevices(devices.get(), std::size(DeviceUsages),
  64. sizeof(RAWINPUTDEVICE))) {
  65. PLOG(ERROR) << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
  66. window_.reset();
  67. return;
  68. }
  69. events_monitored_ = true;
  70. }
  71. void RawInputDataFetcher::StopMonitor() {
  72. if (!events_monitored_)
  73. return;
  74. // Stop receiving raw input.
  75. DCHECK(window_);
  76. std::unique_ptr<RAWINPUTDEVICE[]> devices(GetRawInputDevices(RIDEV_REMOVE));
  77. if (!::RegisterRawInputDevices(devices.get(), std::size(DeviceUsages),
  78. sizeof(RAWINPUTDEVICE))) {
  79. PLOG(INFO) << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
  80. }
  81. events_monitored_ = false;
  82. window_.reset();
  83. }
  84. bool RawInputDataFetcher::DisconnectUnrecognizedGamepad(int source_id) {
  85. for (auto it = controllers_.begin(); it != controllers_.end(); ++it) {
  86. if (it->second->GetSourceId() == source_id) {
  87. it->second->Shutdown();
  88. controllers_.erase(it);
  89. return true;
  90. }
  91. }
  92. return false;
  93. }
  94. void RawInputDataFetcher::ClearControllers() {
  95. for (const auto& entry : controllers_)
  96. entry.second->Shutdown();
  97. controllers_.clear();
  98. }
  99. void RawInputDataFetcher::GetGamepadData(bool devices_changed_hint) {
  100. if (devices_changed_hint)
  101. EnumerateDevices();
  102. for (const auto& entry : controllers_) {
  103. const RawInputGamepadDeviceWin* device = entry.second.get();
  104. PadState* state = GetPadState(device->GetSourceId());
  105. if (!state)
  106. continue;
  107. device->ReadPadState(&state->data);
  108. }
  109. }
  110. void RawInputDataFetcher::EnumerateDevices() {
  111. UINT count = 0;
  112. UINT result =
  113. ::GetRawInputDeviceList(nullptr, &count, sizeof(RAWINPUTDEVICELIST));
  114. if (result == static_cast<UINT>(-1)) {
  115. PLOG(ERROR) << "GetRawInputDeviceList() failed";
  116. return;
  117. }
  118. DCHECK_EQ(0u, result);
  119. std::unique_ptr<RAWINPUTDEVICELIST[]> device_list(
  120. new RAWINPUTDEVICELIST[count]);
  121. result = ::GetRawInputDeviceList(device_list.get(), &count,
  122. sizeof(RAWINPUTDEVICELIST));
  123. if (result == static_cast<UINT>(-1)) {
  124. PLOG(ERROR) << "GetRawInputDeviceList() failed";
  125. return;
  126. }
  127. DCHECK_EQ(count, result);
  128. std::unordered_set<HANDLE> enumerated_device_handles;
  129. for (UINT i = 0; i < count; ++i) {
  130. if (device_list[i].dwType == RIM_TYPEHID) {
  131. HANDLE device_handle = device_list[i].hDevice;
  132. auto controller_it = controllers_.find(device_handle);
  133. RawInputGamepadDeviceWin* device;
  134. if (controller_it != controllers_.end()) {
  135. device = controller_it->second.get();
  136. } else {
  137. int source_id = ++last_source_id_;
  138. auto new_device = std::make_unique<RawInputGamepadDeviceWin>(
  139. device_handle, source_id);
  140. if (!new_device->IsValid()) {
  141. new_device->Shutdown();
  142. continue;
  143. }
  144. const int vendor_int = new_device->GetVendorId();
  145. const int product_int = new_device->GetProductId();
  146. const int version_number = new_device->GetVersionNumber();
  147. const std::wstring product_wstring = new_device->GetProductString();
  148. const std::string product_string = base::SysWideToUTF8(product_wstring);
  149. const GamepadId gamepad_id = GamepadIdList::Get().GetGamepadId(
  150. product_string, vendor_int, product_int);
  151. if (NintendoController::IsNintendoController(gamepad_id)) {
  152. // Nintendo devices are handled by the Nintendo data fetcher.
  153. new_device->Shutdown();
  154. continue;
  155. }
  156. bool is_recognized = GamepadId::kUnknownGamepad != gamepad_id;
  157. // Record gamepad metrics before excluding XInput devices. This allows
  158. // us to recognize XInput devices even though the XInput API masks
  159. // the vendor and product IDs.
  160. RecordConnectedGamepad(gamepad_id);
  161. // The presence of "IG_" in the device name indicates that this is an
  162. // XInput Gamepad. Skip enumerating these devices and let the XInput
  163. // path handle it.
  164. // http://msdn.microsoft.com/en-us/library/windows/desktop/ee417014.aspx
  165. const std::wstring device_name = new_device->GetDeviceName();
  166. if (filter_xinput_ && device_name.find(L"IG_") != std::wstring::npos) {
  167. new_device->Shutdown();
  168. continue;
  169. }
  170. PadState* state = GetPadState(source_id, is_recognized);
  171. if (!state) {
  172. new_device->Shutdown();
  173. continue; // No slot available for this gamepad.
  174. }
  175. auto emplace_result =
  176. controllers_.emplace(device_handle, std::move(new_device));
  177. device = emplace_result.first->second.get();
  178. Gamepad& pad = state->data;
  179. pad.connected = true;
  180. pad.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
  181. pad.vibration_actuator.not_null = device->SupportsVibration();
  182. state->mapper = GetGamepadStandardMappingFunction(
  183. product_string, vendor_int, product_int,
  184. /*hid_specification_version=*/0, version_number,
  185. GAMEPAD_BUS_UNKNOWN);
  186. state->axis_mask = 0;
  187. state->button_mask = 0;
  188. UpdateGamepadStrings(product_string, vendor_int, product_int,
  189. state->mapper != nullptr, pad);
  190. }
  191. enumerated_device_handles.insert(device_handle);
  192. }
  193. }
  194. // Clear out old controllers that weren't part of this enumeration pass.
  195. auto controller_it = controllers_.begin();
  196. while (controller_it != controllers_.end()) {
  197. if (enumerated_device_handles.find(controller_it->first) ==
  198. enumerated_device_handles.end()) {
  199. controller_it->second->Shutdown();
  200. controller_it = controllers_.erase(controller_it);
  201. } else {
  202. ++controller_it;
  203. }
  204. }
  205. }
  206. RawInputGamepadDeviceWin* RawInputDataFetcher::DeviceFromSourceId(
  207. int source_id) {
  208. for (const auto& entry : controllers_) {
  209. if (entry.second->GetSourceId() == source_id)
  210. return entry.second.get();
  211. }
  212. return nullptr;
  213. }
  214. void RawInputDataFetcher::PlayEffect(
  215. int source_id,
  216. mojom::GamepadHapticEffectType type,
  217. mojom::GamepadEffectParametersPtr params,
  218. mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback,
  219. scoped_refptr<base::SequencedTaskRunner> callback_runner) {
  220. RawInputGamepadDeviceWin* device = DeviceFromSourceId(source_id);
  221. if (!device) {
  222. RunVibrationCallback(
  223. std::move(callback), std::move(callback_runner),
  224. mojom::GamepadHapticsResult::GamepadHapticsResultError);
  225. return;
  226. }
  227. if (!device->SupportsVibration()) {
  228. RunVibrationCallback(
  229. std::move(callback), std::move(callback_runner),
  230. mojom::GamepadHapticsResult::GamepadHapticsResultNotSupported);
  231. return;
  232. }
  233. device->PlayEffect(type, std::move(params), std::move(callback),
  234. std::move(callback_runner));
  235. }
  236. void RawInputDataFetcher::ResetVibration(
  237. int source_id,
  238. mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback,
  239. scoped_refptr<base::SequencedTaskRunner> callback_runner) {
  240. RawInputGamepadDeviceWin* device = DeviceFromSourceId(source_id);
  241. if (!device) {
  242. RunVibrationCallback(
  243. std::move(callback), std::move(callback_runner),
  244. mojom::GamepadHapticsResult::GamepadHapticsResultError);
  245. return;
  246. }
  247. if (!device->SupportsVibration()) {
  248. RunVibrationCallback(
  249. std::move(callback), std::move(callback_runner),
  250. mojom::GamepadHapticsResult::GamepadHapticsResultNotSupported);
  251. return;
  252. }
  253. device->ResetVibration(std::move(callback), std::move(callback_runner));
  254. }
  255. LRESULT RawInputDataFetcher::OnInput(HRAWINPUT input_handle) {
  256. // Get the size of the input record.
  257. UINT size = 0;
  258. UINT result = ::GetRawInputData(input_handle, RID_INPUT, nullptr, &size,
  259. sizeof(RAWINPUTHEADER));
  260. if (result == static_cast<UINT>(-1)) {
  261. PLOG(ERROR) << "GetRawInputData() failed";
  262. return 0;
  263. }
  264. DCHECK_EQ(0u, result);
  265. // Retrieve the input record.
  266. std::unique_ptr<uint8_t[]> buffer(new uint8_t[size]);
  267. RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get());
  268. result = ::GetRawInputData(input_handle, RID_INPUT, buffer.get(), &size,
  269. sizeof(RAWINPUTHEADER));
  270. if (result == static_cast<UINT>(-1)) {
  271. PLOG(ERROR) << "GetRawInputData() failed";
  272. return 0;
  273. }
  274. DCHECK_EQ(size, result);
  275. // Notify the observer about events generated locally.
  276. if (input->header.dwType == RIM_TYPEHID && input->header.hDevice != NULL) {
  277. auto it = controllers_.find(input->header.hDevice);
  278. if (it != controllers_.end())
  279. it->second->UpdateGamepad(input);
  280. }
  281. return ::DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER));
  282. }
  283. bool RawInputDataFetcher::HandleMessage(UINT message,
  284. WPARAM wparam,
  285. LPARAM lparam,
  286. LRESULT* result) {
  287. switch (message) {
  288. case WM_INPUT:
  289. *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
  290. return true;
  291. default:
  292. return false;
  293. }
  294. }
  295. } // namespace device