From af98395e25f74d45da8f85dd07342faf60bc8091 Mon Sep 17 00:00:00 2001 From: Taras <109293326+taras-janea@users.noreply.github.com> Date: Sun, 16 Oct 2022 18:29:37 +0300 Subject: [PATCH] [TextExtractor] Fix focus on overlay on the first activation (#21098) * TextExtractor-20950: fix focus on overlay on the first TextExtractor activation * TextExtractor-20950: fix typo --- .../PowerOCR/PowerOCR/Helpers/OSInterop.cs | 14 ++++- .../PowerOCR/Helpers/WindowUtilities.cs | 52 ++++++++----------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/modules/PowerOCR/PowerOCR/Helpers/OSInterop.cs b/src/modules/PowerOCR/PowerOCR/Helpers/OSInterop.cs index ee26e14f4c..8c44c99a66 100644 --- a/src/modules/PowerOCR/PowerOCR/Helpers/OSInterop.cs +++ b/src/modules/PowerOCR/PowerOCR/Helpers/OSInterop.cs @@ -69,8 +69,20 @@ public static class OSInterop internal static extern short GetAsyncKeyState(int vKey); public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); -#pragma warning restore CA1401 // P/Invokes should not be visible + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr SetForegroundWindow(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll")] + public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId); + + [DllImport("user32.dll")] + public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach); + +#pragma warning restore CA1401 // P/Invokes should not be visible [StructLayout(LayoutKind.Sequential)] internal struct LowLevelKeyboardInputEvent { diff --git a/src/modules/PowerOCR/PowerOCR/Helpers/WindowUtilities.cs b/src/modules/PowerOCR/PowerOCR/Helpers/WindowUtilities.cs index d8a75e76c8..d4301defc5 100644 --- a/src/modules/PowerOCR/PowerOCR/Helpers/WindowUtilities.cs +++ b/src/modules/PowerOCR/PowerOCR/Helpers/WindowUtilities.cs @@ -2,7 +2,6 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Windows; using System.Windows.Forms; using Microsoft.PowerToys.Telemetry; @@ -16,36 +15,12 @@ public static class WindowUtilities { if (IsOCROverlayCreated()) { - Logger.LogWarning("Tired to launch the overlay but it was already created."); + Logger.LogWarning("Tried to launch the overlay, but it has been already created."); return; } - Screen[] allScreens = Screen.AllScreens; - WindowCollection allWindows = System.Windows.Application.Current.Windows; - - List allFullscreenGrab = new List(); - - foreach (Screen screen in allScreens) + foreach (Screen screen in Screen.AllScreens) { - bool screenHasWindow = true; - - foreach (Window window in allWindows) - { - System.Drawing.Point windowCenter = - new System.Drawing.Point( - (int)(window.Left + (window.Width / 2)), - (int)(window.Top + (window.Height / 2))); - screenHasWindow = screen.Bounds.Contains(windowCenter); - - // if (window is EditTextWindow) - // isEditWindowOpen = true; - } - - if (allWindows.Count < 1) - { - screenHasWindow = false; - } - OCROverlay overlay = new OCROverlay() { WindowStartupLocation = WindowStartupLocation.Manual, @@ -73,8 +48,7 @@ public static class WindowUtilities } overlay.Show(); - overlay.Activate(); - allFullscreenGrab.Add(overlay); + ActivateWindow(overlay); } PowerToysTelemetry.Log.WriteEvent(new PowerOCR.Telemetry.PowerOCRInvokedEvent()); @@ -110,4 +84,24 @@ public static class WindowUtilities // TODO: Decide when to close the process // System.Windows.Application.Current.Shutdown(); } + + public static void ActivateWindow(Window window) + { + var handle = new System.Windows.Interop.WindowInteropHelper(window).Handle; + var fgHandle = OSInterop.GetForegroundWindow(); + + var threadId1 = OSInterop.GetWindowThreadProcessId(handle, System.IntPtr.Zero); + var threadId2 = OSInterop.GetWindowThreadProcessId(fgHandle, System.IntPtr.Zero); + + if (threadId1 != threadId2) + { + OSInterop.AttachThreadInput(threadId1, threadId2, true); + OSInterop.SetForegroundWindow(handle); + OSInterop.AttachThreadInput(threadId1, threadId2, false); + } + else + { + OSInterop.SetForegroundWindow(handle); + } + } }