One of the most irritating thing in Windows is no way to prevent an application from stealing focus. There are multiple questions on Stack Overflow regarding the issue, there are rumors that Microsoft wanted to do something but they cannot detect it reliably. There are workarounds like ForegroundLockTimeout
but ultimately there is no good solution.
I had the the following problem problem — application X was constantly creating new instance of application Y (as desired) which in turn resulted in creating new window stealing focus and appearing on the screen. This is especially irritating when typing or when working using RDP since new window consumes some bandwidth which (especially painful over mobile connection).
Powershell hiding windows
You can use a powershell background script which would restore the focus if it was stole. Here is the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
Add-Type -AssemblyName System.Windows.Forms [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") $TypeDef = @" using System; using System.Text; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; namespace Api { public class ApiDef { [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll", SetLastError=true)] static extern IntPtr GetForegroundWindow(); private static string ReadText(IntPtr hWnd){ StringBuilder sb = new StringBuilder(256); int res = GetWindowText((IntPtr)hWnd, sb, 256); return sb.ToString(); } public static void Activate(){ var oldWindow = GetForegroundWindow(); while(true){ var foreground = GetForegroundWindow(); var text = ReadText(foreground).ToLower(); if(text.Contains("whatever title you like")){ SendKeys.SendWait("%{ESC}"); }else{ oldWindow = foreground; } Thread.Sleep(250); } } } } "@ Add-Type -TypeDefinition $TypeDef -Language CSharpVersion3 -ReferencedAssemblies @("System.Windows.Forms") [Api.Apidef]::Activate() |
Every 250 milliseconds I get the foreground window and check its title. If it is something which I know steals the focus then I send CTRL + ESC sequence which ultimately switches application back.
I tried doing SetWindowPos
or BringWindowToTop
orSetForegroundWindow
but none of those worked as expected. Finally I decided to go with the hotkey and it looks like this is good enough for me.
VirtuaWin
There is actually much easier solution for doing that. VirtuaWin can create multiple desktops and automatically move windows between them based on rules. Just capture the class or process name you want to move, configure rule and the window will be moved automatically.
Running in different session
You can open new session to the host (using MSTSC or Remote App Terminal Services) and then run application in that session. You won’t see its UI at all, however, it will run normally. You can do that using qwinsta
to get session id and then psexec.exe -i session_id app.exe
Creating new desktop
You can create new desktop using Sysinternals Desktops utility. Next, run application stealing focus in new desktop and it will not pop up on other desktops anymore.
I think desktop switcher in Windows 10 may be using the same API. If you are using it then you may look at Windows 10 virtual desktop enhancer to get some more shortcuts.
There is also Dexpot which I was using for many years and it is great. Just watch the license restrictions if you want to use it commercially.
See Pushing the limits and Understanding windows at a deeper level articles about this part of OS.