Center Window and Move Window (yet more Powershell hybrids)

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Center Window and Move Window (yet more Powershell hybrids)

#1 Post by aGerman » 06 Sep 2018 13:44

Center Window:

Code: Select all

@echo off &setlocal
mode con cols=50 lines=20

call :init_Center

for /l %%i in () do (
  %Center% middle
  %Center% left
  %Center% right
  %Center% top
  %Center% bottom
)

goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:init_Center
setlocal DisableDelayedExpansion
:: prefer PowerShell Core if installed
for %%i in ("pwsh.exe") do if "%%~$PATH:i"=="" (set "ps=powershell") else set "ps=pwsh"

:: - BRIEF -
::  Center the console window.
:: - SYNTAX -
::  %center% middle|left|top|right|bottom [pid]
::    middle|left|top|right|bottom  either of them specifies the position where
::                                   to center the window on the monitor
::    pid                           (optional) ID of a process whose main window
::                                   is to be centered 
:: - EXAMPLES -
::  Place the window in the middle of the monitor:
::    %Center%
::  Place the window in the middle of the top of the monitor:
::    %Center% top
set Center=for %%- in (1 2) do if %%-==2 (for /f "tokens=1,2" %%. in ("^^!arg^^! x") do^
%=% %ps%.exe -nop -ep Bypass -c ^"^
%===% $w=Add-Type -Name WAPI -PassThru -MemberDefinition '^
%=====% [DllImport(\"user32.dll\")]^
%=======% public static extern void SetProcessDPIAware();^
%=====% [DllImport(\"shcore.dll\")]^
%=======% public static extern void SetProcessDpiAwareness(int value);^
%=====% [DllImport(\"kernel32.dll\")]^
%=======% public static extern IntPtr GetConsoleWindow();^
%=====% [DllImport(\"user32.dll\")]^
%=======% public static extern void GetWindowRect(IntPtr hwnd, int[] rect);^
%=====% [DllImport(\"user32.dll\")]^
%=======% public static extern void GetClientRect(IntPtr hwnd, int[] rect);^
%=====% [DllImport(\"user32.dll\")]^
%=======% public static extern void GetMonitorInfoW(IntPtr hMonitor, int[] lpmi);^
%=====% [DllImport(\"user32.dll\")]^
%=======% public static extern IntPtr MonitorFromWindow(IntPtr hwnd, int dwFlags);^
%=====% [DllImport(\"user32.dll\")]^
%=======% public static extern int SetWindowPos(IntPtr hwnd, IntPtr hwndAfterZ, int x, int y, int w, int h, int flags);^
%===% ';^
%===% $PROCESS_PER_MONITOR_DPI_AWARE=2;^
%===% try {$w::SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE)} catch {$w::SetProcessDPIAware()}^
%===% $tpid=0;^
%===% if ([Int32]::TryParse('%%~/', [ref]$tpid)) {^
%=====% $hwnd=(gps -id $tpid -ea SilentlyContinue).MainWindowHandle;^
%===% } else {^
%=====% $hwnd=$w::GetConsoleWindow();^
%===% }^
%===   The $moninf array is a replacement for the MONITORINFO structure. The elements at index         =% ^
%===   5, 6, 7, and 8 represent left, top, right, and bottom boundaries of the monitor's work space.   =% ^
%===% $moninf=[int[]]::new(10);^
%===% $moninf[0]=40;^
%===% $MONITOR_DEFAULTTONEAREST=2;^
%===% $w::GetMonitorInfoW($w::MonitorFromWindow($hwnd, $MONITOR_DEFAULTTONEAREST), $moninf);^
%===% $monwidth=$moninf[7] - $moninf[5];^
%===% $monheight=$moninf[8] - $moninf[6];^
%===   The $wrect array is a replacement for the RECT structure. The elements at index   =% ^
%===   0, 1, 2, and 3 represent left, top, right, and bottom boundaries of the window.   =% ^
%===% $wrect=[int[]]::new(4);^
%===% $w::GetWindowRect($hwnd, $wrect);^
%===% $winwidth=$wrect[2] - $wrect[0];^
%===% $winheight=$wrect[3] - $wrect[1];^
%===% $x=0; $y=0;^
%===% if ('%%~.' -eq 'middle') {^
%=====% $x=[int][math]::Round($moninf[5] + $monwidth / 2 - $winwidth / 2);^
%=====% $y=[int][math]::Round($moninf[6] + $monheight / 2 - $winheight / 2);^
%===% } elseif ('%%~.' -eq 'left') {^
%=====% $x=$moninf[5];^
%=====% $y=[int][math]::Round($moninf[6] + $monheight / 2 - $winheight / 2);^
%===% } elseif ('%%~.' -eq 'top') {^
%=====% $x=[int][math]::Round($moninf[5] + $monwidth / 2 - $winwidth / 2);^
%=====% $y=$moninf[6];^
%===% } elseif ('%%~.' -eq 'right') {^
%=====% $x=$moninf[7] - $winwidth;^
%=====% $y=[int][math]::Round($moninf[6] + $monheight / 2 - $winheight / 2);^
%===% } elseif ('%%~.' -eq 'bottom') {^
%=====% $x=[int][math]::Round($moninf[5] + $monwidth / 2 - $winwidth / 2);^
%=====% $y=$moninf[8] - $winheight;^
%===% } else {exit 1}^
%===% $SWP_NOSIZE=0x0001;^
%===% $SWP_NOZORDER=0x0004;^
%===% exit [int]($w::SetWindowPos($hwnd, [IntPtr]::Zero, $x, $y, 0, 0, $SWP_NOSIZE -bOr $SWP_NOZORDER) -eq 0);^
%=% ^" ^&endlocal) else setlocal EnableDelayedExpansion ^&set arg=

endlocal &set "Center=%Center%"
if !!# neq # set "Center=%Center:^^=%"
exit /b
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Press [Ctrl]+[C] if you can't catch the red X :lol:

~~~~~~~~~~~~~~~~~~~~~~~~~~~
Move Window:

Code: Select all

@echo off &setlocal

call :init_MoveWindow
%MoveWindow% 100 50
echo %errorlevel%

pause
exit /b


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:init_MoveWindow
setlocal DisableDelayedExpansion
:: prefer PowerShell Core if installed
for %%i in ("pwsh.exe") do if "%%~$PATH:i"=="" (set "ps=powershell") else set "ps=pwsh"

:: - BRIEF -
::  Move the window to a certain position on the virtual screen.
:: - SYNTAX -
::  %MoveWindow% X Y [pid]
::    X    left side of the window on the screen in dots
::    Y    top of the window on the screen in dots
::    pid  (optional) ID of a process whose main window is to be moved
:: - EXAMPLES -
::  Move the left side of the window to position 100, and its top to position 50:
::    %MoveWindow% 100 50
set MoveWindow=for %%- in (1 2) do if %%-==2 (for /f "tokens=1-3" %%. in ("^^!args^^! x x x") do^
%=% %ps%.exe -nop -ep Bypass -c ^"^
%===% $w=Add-Type -Name WAPI -PassThru -MemberDefinition '^
%=====% [DllImport(\"user32.dll\")]^
%=======% public static extern void SetProcessDPIAware();^
%=====% [DllImport(\"shcore.dll\")]^
%=======% public static extern void SetProcessDpiAwareness(int value);^
%=====% [DllImport(\"kernel32.dll\")]^
%=======% public static extern IntPtr GetConsoleWindow();^
%=====% [DllImport(\"user32.dll\")]^
%=======% public static extern int SetWindowPos(IntPtr hwnd, IntPtr hwndAfterZ, int x, int y, int w, int h, int flags);^
%===% ';^
%===% $PROCESS_PER_MONITOR_DPI_AWARE=2;^
%===% try {$w::SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE)} catch {$w::SetProcessDPIAware()}^
%===% $x=0; $y=0; $tpid=0;^
%===% if (-not [Int32]::TryParse('%%~.', [ref]$x) -or -not [Int32]::TryParse('%%~/', [ref]$y)) {exit 1}^
%===% if ([Int32]::TryParse('%%~0', [ref]$tpid)) {^
%=====% $wnd=(gps -id $tpid -ea SilentlyContinue).MainWindowHandle;^
%===% } else {^
%=====% $wnd=$w::GetConsoleWindow();^
%===% }^
%===% $HWND_TOP=[IntPtr]::Zero;^
%===% $SWP_NOSIZE=0x0001;^
%===% $SWP_SHOWWINDOW=0x0040;^
%===% exit [int]($w::SetWindowPos($wnd, $HWND_TOP, $x, $y, 0, 0, $SWP_NOSIZE -bOr $SWP_SHOWWINDOW) -eq 0);^
%=% ^" ^&endlocal) else setlocal EnableDelayedExpansion ^&set args=

endlocal &set "MoveWindow=%MoveWindow%"
if !!# neq # set "MoveWindow=%MoveWindow:^^=%"
exit /b
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Both macros default to update the position of the console window. However, other windows can be moved by passing the ID of the belonging process as optional argument. In case of the Windows Terminal use the %TermPid% macro. Refer to:
viewtopic.php?f=3&t=10576

Steffen
Last edited by aGerman on 29 Oct 2022 09:32, edited 1 time in total.
Reason: support for other windows, such like Windows Terminal

IcarusLives
Posts: 175
Joined: 17 Jan 2016 23:55

Re: Center Window (yet another Powershell hybrid)

#2 Post by IcarusLives » 06 Sep 2018 14:40

Ooooo I like this release! Very nice! Is it possible to place in more dynamic positions, or just the 5?

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Center Window (yet another Powershell hybrid)

#3 Post by aGerman » 06 Sep 2018 14:59

Since the macro is called "center" I can't think of any further locations that deserve this name :wink: Of course it would be possible to move the window to any position you want but in that case "center" would be rather misleading. If you want me to write another script to move the window to certain x,y coordinates I would be able to modify the code accordingly.

Steffen

IcarusLives
Posts: 175
Joined: 17 Jan 2016 23:55

Re: Center Window (yet another Powershell hybrid)

#4 Post by IcarusLives » 07 Sep 2018 07:08

Haha, I guess you've got a point! No, this script is great! Thank you very much for this release.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Center Window and Move Window (yet more Powershell hybrids)

#5 Post by aGerman » 07 Sep 2018 14:15

I updated the initial post with an additional move_window macro.

Steffen

IcarusLives
Posts: 175
Joined: 17 Jan 2016 23:55

Re: Center Window and Move Window (yet more Powershell hybrids)

#6 Post by IcarusLives » 07 Sep 2018 14:20

I love the move window macro! This is great, thank you very much for this.

I also respect how short and concise it is.

Both working Win 10 64bit

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Center Window and Move Window (yet more Powershell hybrids)

#7 Post by aGerman » 07 Sep 2018 14:25

Thanks for your feedback, IcarusLives :) Much appreciated.

Steffen

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Center Window and Move Window (yet more Powershell hybrids)

#8 Post by aGerman » 29 Oct 2022 09:34

I updated the initial post to support other windows, such like Windows Terminal.

Steffen

Post Reply