diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index c160382c17..86e6a9baf3 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -184,7 +184,7 @@ bool LLWindowCallbacks::handleTimerEvent(LLWindow *window) return false; } -bool LLWindowCallbacks::handleDeviceChange(LLWindow *window) +bool LLWindowCallbacks::handleDeviceChange(LLWindow *window, bool deviceRemoved) // [FIRE-10419] Added deviceRemoved bool to prevent reinitialize on disconnect. { return false; } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 63b585231f..dee4577d93 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -67,7 +67,7 @@ public: virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); virtual bool handleTimerEvent(LLWindow *window); - virtual bool handleDeviceChange(LLWindow *window); + virtual bool handleDeviceChange(LLWindow *window, bool deviceRemoved); // [FIRE-10419] Added deviceRemoved bool to prevent reinitialize on disconnect. virtual bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); virtual bool handleWindowDidChangeScreen(LLWindow *window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index c4a3674a4f..e707b06abf 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -579,7 +579,15 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Make an instance of our window then define the window class mhInstance = GetModuleHandle(NULL); + // [FIRE-10419] Add notification filters for device notifcations for HID device handling + DEV_BROADCAST_DEVICEINTERFACE notificationFilter; + ZeroMemory(¬ificationFilter, sizeof(notificationFilter)); + notificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + + HDEVNOTIFY deviceNotification = RegisterDeviceNotification(mWindowHandle, ¬ificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); + // // Init Direct Input - needed for joystick / Spacemouse LPDIRECTINPUT8 di8_interface; @@ -2291,6 +2299,24 @@ void LLWindowWin32::gatherInput() updateCursor(); } +// Define device classID for filtering +constexpr std::array classIDStrings = { + L"{745a17a0-74d3-11d0-b6fe-00a0c90f57da}", // Modern HID + L"{4d36e96c-e325-11ce-bfc1-08002be10318}", // Legacy/Serial + L"{a5dcbf10-6530-11d2-901f-00c04fb951ed}" // SpaceNavigator/Xbox +}; + +std::array deviceCLSIDWhitelist; + +// Convert to CLSID to make it easier +void initializeDeviceCLSIDArray() +{ + for (size_t i = 0; i < classIDStrings.size(); ++i) + { + CLSIDFromString(classIDStrings[i], &deviceCLSIDWhitelist[i]); + } +} + static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard"); static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse"); @@ -2349,13 +2375,42 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_DEVICECHANGE: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE"); - if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) - { - WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); - return 1; + // [FIRE-10419] Prevent all devices from being scanned on each change + // if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) + // { + // WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); + // return 1; + // } + + + // Only bother initalizing when needed. + if (deviceCLSIDWhitelist.empty()) + { + initializeDeviceCLSIDArray(); + } + + if (w_param == DBT_DEVICEARRIVAL || w_param == DBT_DEVICEREMOVECOMPLETE) + { + DEV_BROADCAST_HDR* dtype = (DEV_BROADCAST_HDR*)l_param; + if (dtype->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + { + DEV_BROADCAST_DEVICEINTERFACE* iface = (DEV_BROADCAST_DEVICEINTERFACE*)l_param; + + // Iterate through the CLSID whitelist for comparison and only fire if it's a useful device + for (const auto& guid : deviceCLSIDWhitelist) + { + if (memcmp(&iface->dbcc_classguid, &guid, sizeof(GUID)) == 0) + { + bool deviceRemoved = (w_param == DBT_DEVICEREMOVECOMPLETE); + WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp, deviceRemoved)); + break; + } + } + } } break; + // } case WM_PAINT: diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 030b01a6f3..b0792712c2 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1839,10 +1839,22 @@ bool LLViewerWindow::handleTimerEvent(LLWindow *window) return false; } -bool LLViewerWindow::handleDeviceChange(LLWindow *window) +// [FIRE-10419] Added deviceRemoved bool to prevent reinitialize on disconnect. +// bool LLViewerWindow::handleDeviceChange(LLWindow* window) +// { +// if (!LLViewerJoystick::getInstance()->isJoystickInitialized()) +// { +// LLViewerJoystick::getInstance()->init(true); +// return true; +// } +// return false; +// } +// + +bool LLViewerWindow::handleDeviceChange(LLWindow *window, bool deviceRemoved) { // give a chance to use a joystick after startup (hot-plugging) - if (!LLViewerJoystick::getInstance()->isJoystickInitialized() ) + if (!deviceRemoved && !LLViewerJoystick::getInstance()->isJoystickInitialized()) { LLViewerJoystick::getInstance()->init(true); return true; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index f63be5dbf1..1ddd41e547 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -225,7 +225,7 @@ public: /*virtual*/ void handleWindowUnblock(LLWindow *window); /*virtual*/ void handleDataCopy(LLWindow *window, S32 data_type, void *data); /*virtual*/ bool handleTimerEvent(LLWindow *window); - /*virtual*/ bool handleDeviceChange(LLWindow *window); + /*virtual*/ bool handleDeviceChange(LLWindow *window, bool deviceRemoved); // [FIRE-10419] Added deviceRemoved bool to prevent reinitialize on disconnect. /*virtual*/ bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); /*virtual*/ bool handleWindowDidChangeScreen(LLWindow *window);