DInput.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Copyright 2010 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "InputCommon/ControllerInterface/DInput/DInput.h"
  4. #include "Common/HRWrap.h"
  5. #include "Common/Logging/Log.h"
  6. #include "Common/StringUtil.h"
  7. #include "InputCommon/ControllerInterface/ControllerInterface.h"
  8. #include "InputCommon/ControllerInterface/DInput/DInputJoystick.h"
  9. #include "InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h"
  10. #pragma comment(lib, "Dinput8.lib")
  11. #pragma comment(lib, "dxguid.lib")
  12. namespace ciface::DInput
  13. {
  14. static IDirectInput8* s_idi8 = nullptr;
  15. BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
  16. {
  17. ((std::list<DIDEVICEOBJECTINSTANCE>*)pvRef)->push_back(*lpddoi);
  18. return DIENUM_CONTINUE;
  19. }
  20. BOOL CALLBACK DIEnumDevicesCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
  21. {
  22. ((std::list<DIDEVICEINSTANCE>*)pvRef)->push_back(*lpddi);
  23. return DIENUM_CONTINUE;
  24. }
  25. std::string GetDeviceName(const LPDIRECTINPUTDEVICE8 device)
  26. {
  27. DIPROPSTRING str = {};
  28. str.diph.dwSize = sizeof(str);
  29. str.diph.dwHeaderSize = sizeof(str.diph);
  30. str.diph.dwHow = DIPH_DEVICE;
  31. std::string result;
  32. HRESULT hr = device->GetProperty(DIPROP_PRODUCTNAME, &str.diph);
  33. if (SUCCEEDED(hr))
  34. {
  35. result = StripWhitespace(WStringToUTF8(str.wsz));
  36. }
  37. else
  38. {
  39. ERROR_LOG_FMT(CONTROLLERINTERFACE, "GetProperty(DIPROP_PRODUCTNAME) failed: {}",
  40. Common::HRWrap(hr));
  41. }
  42. return result;
  43. }
  44. // Assumes hwnd had not changed from the previous call
  45. void PopulateDevices(HWND hwnd)
  46. {
  47. if (!s_idi8)
  48. {
  49. HRESULT hr = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION,
  50. IID_IDirectInput8, (LPVOID*)&s_idi8, nullptr);
  51. if (FAILED(hr))
  52. {
  53. ERROR_LOG_FMT(CONTROLLERINTERFACE, "DirectInput8Create failed: {}", Common::HRWrap(hr));
  54. return;
  55. }
  56. }
  57. // Remove old (invalid) devices. No need to ever remove the KeyboardMouse device.
  58. // Note that if we have 2+ DInput controllers, not fully repopulating devices
  59. // will mean that a device with index "2" could persist while there is no device with index "0".
  60. // This is slightly inconsistent as when we refresh all devices, they will instead reset, and
  61. // that happens a lot (for uncontrolled reasons, like starting/stopping the emulation).
  62. g_controller_interface.RemoveDevice(
  63. [](const auto* dev) { return dev->GetSource() == DINPUT_SOURCE_NAME && !dev->IsValid(); });
  64. InitKeyboardMouse(s_idi8, hwnd);
  65. InitJoystick(s_idi8, hwnd);
  66. }
  67. void ChangeWindow(HWND hwnd)
  68. {
  69. if (s_idi8) // Has init? Ignore if called before the first PopulateDevices()
  70. {
  71. // The KeyboardMouse device is marked as virtual device, so we avoid removing it.
  72. // We need to force all the DInput joysticks to be destroyed now, or recreation would fail.
  73. g_controller_interface.RemoveDevice(
  74. [](const auto* dev) {
  75. return dev->GetSource() == DINPUT_SOURCE_NAME && !dev->IsVirtualDevice();
  76. },
  77. true);
  78. SetKeyboardMouseWindow(hwnd);
  79. InitJoystick(s_idi8, hwnd);
  80. }
  81. }
  82. void DeInit()
  83. {
  84. if (s_idi8)
  85. {
  86. s_idi8->Release();
  87. s_idi8 = nullptr;
  88. }
  89. }
  90. } // namespace ciface::DInput