Skip to content

Instantly share code, notes, and snippets.

@mfic
Forked from JohnLBevan/MoveWindow.ps1
Last active July 10, 2024 07:15
Show Gist options
  • Select an option

  • Save mfic/81ade6524c8339c84d96a7926d17c33e to your computer and use it in GitHub Desktop.

Select an option

Save mfic/81ade6524c8339c84d96a7926d17c33e to your computer and use it in GitHub Desktop.

Revisions

  1. mfic revised this gist Jul 10, 2024. 1 changed file with 53 additions and 77 deletions.
    130 changes: 53 additions & 77 deletions MoveWindow.ps1
    Original file line number Diff line number Diff line change
    @@ -1,109 +1,85 @@
    <#
    Originally coded to move the window to where the mouse cursor is; most code left
    However, due to issues this only moves the window to the top left corner of it's parent container
    That's good enough for my scenario; i.e. puts the window back on screen.
    #>

    # Embed the C# code in PowerShell
    # Fork from: https://gist.github.com/JohnLBevan/1593bbb860c2d2af436a1c9414e8adfa
    Add-Type @"
    using System;
    using System.Runtime.InteropServices;
    using System;
    using System.Runtime.InteropServices;
    // https://msdn.microsoft.com/en-us/library/windows/desktop/dd162805(v=vs.85).aspx
    public struct POINT
    public class WindowMover
    {
    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
    public long x;
    public long y;
    public int x;
    public int y;
    }
    // https://msdn.microsoft.com/en-us/library/windows/desktop/dd162897(v=vs.85).aspx
    public struct RECT
    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
    public long left;
    public long top;
    public long right;
    public long bottom;
    public int left;
    public int top;
    public int right;
    public int bottom;
    }
    public class User32WinApi
    public class User32
    {
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms648390(v=vs.85).aspx
    /*
    Gets the coordinates of the mouse cursor
    (I've not added logic for other "remote desktop" or similar support; see above link for notes on OpenInputDesktop if that's required for your scenario
    */
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetCursorPos(out POINT lpPoint);
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms633505(v=vs.85).aspx
    /*
    Gets the handle of the in-focus window
    NB: In some scenarios this can be NULL; so code needed to handle such an event
    */
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms633519(v=vs.85).aspx
    /*
    Gets the coordinates of the rectangle relative to the top left corner of the screen.
    NB: bottom right is 1 pixed beyond the bottom right boundary of the shape; i.e. defines the border, not the filled area.
    */
    /* no need to find the before or after positions; let's just assume it works
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    */
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms633503(v=vs.85).aspx
    /*
    top & left are always 0 (i.e. since the rectangle is relative to the window itself)
    bottom & right equal the windows hieght and width, respectively.
    */
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms633534(v=vs.85).aspx
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
    }
    "@
    $repaint = $true #presumably it's best to always repaint the window after a move, just in case being offscreen blanked it in some way / something like that?
    $positionOfCursor = New-Object POINT
    $windowSize = New-Object RECT
    public static void MoveActiveWindowToCursor()
    {
    POINT cursorPos;
    if (!User32.GetCursorPos(out cursorPos))
    {
    throw new Exception("Failed to get cursor position.");
    }
    "Quick; get the window in question in focus, then put your mouse in position!"
    Start-Sleep -Seconds 5 #allow 5 seconds for the user to get the window they're after in focus (e.g. using ALT+TAB / whatever), and move their mouse to the required positoin
    $activeWindow = [User32WinApi]::GetForegroundWindow()
    if ($activeWindow) {
    if([User32WinApi]::GetCursorPos([ref]$positionOfCursor)) {
    if([User32WinApi]::GetClientRect($activeWindow, [ref]$windowSize)) {
    $Name = @((Get-Process | ?{$_.MainWindowHandle -eq $activeWindow } | select -ExpandProperty MainWindowTitle),"No Name Found for Handle $activeWindow" -ne $null)[0]
    "Moving window for $Name to Mouse Cursor Position ($($positionOfCursor.x), $($positionOfCursor.y))"

    #have replaced `$positionOfCursor.x, $positionOfCursor.y` with `0, 0` as having issues converting long values to ints as returned values are out of range
    #this works for my scenario; just aligns the window with its parent's top left corner
    if ([User32WinApi]::MoveWindow($activeWindow, 0, 0, $windowSize.right, $windowSize.bottom, $repaint)) {
    "Window moved successfully (hope you agree!)"
    } else {
    Write-Warning "Failed to move the window"
    }
    } else {
    Write-Warning "Failed to get size of the active window"
    IntPtr hWnd = User32.GetForegroundWindow();
    if (hWnd == IntPtr.Zero)
    {
    throw new Exception("No active window found.");
    }
    } else {
    Write-Warning "Failed to get position of cursor"
    }
    } else {
    Write-Warning "No active window found"
    }
    RECT windowRect;
    if (!User32.GetClientRect(hWnd, out windowRect))
    {
    throw new Exception("Failed to get window size.");
    }
    int width = windowRect.right;
    int height = windowRect.bottom;
    if (!User32.MoveWindow(hWnd, cursorPos.x, cursorPos.y, width, height, true))
    {
    throw new Exception("Failed to move the window.");
    }
    }
    }
    "@

    # Allow some time to focus the window and move the cursor
    Write-Output "Quick; get the window in question in focus, then put your mouse in position!"
    Start-Sleep -Seconds 5

    # Call the C# method to move the window
    try {
    [WindowMover]::MoveActiveWindowToCursor()
    Write-Output "Window moved successfully (hope you agree!)"
    }
    catch {
    Write-Warning $_.Exception.Message
    }
  2. @JohnLBevan JohnLBevan created this gist Jun 20, 2017.
    109 changes: 109 additions & 0 deletions MoveWindow.ps1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,109 @@
    <#
    Originally coded to move the window to where the mouse cursor is; most code left
    However, due to issues this only moves the window to the top left corner of it's parent container
    That's good enough for my scenario; i.e. puts the window back on screen.
    #>

    Add-Type @"
    using System;
    using System.Runtime.InteropServices;
    // https://msdn.microsoft.com/en-us/library/windows/desktop/dd162805(v=vs.85).aspx
    public struct POINT
    {
    public long x;
    public long y;
    }
    // https://msdn.microsoft.com/en-us/library/windows/desktop/dd162897(v=vs.85).aspx
    public struct RECT
    {
    public long left;
    public long top;
    public long right;
    public long bottom;
    }
    public class User32WinApi
    {
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms648390(v=vs.85).aspx
    /*
    Gets the coordinates of the mouse cursor
    (I've not added logic for other "remote desktop" or similar support; see above link for notes on OpenInputDesktop if that's required for your scenario
    */
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetCursorPos(out POINT lpPoint);
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms633505(v=vs.85).aspx
    /*
    Gets the handle of the in-focus window
    NB: In some scenarios this can be NULL; so code needed to handle such an event
    */
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms633519(v=vs.85).aspx
    /*
    Gets the coordinates of the rectangle relative to the top left corner of the screen.
    NB: bottom right is 1 pixed beyond the bottom right boundary of the shape; i.e. defines the border, not the filled area.
    */
    /* no need to find the before or after positions; let's just assume it works
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    */
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms633503(v=vs.85).aspx
    /*
    top & left are always 0 (i.e. since the rectangle is relative to the window itself)
    bottom & right equal the windows hieght and width, respectively.
    */
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms633534(v=vs.85).aspx
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
    }
    "@
    $repaint = $true #presumably it's best to always repaint the window after a move, just in case being offscreen blanked it in some way / something like that?
    $positionOfCursor = New-Object POINT
    $windowSize = New-Object RECT

    "Quick; get the window in question in focus, then put your mouse in position!"
    Start-Sleep -Seconds 5 #allow 5 seconds for the user to get the window they're after in focus (e.g. using ALT+TAB / whatever), and move their mouse to the required positoin
    $activeWindow = [User32WinApi]::GetForegroundWindow()
    if ($activeWindow) {
    if([User32WinApi]::GetCursorPos([ref]$positionOfCursor)) {
    if([User32WinApi]::GetClientRect($activeWindow, [ref]$windowSize)) {
    $Name = @((Get-Process | ?{$_.MainWindowHandle -eq $activeWindow } | select -ExpandProperty MainWindowTitle),"No Name Found for Handle $activeWindow" -ne $null)[0]
    "Moving window for $Name to Mouse Cursor Position ($($positionOfCursor.x), $($positionOfCursor.y))"

    #have replaced `$positionOfCursor.x, $positionOfCursor.y` with `0, 0` as having issues converting long values to ints as returned values are out of range
    #this works for my scenario; just aligns the window with its parent's top left corner
    if ([User32WinApi]::MoveWindow($activeWindow, 0, 0, $windowSize.right, $windowSize.bottom, $repaint)) {
    "Window moved successfully (hope you agree!)"
    } else {
    Write-Warning "Failed to move the window"
    }
    } else {
    Write-Warning "Failed to get size of the active window"
    }
    } else {
    Write-Warning "Failed to get position of cursor"
    }
    } else {
    Write-Warning "No active window found"
    }