How can I prevent theft of focus, but still get focus when returning to my application using Alt + Tab?

Following MS recommendations, my WPF App App Designer contains the following code for proper focus behavior:

HwndSource.DefaultAcquireHwndFocusInMenuMode = false; Keyboard.DefaultRestoreFocusMode = RestoreFocusMode.None; 

As explained in this article , these settings prevent theft of focus.

However, setting DefaultRestoreFocusMode to None has a bad side effect. When using Alt + Tab to leave a WPF application and then return to it, the WPF application does not receive focus. However, if I did not set DefaultRestoreFocusMode to zero, it will receive focus as expected. Is there a way to prevent focus, but focus is still set when returning to a WPF application via Alt + Tab?

-Craig

+7
source share
1 answer

I do not allow my wpf window to get focus by doing below, and I can still activate it using ALT-TAB or by clicking on it with a taskbar item.

Here you change the window styles in your window so that it does not activate.

 var yourWindow = new YourWindowType(); //set the windowstyle to noactivate so the window doesn't get focus yourWindow.SourceInitialized += (s, e) => { var interopHelper = new WindowInteropHelper(yourWindow); int exStyle = User32.GetWindowLong(interopHelper.Handle, (int)WindowLongFlags.GWL_EXSTYLE); User32.SetWindowLong(interopHelper.Handle, (int)WindowLongFlags.GWL_EXSTYLE, exStyle | (int)WindowStylesEx.WS_EX_NOACTIVATE); //If you have trouble typing into your form textboxes then do this ElementHost.EnableModelessKeyboardInterop(yourWindow); }; 

This is what I added as an extra precaution, plus it allows you to drag your window if it is borderless:

 private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { //don't activate the window when you click on it. case WindowMessage.WM_MOUSEACTIVATE: handled = true; return (IntPtr)MouseActivate.MA_NOACTIVATE; //For Borderless Windows: occurs while dragging. it reports new position before it has been finalized. //otherwise you wont see the window moving while you're dragging it case WindowMessage.WM_MOVING: RECT rect = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT)); User32.SetWindowPos(new WindowInteropHelper(this).Handle, Hwnd.HWND_TOPMOST, rect.Left, rect.Top, rect.Width, rect.Height, SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOSIZE); break; } return IntPtr.Zero; } 

They add a hook so that WndProc is actually called in WPF:

 private void Window_Loaded(object sender, RoutedEventArgs e) { HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); if (source == null) return; source.AddHook(WndProc); } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); if (source == null) return; source.RemoveHook(WndProc); } 

Just FYI .. this still works, even if you don't focus:

  private void WpfPillForm_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { this.DragMove(); } 

Here's the Win32 API declarations, so you don't need to look for them:

  [StructLayout(LayoutKind.Sequential)] public struct WINDOWPOS { public IntPtr hwnd; public IntPtr hwndInsertAfter; public int x; public int y; public int cx; public int cy; public int flags; } [StructLayout(LayoutKind.Sequential)] struct RECT { public int left, top, right, bottom; } public static class MouseActivate { public const int MA_ACTIVATE = 1; public const int MA_ACTIVATEANDEAT = 2; public const int MA_NOACTIVATE = 3; public const int MA_NOACTIVATEANDEAT = 4; } public enum WindowLongFlags : int { GWL_EXSTYLE = -20, GWLP_HINSTANCE = -6, GWLP_HWNDPARENT = -8, GWL_ID = -12, GWL_STYLE = -16, GWL_USERDATA = -21, GWL_WNDPROC = -4, DWLP_USER = 0x8, DWLP_MSGRESULT = 0x0, DWLP_DLGPROC = 0x4 } public const int WM_MOVING = 0x0216; public const uint WS_EX_NOACTIVATE = 0x08000000, [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern int GetWindowLong(IntPtr hwnd, int index); 
+2
source

All Articles