From 720fad80c3029f00f01e39563a33269b66af22a5 Mon Sep 17 00:00:00 2001 From: Arjun Balgovind <32061677+arjunbalgovind@users.noreply.github.com> Date: Mon, 22 Jun 2020 14:47:33 -0700 Subject: [PATCH] Fix Launcher focus for most cases (#4362) * Add SendInput hack * Cleaned up code * Fixed formatting * Moved Activate fn call * Add more comments with link to issue --- .../launcher/PowerLauncher/MainWindow.xaml.cs | 17 ++++- .../Wox/Helper/WindowsInteropHelper.cs | 62 +++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs index 67e3df34f4..988391a5f1 100644 --- a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs +++ b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs @@ -64,6 +64,17 @@ namespace PowerLauncher _viewModel.Save(); } + private void BringProcessToForeground() + { + // Use SendInput hack to allow Activate to work - required to resolve focus issue https://github.com/microsoft/PowerToys/issues/4270 + WindowsInteropHelper.INPUT input = new WindowsInteropHelper.INPUT { type = WindowsInteropHelper.INPUTTYPE.INPUT_MOUSE, data = { } }; + WindowsInteropHelper.INPUT[] inputs = new WindowsInteropHelper.INPUT[] { input }; + + // Send empty mouse event. This makes this thread the last to send input, and hence allows it to pass foreground permission checks + WindowsInteropHelper.SendInput(1, inputs, WindowsInteropHelper.INPUT.Size); + Activate(); + } + private void OnLoaded(object sender, RoutedEventArgs _) { WindowsInteropHelper.DisableControlBox(this); @@ -79,7 +90,7 @@ namespace PowerLauncher ListBox.SuggestionsList.PreviewMouseLeftButtonUp += SuggestionsList_PreviewMouseLeftButtonUp; _viewModel.PropertyChanged += ViewModel_PropertyChanged; - Activate(); + BringProcessToForeground(); } private void SuggestionsList_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) @@ -105,7 +116,7 @@ namespace PowerLauncher // Not called on first launch // Additionally called when deactivated by clicking on screen UpdatePosition(); - Activate(); + BringProcessToForeground(); if (!_viewModel.LastQuerySelected) { @@ -346,4 +357,4 @@ namespace PowerLauncher Hide(); } } -} +} diff --git a/src/modules/launcher/Wox/Helper/WindowsInteropHelper.cs b/src/modules/launcher/Wox/Helper/WindowsInteropHelper.cs index 462047886d..f4edf5c56d 100644 --- a/src/modules/launcher/Wox/Helper/WindowsInteropHelper.cs +++ b/src/modules/launcher/Wox/Helper/WindowsInteropHelper.cs @@ -34,6 +34,68 @@ namespace Wox.Helper } } + [DllImport("user32.dll")] + public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); + + [StructLayout(LayoutKind.Sequential)] + public struct INPUT + { + public INPUTTYPE type; + public InputUnion data; + + public static int Size + { + get { return Marshal.SizeOf(typeof(INPUT)); } + } + } + + [StructLayout(LayoutKind.Explicit)] + public struct InputUnion + { + [FieldOffset(0)] + internal MOUSEINPUT mi; + [FieldOffset(0)] + internal KEYBDINPUT ki; + [FieldOffset(0)] + internal HARDWAREINPUT hi; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MOUSEINPUT + { + internal int dx; + internal int dy; + internal int mouseData; + internal uint dwFlags; + internal uint time; + internal UIntPtr dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct KEYBDINPUT + { + internal short wVk; + internal short wScan; + internal uint dwFlags; + internal int time; + internal UIntPtr dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HARDWAREINPUT + { + internal int uMsg; + internal short wParamL; + internal short wParamH; + } + + public enum INPUTTYPE : uint + { + INPUT_MOUSE = 0, + INPUT_KEYBOARD = 1, + INPUT_HARDWARE = 2, + } + [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowLong(IntPtr hWnd, int nIndex);