[Refactor]Use same improved BringToForeground across the solution (#28532)

* Use single BringToForeground across the solution

* Close flyout manually

* Try with sending input, if it fails try threads
This commit is contained in:
Stefan Markovic
2023-10-23 18:16:11 +02:00
committed by GitHub
parent f718bef45c
commit 6a092548b1
13 changed files with 95 additions and 109 deletions

View File

@@ -38,5 +38,67 @@ namespace ManagedCommon
[DllImport("user32.dll")]
internal static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
internal INPUTTYPE type;
internal InputUnion data;
internal static int Size
{
get { return Marshal.SizeOf(typeof(INPUT)); }
}
}
[StructLayout(LayoutKind.Explicit)]
internal 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;
}
internal enum INPUTTYPE : uint
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2,
}
}
}

View File

@@ -10,20 +10,29 @@ namespace ManagedCommon
{
public static void BringToForeground(IntPtr handle)
{
NativeMethods.INPUT input = new NativeMethods.INPUT { type = NativeMethods.INPUTTYPE.INPUT_MOUSE, data = { } };
NativeMethods.INPUT[] inputs = new NativeMethods.INPUT[] { input };
_ = NativeMethods.SendInput(1, inputs, NativeMethods.INPUT.Size);
NativeMethods.SetForegroundWindow(handle);
var fgHandle = NativeMethods.GetForegroundWindow();
var threadId1 = NativeMethods.GetWindowThreadProcessId(handle, System.IntPtr.Zero);
var threadId2 = NativeMethods.GetWindowThreadProcessId(fgHandle, System.IntPtr.Zero);
if (fgHandle != handle)
{
var threadId1 = NativeMethods.GetWindowThreadProcessId(handle, System.IntPtr.Zero);
var threadId2 = NativeMethods.GetWindowThreadProcessId(fgHandle, System.IntPtr.Zero);
if (threadId1 != threadId2)
{
NativeMethods.AttachThreadInput(threadId1, threadId2, true);
NativeMethods.SetForegroundWindow(handle);
NativeMethods.AttachThreadInput(threadId1, threadId2, false);
}
else
{
NativeMethods.SetForegroundWindow(handle);
if (threadId1 != threadId2)
{
NativeMethods.AttachThreadInput(threadId1, threadId2, true);
NativeMethods.SetForegroundWindow(handle);
NativeMethods.AttachThreadInput(threadId1, threadId2, false);
}
else
{
NativeMethods.SetForegroundWindow(handle);
}
}
}
}

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Hosts.Helpers;
using ManagedCommon;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using WinUIEx;
@@ -25,7 +26,7 @@ namespace Hosts
AppTitleTextBlock.Text = title;
var handle = this.GetWindowHandle();
ManagedCommon.WindowHelpers.BringToForeground(handle);
WindowHelpers.BringToForeground(handle);
Activated += MainWindow_Activated;
}

View File

@@ -10,6 +10,7 @@ using ImageResizer.Properties;
using ImageResizer.Utilities;
using ImageResizer.ViewModels;
using ImageResizer.Views;
using ManagedCommon;
namespace ImageResizer
{
@@ -41,15 +42,7 @@ namespace ImageResizer
mainWindow.Show();
// Temporary workaround for issue #1273
BecomeForegroundWindow(new System.Windows.Interop.WindowInteropHelper(mainWindow).Handle);
}
private static void BecomeForegroundWindow(IntPtr hWnd)
{
NativeMethods.INPUT input = new NativeMethods.INPUT { type = NativeMethods.INPUTTYPE.INPUT_MOUSE, data = { } };
NativeMethods.INPUT[] inputs = new NativeMethods.INPUT[] { input };
_ = NativeMethods.SendInput(1, inputs, NativeMethods.INPUT.Size);
NativeMethods.SetForegroundWindow(hWnd);
WindowHelpers.BringToForeground(new System.Windows.Interop.WindowInteropHelper(mainWindow).Handle);
}
public void Dispose()

View File

@@ -15,69 +15,7 @@ namespace ImageResizer.Utilities
[DllImport("user32.dll")]
internal static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool SetProcessDPIAware();
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
internal INPUTTYPE type;
internal InputUnion data;
internal static int Size
{
get { return Marshal.SizeOf(typeof(INPUT)); }
}
}
[StructLayout(LayoutKind.Explicit)]
internal 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;
}
internal enum INPUTTYPE : uint
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2,
}
}
}

View File

@@ -22,19 +22,6 @@ namespace Peek.UI.Extensions
return hwnd.GetMonitorScale();
}
public static void BringToForeground(this Window window)
{
// Ability to be able to set the Window to the Foreground is very limited. A current workaround is simulating mouse input before bringing to the foreground.
var windowHandle = window.GetWindowHandle();
Windows.Win32.UI.Input.KeyboardAndMouse.INPUT input = new Windows.Win32.UI.Input.KeyboardAndMouse.INPUT { type = Windows.Win32.UI.Input.KeyboardAndMouse.INPUT_TYPE.INPUT_MOUSE, Anonymous = { } };
Windows.Win32.UI.Input.KeyboardAndMouse.INPUT[] inputs = new Windows.Win32.UI.Input.KeyboardAndMouse.INPUT[] { input };
_ = PInvoke.SendInput(inputs.AsSpan<Windows.Win32.UI.Input.KeyboardAndMouse.INPUT>(), Marshal.SizeOf(typeof(Windows.Win32.UI.Input.KeyboardAndMouse.INPUT)));
if (PInvoke.SetForegroundWindow(new HWND(windowHandle)) == 0)
{
Logger.LogWarning("Couldn't set the Peek window as the foreground window.");
}
}
internal static void CenterOnMonitor(this Window window, HWND hwndDesktop, double? width = null, double? height = null)
{
var hwndToCenter = new HWND(window.GetWindowHandle());

View File

@@ -4,7 +4,6 @@ GetDpiForWindow
GetForegroundWindow
SetForegroundWindow
SetActiveWindow
SendInput
GetWindowThreadProcessId
GetCurrentThreadId
AttachThreadInput

View File

@@ -184,7 +184,7 @@ namespace Peek.UI
}
this.Show();
this.BringToForeground();
WindowHelpers.BringToForeground(this.GetWindowHandle());
}
private Size GetMonitorMaxContentSize(Size monitorSize, double scaling)

View File

@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using ManagedCommon;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
@@ -98,7 +99,7 @@ namespace RegistryPreview
UpdateWindowTitle(resourceLoader.GetString("FileNotFound"));
}
ManagedCommon.WindowHelpers.BringToForeground(windowHandle);
WindowHelpers.BringToForeground(windowHandle);
}
private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)

View File

@@ -45,13 +45,5 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
{
}
}
public static void BecomeForegroundWindow(IntPtr hWnd)
{
NativeKeyboardHelper.INPUT input = new NativeKeyboardHelper.INPUT { type = NativeKeyboardHelper.INPUTTYPE.INPUT_MOUSE, data = { } };
NativeKeyboardHelper.INPUT[] inputs = new NativeKeyboardHelper.INPUT[] { input };
_ = NativeMethods.SendInput(1, inputs, NativeKeyboardHelper.INPUT.Size);
NativeMethods.SetForegroundWindow(hWnd);
}
}
}

View File

@@ -170,7 +170,7 @@ namespace Microsoft.PowerToys.Settings.UI
// https://github.com/microsoft/microsoft-ui-xaml/issues/7595 - Activate doesn't bring window to the foreground
// Need to call SetForegroundWindow to actually gain focus.
Utils.BecomeForegroundWindow(settingsWindow.GetWindowHandle());
WindowHelpers.BringToForeground(settingsWindow.GetWindowHandle());
}
else
{

View File

@@ -33,6 +33,10 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
{
FlyoutMenuButton selectedModuleBtn = sender as FlyoutMenuButton;
bool moduleRun = true;
// Closing manually the flyout to workaround focus gain problems
App.GetFlyoutWindow()?.Hide();
switch ((string)selectedModuleBtn.Tag)
{
case "ColorPicker": // Launch ColorPicker

View File

@@ -205,7 +205,7 @@ namespace Microsoft.PowerToys.Settings.UI
// https://github.com/microsoft/microsoft-ui-xaml/issues/7595 - Activate doesn't bring window to the foreground
// Need to call SetForegroundWindow to actually gain focus.
Utils.BecomeForegroundWindow(flyout.GetWindowHandle());
WindowHelpers.BringToForeground(flyout.GetWindowHandle());
});
});