Processing Ajax...

Title

Message

Confirm

Confirm

Confirm

Confirm

Are you sure you want to delete this item?

Confirm

Are you sure you want to delete this item?

Focus and Highlight Topmost Window on Previous Monitor

Description
This script will switch focus to the topmost window on the previous monitor and highlight it for 5 seconds.
Language
C#.net
Minimum Version
Created By
Thomas Malloch (BFS)
Contributors
-
Date Created
Aug 7, 2018
Date Last Modified
Sep 14, 2018

Scripted Function (Macro) Code

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;

// The 'windowHandle' parameter will contain the window handle for the:
//   - Active window when run by hotkey
//   - Window Location target when run by a Window Location rule
//   - TitleBar Button owner when run by a TitleBar Button
//   - Jump List owner when run from a Taskbar Jump List
//   - Currently focused window if none of these match
public static class DisplayFusionFunction
{
	[DllImport("user32.dll", SetLastError = true)]
	private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
	
	//some constants
	const uint GW_HWNDNEXT = 2;
	
	public static void Run(IntPtr windowHandle)
	{
        // Get the current monitor ID
        uint currentMonitor = BFS.Monitor.GetMonitorIDByWindow(windowHandle);
        
        // Get all of the monitor IDs
        uint[] ids = BFS.Monitor.GetMonitorIDs();
        
        // Reverse the order of the ids
        Array.Reverse(ids);
        
        // Find where we are in the monitor ID array
        int index = -1;
        for(int i = 0; i < ids.Length; i++)
        {
            if(ids[i] != currentMonitor)
                continue;
                
            index = i;
            break;
        }
        
        // If we didn't find the index, exit the script
        if(index == -1)
            return;
            
        // Find the next monitor ID
        uint nextMonitorID = ids[++index % ids.Length];
        
        // Find the topmost window on the next monitor
        IntPtr window = GetTopmostWindowOnMonitor(nextMonitorID);
        
        // Focus the next window on the next monitor
        BFS.Window.Focus(window);
        
        // Highlight the window
        BFS.Window.SetWindowHighlight(window, Color.Blue);
                        
        // Move the mouse cursor to the center of the window
        BFS.DisplayFusion.RunFunction("Move Mouse Cursor to Center of Active Window");
        
        // Wait 1.5 seconds
        BFS.General.ThreadWait(1500);
        
        // Remove the highlight
        BFS.Window.RemoveWindowHighlight(window);
	}
	
	private static IntPtr GetTopmostWindowOnMonitor(uint id)
	{
        //get the visible window handles for that monitor
        HashSet<IntPtr> visibleWindows = new HashSet<IntPtr>( BFS.Window.GetVisibleWindowHandlesByMonitor(id) );
	
        //enumerate through the monitors, starting with the focused window, and moving down
		//only enumerate if we havn't found the windows yet
		for(IntPtr window = BFS.Window.GetFocusedWindow(); ; window = GetWindow(window, GW_HWNDNEXT))
		{
			//check to see if there are no windows left
			if(window == IntPtr.Zero)
				break;
				
            //check to see if the window is visible. if it's not, ignore it
			if(!visibleWindows.Contains(window))
                continue;
				
			//if it is a window we should ignore, ignore it
			if(IsDisplayFusionWindowOrHiddenExplorerWindow(window))
				continue;
			
			//get the monitor this window is in
			uint monitor = BFS.Monitor.GetMonitorIDByWindow(window);
			
			//if the monitor isn't in our collection, get the next window
			if(id != monitor)
				continue;
				
			return window;
		}
	
        //return IntPtr.Zero if we didn't find anything
        return IntPtr.Zero;
	}
	
	private static bool IsDisplayFusionWindowOrHiddenExplorerWindow(IntPtr window)
	{
        //ignore any DisplayFusion windows (title bar buttons, etc.)
        //ignore pesky hidden explorer.exe windows
        if((BFS.Window.GetClass(window).StartsWith("DF", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("EdgeUiInputTopWndClass", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("EdgeUiInputWndClass", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("NativeHWNDHost", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("ModeInputWnd", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("MetroGhostWindow", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("ImmersiveLauncher", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("ApplicationManager_ImmersiveShellWindow", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("Shell_TrayWnd", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("WorkerW", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("Progman", StringComparison.OrdinalIgnoreCase)) ||
            (BFS.Window.GetClass(window).Equals("SearchPane", StringComparison.OrdinalIgnoreCase)))
        {
            return true;
        }
        
        return false;
	}
}