18 #if defined(_WIN32) && !defined(CPPPARSER) 25 WinInputDeviceManager::
26 WinInputDeviceManager() :
31 _message_hwnd(nullptr) {
35 _xinput_device0.local_object();
36 _xinput_device1.local_object();
37 _xinput_device2.local_object();
38 _xinput_device3.local_object();
41 HMODULE module = LoadLibraryA(
"cfgmgr32.dll");
43 _CM_Get_DevNode_PropertyW = (pCM_Get_DevNode_Property)GetProcAddress(module,
"CM_Get_DevNode_PropertyW");
45 _CM_Get_DevNode_PropertyW =
nullptr;
50 wc.cbSize =
sizeof(WNDCLASSEX);
51 wc.lpfnWndProc = window_proc;
52 wc.hInstance = GetModuleHandle(
nullptr);
53 wc.lpszClassName =
"InputDeviceManager";
54 if (!RegisterClassEx(&wc)) {
56 <<
"Failed to register message-only window class.\n";
60 _message_hwnd = CreateWindowEx(0, wc.lpszClassName,
"InputDeviceManager", 0, 0, 0, 0, 0, HWND_MESSAGE,
nullptr,
nullptr,
nullptr);
63 <<
"Failed to create message-only window.\n";
68 RAWINPUTDEVICE rid[3];
69 rid[0].usUsagePage = 1;
71 rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
72 rid[0].hwndTarget = _message_hwnd;
73 rid[1].usUsagePage = 1;
75 rid[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
76 rid[1].hwndTarget = _message_hwnd;
77 rid[2].usUsagePage = 1;
79 rid[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
80 rid[2].hwndTarget = _message_hwnd;
81 if (!RegisterRawInputDevices(rid, 3,
sizeof(RAWINPUTDEVICE))) {
83 <<
"Failed to register raw input devices.\n";
89 RAWINPUTDEVICELIST devices[64];
90 UINT num_devices = 64;
91 num_devices = GetRawInputDeviceList(devices, &num_devices,
sizeof(RAWINPUTDEVICELIST));
92 if (num_devices == (UINT)-1) {
95 for (UINT i = 0; i < num_devices; ++i) {
96 if (devices[i].dwType != RIM_TYPEHID) {
99 HANDLE handle = devices[i].hDevice;
101 if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME,
nullptr, &size) != 0) {
105 char *path = (
char *)alloca(size);
106 if (path ==
nullptr ||
107 GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (
void *)path, &size) < 0) {
111 if (strstr(path,
"&IG_") !=
nullptr) {
112 xinput_handle = handle;
116 if (num_xinput == 1) {
118 on_input_device_arrival(xinput_handle);
119 }
else if (num_xinput > 0) {
121 _xinput_device0.detect(
this);
122 _xinput_device1.detect(
this);
123 _xinput_device2.detect(
this);
124 _xinput_device3.detect(
this);
131 WinInputDeviceManager::
132 ~WinInputDeviceManager() {
133 if (_message_hwnd !=
nullptr) {
134 DestroyWindow(_message_hwnd);
135 _message_hwnd =
nullptr;
142 void WinInputDeviceManager::
143 device_destroyed(WinRawInputDevice *device) {
146 if (device->_handle !=
nullptr) {
147 _raw_devices.erase(device->_handle);
150 _raw_devices_by_path.erase(device->_path);
156 void WinInputDeviceManager::
157 on_input(HRAWINPUT handle) {
159 if (GetRawInputData(handle, RID_INPUT,
nullptr, &size,
sizeof(RAWINPUTHEADER)) < 0) {
163 PRAWINPUT data = (PRAWINPUT)alloca(size);
164 if (GetRawInputData(handle, RID_INPUT, data, &size,
sizeof(RAWINPUTHEADER)) <= 0) {
169 PT(WinRawInputDevice) device;
172 auto it = _raw_devices.find(data->header.hDevice);
173 if (it != _raw_devices.end()) {
177 if (device !=
nullptr) {
178 device->on_input(data);
185 void WinInputDeviceManager::
186 on_input_device_arrival(HANDLE handle) {
189 if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME,
nullptr, &size) != 0) {
193 char *path = (
char *)alloca(size);
194 if (path ==
nullptr ||
195 GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (
void *)path, &size) < 0) {
199 if (device_cat.is_debug()) {
201 <<
"GIDC_ARRIVAL: " << path <<
"\n";
205 RID_DEVICE_INFO info;
206 info.cbSize =
sizeof(RID_DEVICE_INFO);
207 size =
sizeof(RID_DEVICE_INFO);
208 if (GetRawInputDeviceInfoA(handle, RIDI_DEVICEINFO, &info, &size) <= 0) {
213 while (path[0] ==
'\\' || path[0] ==
'?' || path[0] ==
'.') {
236 std::string name, manufacturer;
238 CONFIGRET ret = CM_Locate_DevNodeA(&inst, (DEVINSTID_A)path, CM_LOCATE_DEVNODE_PHANTOM);
239 if (ret == CR_SUCCESS) {
242 if (CM_Get_DevNode_Registry_Property(inst, CM_DRP_DEVICEDESC, 0, buffer, &buflen, 0) == CR_SUCCESS) {
246 if (CM_Get_DevNode_Registry_Property(inst, CM_DRP_MFG, 0, buffer, &buflen, 0) == CR_SUCCESS) {
247 if (strcmp(buffer,
"(Standard system devices)") != 0) {
248 manufacturer.assign(buffer);
257 while (CM_Get_Parent(&parent, cur, 0) == CR_SUCCESS) {
259 std::string dev_class;
260 if (CM_Get_DevNode_Registry_Property(parent, CM_DRP_CLASS, 0, buffer, &buflen, 0) == CR_SUCCESS) {
261 if (strcmp(buffer,
"USB") == 0) {
265 dev_class.assign(buffer);
271 if (manufacturer.empty() &&
272 CM_Get_DevNode_Registry_Property(cur, CM_DRP_MFG, 0, buffer, &buflen, 0) == CR_SUCCESS) {
273 if (strcmp(buffer,
"(Standard system devices)") != 0) {
274 manufacturer.assign(buffer);
280 static const DEVPROPKEY bus_reported_device_desc = {
281 {0x540b947e, 0x8b40, 0x45bc, {0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2}},
286 if (dev_class ==
"HIDClass" && _CM_Get_DevNode_PropertyW !=
nullptr &&
287 _CM_Get_DevNode_PropertyW(cur, &bus_reported_device_desc, &type, (PBYTE)buffer, &buflen, 0) == CR_SUCCESS &&
288 type == DEVPROP_TYPE_STRING) {
291 wchar_t *wbuffer = (
wchar_t *)buffer;
292 size_t wlen = wcslen(wbuffer);
293 while (iswspace(wbuffer[wlen - 1])) {
297 name.assign(encoder.
encode_wtext(std::wstring(wbuffer, wlen)));
301 if (CM_Get_DevNode_Registry_Property(cur, CM_DRP_DEVICEDESC, 0, buffer, &buflen, 0) == CR_SUCCESS) {
304 if (strcmp(buffer,
"USB Input Device") != 0) {
310 }
else if (device_cat.is_debug()) {
313 <<
"Could not locate device node " << path <<
" (" << ret <<
")\n";
318 if (info.dwType == RIM_TYPEHID && strstr(path,
"&IG_") !=
nullptr &&
319 XInputDevice::init_xinput()) {
322 if (_xinput_device0.check_arrival(info, inst, name, manufacturer)) {
323 add_device(&_xinput_device0);
325 if (_xinput_device1.check_arrival(info, inst, name, manufacturer)) {
326 add_device(&_xinput_device1);
328 if (_xinput_device2.check_arrival(info, inst, name, manufacturer)) {
329 add_device(&_xinput_device2);
331 if (_xinput_device3.check_arrival(info, inst, name, manufacturer)) {
332 add_device(&_xinput_device3);
342 PT(WinRawInputDevice) device;
343 auto it = _raw_devices_by_path.find(path);
344 if (it != _raw_devices_by_path.end()) {
347 device =
new WinRawInputDevice(
this, path);
348 _raw_devices_by_path[path] = device;
351 if (device->on_arrival(handle, info, move(name))) {
352 _raw_devices[handle] = device;
353 _connected_devices.add_device(device);
355 if (device_cat.is_debug()) {
357 <<
"Discovered input device " << *device <<
"\n";
359 throw_event(
"connect-device", device.p());
366 void WinInputDeviceManager::
367 on_input_device_removal(HANDLE handle) {
374 PT(WinRawInputDevice) device;
377 auto it = _raw_devices.find(handle);
378 if (it != _raw_devices.end()) {
379 device = std::move(it->second);
380 _raw_devices.erase(it);
381 device->on_removal();
383 if (_connected_devices.remove_device(device)) {
384 throw_event(
"disconnect-device", device.p());
386 if (device_cat.is_debug()) {
388 <<
"Removed input device " << *device <<
"\n";
397 LRESULT WINAPI WinInputDeviceManager::
398 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
399 WinInputDeviceManager *mgr;
403 if (mgr !=
nullptr) {
404 mgr->on_input((HRAWINPUT)lparam);
408 case WM_INPUT_DEVICE_CHANGE:
409 switch (LOWORD(wparam)) {
412 if (mgr !=
nullptr) {
413 mgr->on_input_device_arrival((HANDLE)lparam);
419 if (mgr !=
nullptr) {
420 mgr->on_input_device_removal((HANDLE)lparam);
429 return DefWindowProcW(hwnd, msg, wparam, lparam);
This class can be used to convert text between multiple representations, e.g.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Similar to MutexHolder, but for a light mutex.
std::string encode_wtext(const std::wstring &wtext) const
Encodes a wide-text string into a single-char string, according to the current encoding.