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