mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-25 07:21:14 +01:00
Merge pull request #7776 from jordan-woyak/wm_devicechange
Add hotplug support to DInput and XInput controller backends
This commit is contained in:
commit
735a705e4d
@ -35,6 +35,7 @@ if(WIN32)
|
||||
ControllerInterface/DInput/DInputJoystick.cpp
|
||||
ControllerInterface/DInput/DInputKeyboardMouse.cpp
|
||||
ControllerInterface/DInput/XInputFilter.cpp
|
||||
ControllerInterface/Win32/Win32.cpp
|
||||
ControllerInterface/XInput/XInput.cpp
|
||||
ControllerInterface/ForceFeedback/ForceFeedbackDevice.cpp
|
||||
)
|
||||
|
@ -8,11 +8,8 @@
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#ifdef CIFACE_USE_XINPUT
|
||||
#include "InputCommon/ControllerInterface/XInput/XInput.h"
|
||||
#endif
|
||||
#ifdef CIFACE_USE_DINPUT
|
||||
#include "InputCommon/ControllerInterface/DInput/DInput.h"
|
||||
#ifdef CIFACE_USE_WIN32
|
||||
#include "InputCommon/ControllerInterface/Win32/Win32.h"
|
||||
#endif
|
||||
#ifdef CIFACE_USE_XLIB
|
||||
#include "InputCommon/ControllerInterface/Xlib/XInput2.h"
|
||||
@ -48,11 +45,8 @@ void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
|
||||
|
||||
m_is_populating_devices = true;
|
||||
|
||||
#ifdef CIFACE_USE_DINPUT
|
||||
// nothing needed
|
||||
#endif
|
||||
#ifdef CIFACE_USE_XINPUT
|
||||
ciface::XInput::Init();
|
||||
#ifdef CIFACE_USE_WIN32
|
||||
ciface::Win32::Init(wsi.render_surface);
|
||||
#endif
|
||||
#ifdef CIFACE_USE_XLIB
|
||||
// nothing needed
|
||||
@ -99,12 +93,11 @@ void ControllerInterface::RefreshDevices()
|
||||
|
||||
m_is_populating_devices = true;
|
||||
|
||||
#ifdef CIFACE_USE_DINPUT
|
||||
if (m_wsi.type == WindowSystemType::Windows)
|
||||
ciface::DInput::PopulateDevices(reinterpret_cast<HWND>(m_wsi.render_surface));
|
||||
#endif
|
||||
#ifdef CIFACE_USE_XINPUT
|
||||
ciface::XInput::PopulateDevices();
|
||||
// Make sure shared_ptr<Device> objects are released before repopulating.
|
||||
InvokeDevicesChangedCallbacks();
|
||||
|
||||
#ifdef CIFACE_USE_WIN32
|
||||
ciface::Win32::PopulateDevices(m_wsi.render_surface);
|
||||
#endif
|
||||
#ifdef CIFACE_USE_XLIB
|
||||
if (m_wsi.type == WindowSystemType::X11)
|
||||
@ -160,11 +153,8 @@ void ControllerInterface::Shutdown()
|
||||
// BEFORE we shutdown the backends.
|
||||
InvokeDevicesChangedCallbacks();
|
||||
|
||||
#ifdef CIFACE_USE_XINPUT
|
||||
ciface::XInput::DeInit();
|
||||
#endif
|
||||
#ifdef CIFACE_USE_DINPUT
|
||||
// nothing needed
|
||||
#ifdef CIFACE_USE_WIN32
|
||||
ciface::Win32::DeInit();
|
||||
#endif
|
||||
#ifdef CIFACE_USE_XLIB
|
||||
// nothing needed
|
||||
@ -192,21 +182,29 @@ void ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_devices_mutex);
|
||||
// Try to find an ID for this device
|
||||
int id = 0;
|
||||
while (true)
|
||||
|
||||
const auto is_id_in_use = [&device, this](int id) {
|
||||
return std::any_of(m_devices.begin(), m_devices.end(), [&device, &id](const auto& d) {
|
||||
return d->GetSource() == device->GetSource() && d->GetName() == device->GetName() &&
|
||||
d->GetId() == id;
|
||||
});
|
||||
};
|
||||
|
||||
const auto preferred_id = device->GetPreferredId();
|
||||
if (preferred_id.has_value() && !is_id_in_use(*preferred_id))
|
||||
{
|
||||
const auto it =
|
||||
std::find_if(m_devices.begin(), m_devices.end(), [&device, &id](const auto& d) {
|
||||
return d->GetSource() == device->GetSource() && d->GetName() == device->GetName() &&
|
||||
d->GetId() == id;
|
||||
});
|
||||
if (it == m_devices.end()) // no device with the same name with this ID, so we can use it
|
||||
break;
|
||||
else
|
||||
id++;
|
||||
// Use the device's preferred ID if available.
|
||||
device->SetId(*preferred_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the first available ID to use.
|
||||
int id = 0;
|
||||
while (is_id_in_use(id))
|
||||
++id;
|
||||
|
||||
device->SetId(id);
|
||||
}
|
||||
device->SetId(id);
|
||||
|
||||
NOTICE_LOG(SERIALINTERFACE, "Added device: %s", device->GetQualifiedName().c_str());
|
||||
m_devices.emplace_back(std::move(device));
|
||||
|
@ -15,8 +15,7 @@
|
||||
|
||||
// enable disable sources
|
||||
#ifdef _WIN32
|
||||
#define CIFACE_USE_XINPUT
|
||||
#define CIFACE_USE_DINPUT
|
||||
#define CIFACE_USE_WIN32
|
||||
#endif
|
||||
#if defined(HAVE_X11) && HAVE_X11
|
||||
#define CIFACE_USE_XLIB
|
||||
|
@ -3,9 +3,11 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "InputCommon/ControllerInterface/DInput/DInput.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
#include "InputCommon/ControllerInterface/DInput/DInputJoystick.h"
|
||||
#include "InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h"
|
||||
|
||||
@ -40,23 +42,32 @@ std::string GetDeviceName(const LPDIRECTINPUTDEVICE8 device)
|
||||
{
|
||||
result = StripSpaces(UTF16ToUTF8(str.wsz));
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(PAD, "GetProperty(DIPROP_PRODUCTNAME) failed.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PopulateDevices(HWND hwnd)
|
||||
{
|
||||
// Remove unplugged devices.
|
||||
g_controller_interface.RemoveDevice(
|
||||
[](const auto* dev) { return dev->GetSource() == DINPUT_SOURCE_NAME && !dev->IsValid(); });
|
||||
|
||||
IDirectInput8* idi8;
|
||||
if (FAILED(DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8,
|
||||
(LPVOID*)&idi8, nullptr)))
|
||||
{
|
||||
ERROR_LOG(PAD, "DirectInput8Create failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
InitKeyboardMouse(idi8, hwnd);
|
||||
InitKeyboardMouse(idi8);
|
||||
InitJoystick(idi8, hwnd);
|
||||
|
||||
idi8->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace DInput
|
||||
} // namespace ciface
|
||||
|
@ -4,8 +4,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
@ -17,7 +18,19 @@ namespace ciface
|
||||
{
|
||||
namespace DInput
|
||||
{
|
||||
#define DATA_BUFFER_SIZE 32
|
||||
constexpr DWORD DATA_BUFFER_SIZE = 32;
|
||||
|
||||
struct GUIDComparator
|
||||
{
|
||||
bool operator()(const GUID& left, const GUID& right) const
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<GUID>);
|
||||
|
||||
return memcmp(&left, &right, sizeof(left)) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
static std::set<GUID, GUIDComparator> s_guids_in_use;
|
||||
|
||||
void InitJoystick(IDirectInput8* const idi8, HWND hwnd)
|
||||
{
|
||||
@ -28,12 +41,18 @@ void InitJoystick(IDirectInput8* const idi8, HWND hwnd)
|
||||
std::unordered_set<DWORD> xinput_guids = GetXInputGUIDS();
|
||||
for (DIDEVICEINSTANCE& joystick : joysticks)
|
||||
{
|
||||
// skip XInput Devices
|
||||
// Skip XInput Devices
|
||||
if (xinput_guids.count(joystick.guidProduct.Data1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip devices we are already using.
|
||||
if (s_guids_in_use.count(joystick.guidInstance))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LPDIRECTINPUTDEVICE8 js_device;
|
||||
if (SUCCEEDED(idi8->CreateDevice(joystick.guidInstance, &js_device, nullptr)))
|
||||
{
|
||||
@ -55,7 +74,9 @@ void InitJoystick(IDirectInput8* const idi8, HWND hwnd)
|
||||
}
|
||||
}
|
||||
|
||||
s_guids_in_use.insert(joystick.guidInstance);
|
||||
auto js = std::make_shared<Joystick>(js_device);
|
||||
|
||||
// only add if it has some inputs/outputs
|
||||
if (js->Inputs().size() || js->Outputs().size())
|
||||
g_controller_interface.AddDevice(std::move(js));
|
||||
@ -161,6 +182,17 @@ Joystick::Joystick(/*const LPCDIDEVICEINSTANCE lpddi, */ const LPDIRECTINPUTDEVI
|
||||
|
||||
Joystick::~Joystick()
|
||||
{
|
||||
DIDEVICEINSTANCE info = {};
|
||||
info.dwSize = sizeof(info);
|
||||
if (SUCCEEDED(m_device->GetDeviceInfo(&info)))
|
||||
{
|
||||
s_guids_in_use.erase(info.guidInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(PAD, "DInputJoystick: GetDeviceInfo failed.");
|
||||
}
|
||||
|
||||
DeInitForceFeedback();
|
||||
|
||||
m_device->Unacquire();
|
||||
@ -177,7 +209,10 @@ std::string Joystick::GetSource() const
|
||||
return DINPUT_SOURCE_NAME;
|
||||
}
|
||||
|
||||
// update IO
|
||||
bool Joystick::IsValid() const
|
||||
{
|
||||
return SUCCEEDED(m_device->Acquire());
|
||||
}
|
||||
|
||||
void Joystick::UpdateInput()
|
||||
{
|
||||
|
@ -68,6 +68,8 @@ public:
|
||||
std::string GetName() const override;
|
||||
std::string GetSource() const override;
|
||||
|
||||
bool IsValid() const final override;
|
||||
|
||||
private:
|
||||
const LPDIRECTINPUTDEVICE8 m_device;
|
||||
|
||||
@ -75,5 +77,5 @@ private:
|
||||
|
||||
bool m_buffered;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace DInput
|
||||
} // namespace ciface
|
||||
|
@ -29,12 +29,13 @@ static const struct
|
||||
#include "InputCommon/ControllerInterface/DInput/NamedKeys.h" // NOLINT
|
||||
};
|
||||
|
||||
// lil silly
|
||||
static HWND m_hwnd;
|
||||
// Prevent duplicate keyboard/mouse devices.
|
||||
static bool s_keyboard_mouse_exists = false;
|
||||
|
||||
void InitKeyboardMouse(IDirectInput8* const idi8, HWND _hwnd)
|
||||
void InitKeyboardMouse(IDirectInput8* const idi8)
|
||||
{
|
||||
m_hwnd = _hwnd;
|
||||
if (s_keyboard_mouse_exists)
|
||||
return;
|
||||
|
||||
// mouse and keyboard are a combined device, to allow shift+click and stuff
|
||||
// if that's dumb, I will make a VirtualDevice class that just uses ranges of inputs/outputs from
|
||||
@ -63,6 +64,8 @@ void InitKeyboardMouse(IDirectInput8* const idi8, HWND _hwnd)
|
||||
|
||||
KeyboardMouse::~KeyboardMouse()
|
||||
{
|
||||
s_keyboard_mouse_exists = false;
|
||||
|
||||
// kb
|
||||
m_kb_device->Unacquire();
|
||||
m_kb_device->Release();
|
||||
@ -75,6 +78,8 @@ KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device,
|
||||
const LPDIRECTINPUTDEVICE8 mo_device)
|
||||
: m_kb_device(kb_device), m_mo_device(mo_device)
|
||||
{
|
||||
s_keyboard_mouse_exists = true;
|
||||
|
||||
m_kb_device->Acquire();
|
||||
m_mo_device->Acquire();
|
||||
|
||||
@ -237,5 +242,5 @@ ControlState KeyboardMouse::Cursor::GetState() const
|
||||
{
|
||||
return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace DInput
|
||||
} // namespace ciface
|
||||
|
@ -13,7 +13,7 @@ namespace ciface
|
||||
{
|
||||
namespace DInput
|
||||
{
|
||||
void InitKeyboardMouse(IDirectInput8* const idi8, HWND _hwnd);
|
||||
void InitKeyboardMouse(IDirectInput8* const idi8);
|
||||
|
||||
class KeyboardMouse : public Core::Device
|
||||
{
|
||||
@ -98,5 +98,5 @@ private:
|
||||
DWORD m_last_update;
|
||||
State m_state_in;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace DInput
|
||||
} // namespace ciface
|
||||
|
@ -31,6 +31,11 @@ Device::~Device()
|
||||
delete output;
|
||||
}
|
||||
|
||||
std::optional<int> Device::GetPreferredId() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void Device::AddInput(Device::Input* const i)
|
||||
{
|
||||
m_inputs.push_back(i);
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -82,7 +83,7 @@ public:
|
||||
class Output : public Control
|
||||
{
|
||||
public:
|
||||
virtual ~Output() {}
|
||||
virtual ~Output() = default;
|
||||
virtual void SetState(ControlState state) = 0;
|
||||
Output* ToOutput() override { return this; }
|
||||
};
|
||||
@ -95,9 +96,17 @@ public:
|
||||
virtual std::string GetSource() const = 0;
|
||||
std::string GetQualifiedName() const;
|
||||
virtual void UpdateInput() {}
|
||||
|
||||
// May be overridden to implement hotplug removal.
|
||||
// Currently handled on a per-backend basis but this could change.
|
||||
virtual bool IsValid() const { return true; }
|
||||
|
||||
// (e.g. Xbox 360 controllers have controller number LEDs which should match the ID we use.)
|
||||
virtual std::optional<int> GetPreferredId() const;
|
||||
|
||||
const std::vector<Input*>& Inputs() const { return m_inputs; }
|
||||
const std::vector<Output*>& Outputs() const { return m_outputs; }
|
||||
|
||||
Input* FindInput(const std::string& name) const;
|
||||
Output* FindOutput(const std::string& name) const;
|
||||
|
||||
|
135
Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp
Normal file
135
Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "InputCommon/ControllerInterface/Win32/Win32.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "Common/Event.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/ScopeGuard.h"
|
||||
#include "InputCommon/ControllerInterface/DInput/DInput.h"
|
||||
#include "InputCommon/ControllerInterface/XInput/XInput.h"
|
||||
|
||||
constexpr UINT WM_DOLPHIN_STOP = WM_USER;
|
||||
|
||||
static Common::Event s_done_populating;
|
||||
static std::atomic<HWND> s_hwnd;
|
||||
static HWND s_message_window;
|
||||
static std::thread s_thread;
|
||||
|
||||
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_INPUT_DEVICE_CHANGE)
|
||||
{
|
||||
ciface::DInput::PopulateDevices(s_hwnd);
|
||||
ciface::XInput::PopulateDevices();
|
||||
s_done_populating.Set();
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, message, wparam, lparam);
|
||||
}
|
||||
|
||||
void ciface::Win32::Init(void* hwnd)
|
||||
{
|
||||
s_hwnd = static_cast<HWND>(hwnd);
|
||||
XInput::Init();
|
||||
|
||||
s_thread = std::thread([] {
|
||||
if (FAILED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)))
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "CoInitializeEx failed: %i", GetLastError());
|
||||
return;
|
||||
}
|
||||
Common::ScopeGuard uninit([] { CoUninitialize(); });
|
||||
|
||||
WNDCLASSEX window_class_info{};
|
||||
window_class_info.cbSize = sizeof(window_class_info);
|
||||
window_class_info.lpfnWndProc = WindowProc;
|
||||
window_class_info.hInstance = GetModuleHandle(nullptr);
|
||||
window_class_info.lpszClassName = L"Message";
|
||||
|
||||
ATOM window_class = RegisterClassEx(&window_class_info);
|
||||
if (!window_class)
|
||||
{
|
||||
NOTICE_LOG(SERIALINTERFACE, "RegisterClassEx failed: %i", GetLastError());
|
||||
return;
|
||||
}
|
||||
Common::ScopeGuard unregister([&window_class] {
|
||||
if (!UnregisterClass(MAKEINTATOM(window_class), GetModuleHandle(nullptr)))
|
||||
ERROR_LOG(SERIALINTERFACE, "UnregisterClass failed: %i", GetLastError());
|
||||
});
|
||||
|
||||
s_message_window = CreateWindowEx(0, L"Message", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr,
|
||||
nullptr, nullptr);
|
||||
if (!s_message_window)
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "CreateWindowEx failed: %i", GetLastError());
|
||||
return;
|
||||
}
|
||||
Common::ScopeGuard destroy([] {
|
||||
if (!DestroyWindow(s_message_window))
|
||||
ERROR_LOG(SERIALINTERFACE, "DestroyWindow failed: %i", GetLastError());
|
||||
s_message_window = nullptr;
|
||||
});
|
||||
|
||||
std::array<RAWINPUTDEVICE, 2> devices;
|
||||
// game pad devices
|
||||
devices[0].usUsagePage = 0x01;
|
||||
devices[0].usUsage = 0x05;
|
||||
devices[0].dwFlags = RIDEV_DEVNOTIFY;
|
||||
devices[0].hwndTarget = s_message_window;
|
||||
// joystick devices
|
||||
devices[1].usUsagePage = 0x01;
|
||||
devices[1].usUsage = 0x04;
|
||||
devices[1].dwFlags = RIDEV_DEVNOTIFY;
|
||||
devices[1].hwndTarget = s_message_window;
|
||||
|
||||
if (!RegisterRawInputDevices(devices.data(), static_cast<UINT>(devices.size()),
|
||||
static_cast<UINT>(sizeof(decltype(devices)::value_type))))
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "RegisterRawInputDevices failed: %i", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, nullptr, 0, 0) > 0)
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
if (msg.message == WM_DOLPHIN_STOP)
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ciface::Win32::PopulateDevices(void* hwnd)
|
||||
{
|
||||
if (s_thread.joinable())
|
||||
{
|
||||
s_hwnd = static_cast<HWND>(hwnd);
|
||||
s_done_populating.Reset();
|
||||
PostMessage(s_message_window, WM_INPUT_DEVICE_CHANGE, 0, 0);
|
||||
if (!s_done_populating.WaitFor(std::chrono::seconds(10)))
|
||||
ERROR_LOG(SERIALINTERFACE, "win32 timed out when trying to populate devices");
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "win32 asked to populate devices, but device thread isn't running");
|
||||
}
|
||||
}
|
||||
|
||||
void ciface::Win32::DeInit()
|
||||
{
|
||||
NOTICE_LOG(SERIALINTERFACE, "win32 DeInit");
|
||||
if (s_thread.joinable())
|
||||
{
|
||||
PostMessage(s_message_window, WM_DOLPHIN_STOP, 0, 0);
|
||||
s_thread.join();
|
||||
}
|
||||
|
||||
XInput::DeInit();
|
||||
}
|
15
Source/Core/InputCommon/ControllerInterface/Win32/Win32.h
Normal file
15
Source/Core/InputCommon/ControllerInterface/Win32/Win32.h
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ciface
|
||||
{
|
||||
namespace Win32
|
||||
{
|
||||
void Init(void* hwnd);
|
||||
void PopulateDevices(void* hwnd);
|
||||
void DeInit();
|
||||
} // namespace Win32
|
||||
} // namespace ciface
|
@ -92,6 +92,8 @@ void PopulateDevices()
|
||||
if (!hXInput)
|
||||
return;
|
||||
|
||||
g_controller_interface.RemoveDevice([](const auto* dev) { return dev->GetSource() == "XInput"; });
|
||||
|
||||
XINPUT_CAPABILITIES caps;
|
||||
for (int i = 0; i != 4; ++i)
|
||||
if (ERROR_SUCCESS == PXInputGetCapabilities(i, 0, &caps))
|
||||
@ -192,6 +194,11 @@ void Device::UpdateMotors()
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<int> Device::GetPreferredId() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
// GET name/source/id
|
||||
|
||||
std::string Device::Button::GetName() const
|
||||
|
@ -92,8 +92,9 @@ public:
|
||||
|
||||
Device(const XINPUT_CAPABILITIES& capabilities, u8 index);
|
||||
|
||||
std::string GetName() const override;
|
||||
std::string GetSource() const override;
|
||||
std::string GetName() const final override;
|
||||
std::string GetSource() const final override;
|
||||
std::optional<int> GetPreferredId() const final override;
|
||||
|
||||
void UpdateMotors();
|
||||
|
||||
@ -104,5 +105,5 @@ private:
|
||||
const BYTE m_subtype;
|
||||
const u8 m_index;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace XInput
|
||||
} // namespace ciface
|
||||
|
@ -63,6 +63,7 @@
|
||||
<ClCompile Include="ControlReference\ControlReference.cpp" />
|
||||
<ClCompile Include="ControlReference\ExpressionParser.cpp" />
|
||||
<ClCompile Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.cpp" />
|
||||
<ClCompile Include="ControllerInterface\Win32\Win32.cpp" />
|
||||
<ClCompile Include="ControllerInterface\XInput\XInput.cpp" />
|
||||
<ClCompile Include="GCAdapter.cpp">
|
||||
<!--
|
||||
@ -104,6 +105,7 @@
|
||||
<ClInclude Include="ControlReference\ControlReference.h" />
|
||||
<ClInclude Include="ControlReference\ExpressionParser.h" />
|
||||
<ClInclude Include="ControllerInterface\ForceFeedback\ForceFeedbackDevice.h" />
|
||||
<ClInclude Include="ControllerInterface\Win32\Win32.h" />
|
||||
<ClInclude Include="ControllerInterface\XInput\XInput.h" />
|
||||
<ClInclude Include="GCAdapter.h" />
|
||||
<ClInclude Include="GCPadStatus.h" />
|
||||
|
@ -4,12 +4,6 @@
|
||||
<Filter Include="ControllerInterface">
|
||||
<UniqueIdentifier>{3a755a86-0efa-4396-bf79-bb3a1910764d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ControllerInterface\DInput">
|
||||
<UniqueIdentifier>{0289ef91-50f5-4c16-9fa4-ff4c4d8208e7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ControllerInterface\XInput">
|
||||
<UniqueIdentifier>{07bad1aa-7e03-4f5c-ade2-a44857c5cbc3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ControllerInterface\ForceFeedback">
|
||||
<UniqueIdentifier>{e10ce316-283c-4be0-848d-578dec2b6404}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@ -25,6 +19,15 @@
|
||||
<Filter Include="ControllerEmu\Setting">
|
||||
<UniqueIdentifier>{ce661cb4-f23f-4ab2-952d-402d381735e5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ControllerInterface\Win32">
|
||||
<UniqueIdentifier>{6ca06b20-d8f6-4622-97ab-eefbc66edbd5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ControllerInterface\DInput">
|
||||
<UniqueIdentifier>{0289ef91-50f5-4c16-9fa4-ff4c4d8208e7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ControllerInterface\XInput">
|
||||
<UniqueIdentifier>{07bad1aa-7e03-4f5c-ade2-a44857c5cbc3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="GCAdapter.cpp" />
|
||||
@ -104,6 +107,9 @@
|
||||
<ClCompile Include="ControllerInterface\DInput\XInputFilter.cpp">
|
||||
<Filter>ControllerInterface\DInput</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ControllerInterface\Win32\Win32.cpp">
|
||||
<Filter>ControllerInterface\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ControlReference\ExpressionParser.cpp">
|
||||
<Filter>ControllerInterface</Filter>
|
||||
</ClCompile>
|
||||
@ -200,6 +206,9 @@
|
||||
<ClInclude Include="ControllerInterface\DInput\XInputFilter.h">
|
||||
<Filter>ControllerInterface\DInput</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ControllerInterface\Win32\Win32.h">
|
||||
<Filter>ControllerInterface\Win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ControlReference\ExpressionParser.h">
|
||||
<Filter>ControllerInterface</Filter>
|
||||
</ClInclude>
|
||||
|
Loading…
x
Reference in New Issue
Block a user