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);