From 3f7fc499fcee79b62d8c66fd1fa4208f764e96f3 Mon Sep 17 00:00:00 2001 From: Simon Hofmann Date: Mon, 18 Mar 2024 13:36:12 +0100 Subject: [PATCH 1/2] (NT-77) Improve focus window implementation on Windows to deal with focus stealing countermeasures on Windows --- src/win32/window_manager.cc | 42 +++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/win32/window_manager.cc b/src/win32/window_manager.cc index e37580e..6bb7a52 100644 --- a/src/win32/window_manager.cc +++ b/src/win32/window_manager.cc @@ -22,7 +22,7 @@ std::vector getWindows() { } WindowHandle getActiveWindow() { - HWND foregroundWindow = GetForegroundWindow(); + auto foregroundWindow = GetForegroundWindow(); if (IsWindow(foregroundWindow)) { return reinterpret_cast(foregroundWindow); } @@ -30,7 +30,7 @@ WindowHandle getActiveWindow() { } MMRect getWindowRect(const WindowHandle windowHandle) { - HWND hWnd = reinterpret_cast(windowHandle); + auto hWnd = reinterpret_cast(windowHandle); RECT windowRect; if (IsWindow(hWnd) && GetWindowRect(hWnd, &windowRect)) { return MMRectMake(windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top); @@ -39,13 +39,13 @@ MMRect getWindowRect(const WindowHandle windowHandle) { } std::string getWindowTitle(const WindowHandle windowHandle) { - HWND hWnd = reinterpret_cast(windowHandle); + auto hWnd = reinterpret_cast(windowHandle); if (IsWindow(hWnd)) { auto BUFFER_SIZE = GetWindowTextLength(hWnd) + 1; if (BUFFER_SIZE) { - LPSTR windowTitle = new CHAR[BUFFER_SIZE]; + auto windowTitle = new CHAR[BUFFER_SIZE]; if (GetWindowText(hWnd, windowTitle, BUFFER_SIZE)) { - return std::string(windowTitle); + return {windowTitle}; } } } @@ -53,32 +53,38 @@ std::string getWindowTitle(const WindowHandle windowHandle) { } bool focusWindow(const WindowHandle windowHandle) { - HWND hWnd = reinterpret_cast(windowHandle); + auto hWnd = reinterpret_cast(windowHandle); if (IsWindow(hWnd)) { // Restore the window if it's minimized if (IsIconic(hWnd)) { ShowWindow(hWnd, SW_RESTORE); } - + + auto processId = GetCurrentProcessId(); + // const auto allowSetForeground = AllowSetForegroundWindow(ASFW_ANY); + const auto allowSetForeground = AllowSetForegroundWindow(processId); + const auto setTopLevel = BringWindowToTop(hWnd); + const auto setForeground = SetForegroundWindow(hWnd); + // Try to set the window to the foreground - return SetForegroundWindow(hWnd); + return allowSetForeground && setTopLevel && setForeground; } return false; } bool resizeWindow(const WindowHandle windowHandle, const MMSize newSize) { - HWND hWnd = reinterpret_cast(windowHandle); + auto hWnd = reinterpret_cast(windowHandle); if (IsWindow(hWnd)) { //size - auto width = newSize.width; - auto height = newSize.height; + const auto width = newSize.width; + const auto height = newSize.height; RECT currentPosition; GetWindowRect(reinterpret_cast(windowHandle), ¤tPosition); //origin - auto x = currentPosition.left; - auto y = currentPosition.top; + const auto x = currentPosition.left; + const auto y = currentPosition.top; return MoveWindow(hWnd, x, y, width, height, TRUE); } @@ -86,18 +92,18 @@ bool resizeWindow(const WindowHandle windowHandle, const MMSize newSize) { } bool moveWindow(const WindowHandle windowHandle, const MMPoint newOrigin) { - HWND hWnd = reinterpret_cast(windowHandle); + auto hWnd = reinterpret_cast(windowHandle); if (IsWindow(hWnd)) { // origin - auto x = newOrigin.x; - auto y = newOrigin.y; + const auto x = newOrigin.x; + const auto y = newOrigin.y; RECT currentPosition; GetWindowRect(reinterpret_cast(windowHandle), ¤tPosition); // size - auto width = currentPosition.right - currentPosition.left; - auto height = currentPosition.bottom - currentPosition.top; + const auto width = currentPosition.right - currentPosition.left; + const auto height = currentPosition.bottom - currentPosition.top; return MoveWindow(hWnd, x, y, width, height, TRUE); } From 6d62a99626b4bed7a5a95cd07d074e1c2826c8d5 Mon Sep 17 00:00:00 2001 From: Simon Hofmann Date: Mon, 18 Mar 2024 18:41:20 +0100 Subject: [PATCH 2/2] (NT-77) Adjust focus test --- test/window-integration-tests/test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/window-integration-tests/test.js b/test/window-integration-tests/test.js index ddbe2e3..59eca03 100644 --- a/test/window-integration-tests/test.js +++ b/test/window-integration-tests/test.js @@ -103,10 +103,18 @@ describe("focusWindow", () => { // WHEN const secondApp = await electron.launch({args: ['second.js']}); const secondPage = await secondApp.firstWindow({timeout: APP_TIMEOUT}); + const handle = await secondApp.browserWindow(secondPage); + await secondPage.waitForLoadState("domcontentloaded"); + await handle.evaluate((win) => { + win.minimize(); + win.restore(); + win.focus(); + }); const result = libnut.focusWindow(openWindowHandle); // THEN + await sleep(1500); const activeWindowHandle = libnut.getActiveWindow(); const activeWindowName = libnut.getWindowTitle(activeWindowHandle); expect(activeWindowName).toBe(TITLE);