diff options
Diffstat (limited to 'wrapper')
| -rw-r--r-- | wrapper/input.cpp | 65 | ||||
| -rw-r--r-- | wrapper/input.h | 78 | ||||
| -rw-r--r-- | wrapper/interop-exception.h | 9 | ||||
| -rw-r--r-- | wrapper/wrapper.vcxproj | 1 | ||||
| -rw-r--r-- | wrapper/wrapper.vcxproj.filters | 3 |
5 files changed, 117 insertions, 39 deletions
diff --git a/wrapper/input.cpp b/wrapper/input.cpp index d50f774..3ce257a 100644 --- a/wrapper/input.cpp +++ b/wrapper/input.cpp @@ -1,43 +1,52 @@ +#include "input.h" #include "interop-exception.h" -#include <utility-rawinput.hpp> -#include <algorithm> #include <msclr\marshal_cppstd.h> +#include <algorithm> using namespace System; using namespace System::Collections::Generic; -struct device_info { - std::wstring name; - std::wstring id; -}; +std::vector<HANDLE> rawinput_handles_from_id(const std::wstring& device_id) +{ + std::vector<HANDLE> handles; + + rawinput_foreach([&](const auto& dev) { + if (dev.id == device_id) handles.push_back(dev.handle); + }); -std::vector<device_info> get_unique_device_info() { - std::vector<device_info> info; + return handles; +} + +std::vector<std::wstring> rawinput_id_list() +{ + std::vector<std::wstring> ids; - rawinput_foreach_with_interface([&](const auto& dev, const WCHAR* name) { - info.push_back({ - L"", // get_property_wstr(name, &DEVPKEY_Device_FriendlyName), /* doesn't work */ - dev_id_from_interface(name) - }); + rawinput_foreach([&](const auto& dev) { + ids.push_back(dev.id); }); - std::sort(info.begin(), info.end(), - [](auto&& l, auto&& r) { return l.id < r.id; }); - auto last = std::unique(info.begin(), info.end(), - [](auto&& l, auto&& r) { return l.id == r.id; }); - info.erase(last, info.end()); - - return info; + std::sort(ids.begin(), ids.end()); + ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); + return ids; } +public ref struct RawInputInteropException : InteropException { + RawInputInteropException(System::String^ what) : + InteropException(what) {} + RawInputInteropException(const char* what) : + InteropException(what) {} + RawInputInteropException(const std::exception& e) : + InteropException(e) {} +}; + public ref struct RawInputInterop { static void AddHandlesFromID(String^ deviceID, List<IntPtr>^ rawInputHandles) { try { - std::vector<HANDLE> nativeHandles = rawinput_handles_from_dev_id( + std::vector<HANDLE> nativeHandles = rawinput_handles_from_id( msclr::interop::marshal_as<std::wstring>(deviceID)); for (auto nh : nativeHandles) rawInputHandles->Add(IntPtr(nh)); @@ -48,21 +57,18 @@ public ref struct RawInputInterop } } - static List<ValueTuple<String^, String^>>^ GetDeviceIDs() + static List<String^>^ GetDeviceIDs() { try { - auto managed = gcnew List<ValueTuple<String^, String^>>(); + auto ids = gcnew List<String^>(); - for (auto&& [name, id] : get_unique_device_info()) + for (auto&& name : rawinput_id_list()) { - managed->Add( - ValueTuple<String^, String^>( - msclr::interop::marshal_as<String^>(name), - msclr::interop::marshal_as<String^>(id))); + ids->Add(msclr::interop::marshal_as<String^>(name)); } - return managed; + return ids; } catch (const std::exception& e) { @@ -71,4 +77,3 @@ public ref struct RawInputInterop } }; - diff --git a/wrapper/input.h b/wrapper/input.h new file mode 100644 index 0000000..c83dca8 --- /dev/null +++ b/wrapper/input.h @@ -0,0 +1,78 @@ +#pragma once + +#pragma comment(lib, "cfgmgr32.lib") + +#include <string> +#include <system_error> +#include <vector> + +#include <Windows.h> +#include <cfgmgr32.h> +#include <initguid.h> // needed for devpkey.h to parse properly +#include <devpkey.h> + +struct rawinput_device { + HANDLE handle; + std::wstring id; +}; + +template <typename Func> +void rawinput_foreach(Func fn, DWORD device_type = RIM_TYPEMOUSE) +{ + const UINT RI_ERROR = -1; + + // get number of devices + UINT num_devs = 0; + if (GetRawInputDeviceList(NULL, &num_devs, sizeof(RAWINPUTDEVICELIST)) != 0) { + throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceList failed"); + } + + auto dev_list = std::vector<RAWINPUTDEVICELIST>(num_devs); + + if (GetRawInputDeviceList(&dev_list[0], &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) { + return; + } + + std::wstring name; + rawinput_device dev; + DEVPROPTYPE prop_type; + CONFIGRET cm_res; + + for (auto [handle, dev_type] : dev_list) { + if (dev_type != device_type) continue; + + // get interface name length + UINT name_len = 0; + if (GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, NULL, &name_len) == RI_ERROR) { + continue; + } + + name.resize(name_len); + + if (GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, &name[0], &name_len) == RI_ERROR) { + continue; + } + + // get sizeof device instance id + ULONG id_size = 0; + cm_res = CM_Get_Device_Interface_PropertyW(&name[0], &DEVPKEY_Device_InstanceId, + &prop_type, NULL, &id_size, 0); + + if (cm_res != CR_BUFFER_SMALL && cm_res != CR_SUCCESS) continue; + + dev.id.resize((id_size + 1) / 2); + + cm_res = CM_Get_Device_Interface_PropertyW(&name[0], &DEVPKEY_Device_InstanceId, + &prop_type, reinterpret_cast<PBYTE>(&dev.id[0]), &id_size, 0); + + if (cm_res != CR_SUCCESS) continue; + + // pop instance id + auto instance_delim_pos = dev.id.find_last_of('\\'); + if (instance_delim_pos != std::string::npos) dev.id.resize(instance_delim_pos); + + dev.handle = handle; + + fn(dev); + } +} diff --git a/wrapper/interop-exception.h b/wrapper/interop-exception.h index 8ebae5c..0e88b2c 100644 --- a/wrapper/interop-exception.h +++ b/wrapper/interop-exception.h @@ -10,12 +10,3 @@ public ref struct InteropException : System::Exception { InteropException(const std::exception& e) : InteropException(e.what()) {} }; - -public ref struct RawInputInteropException : InteropException { - RawInputInteropException(System::String^ what) : - InteropException(what) {} - RawInputInteropException(const char* what) : - InteropException(what) {} - RawInputInteropException(const std::exception& e) : - InteropException(e) {} -}; diff --git a/wrapper/wrapper.vcxproj b/wrapper/wrapper.vcxproj index cd121a2..5d58614 100644 --- a/wrapper/wrapper.vcxproj +++ b/wrapper/wrapper.vcxproj @@ -85,6 +85,7 @@ copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)signed\Newtonsoft.Json. </ResourceCompile> </ItemDefinitionGroup> <ItemGroup> + <ClInclude Include="input.h" /> <ClInclude Include="interop-exception.h" /> <ClInclude Include="resource.h" /> </ItemGroup> diff --git a/wrapper/wrapper.vcxproj.filters b/wrapper/wrapper.vcxproj.filters index 9caeae1..1d0196d 100644 --- a/wrapper/wrapper.vcxproj.filters +++ b/wrapper/wrapper.vcxproj.filters @@ -21,6 +21,9 @@ <ClInclude Include="interop-exception.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="input.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="wrapper.cpp"> |