Complete control of cmd windows
Moderator: DosItHelp
-
- Expert
- Posts: 960
- Joined: 15 Jun 2012 13:16
- Location: Italy, Rome
Re: Complete control of cmd windows
Is it possible to make a move_window starting from the latter?
Re: Complete control of cmd windows
Well, on what base would you move your window then? You need the rectangle of the monitor's work space (not just the size because the origin of the monitor is not necessarily {0,0}, especially if the virtual screen spans over more than one monitor), and you need the window size. I guess this would need an extension of the ConsoleInfo macro upfront, right?
-
- Expert
- Posts: 960
- Joined: 15 Jun 2012 13:16
- Location: Italy, Rome
Re: Complete control of cmd windows
Okay, it gets complicated a lot, for the moment I tried to make a mix from what you did before, something like that came out:
But the X always starts from -8 and I don't understand why.
What are you thinking about?
Code: Select all
set move_window=for %%i in (1 2) do if %%i==2 (%\n%
%=% for /f "tokens=1*" %%j in ("^!arg^!") do (%\n%
powershell -NoProfile -ExecutionPolicy Bypass -Command ^"^
%=% $w=Add-Type -Name WAPI -PassThru -MemberDefinition '^
%===% [DllImport(\"kernel32.dll\")] static extern IntPtr GetConsoleWindow();^
%===% [DllImport(\"user32.dll\")] static extern void GetWindowRect(IntPtr hwnd,int[] rect);^
%===% [DllImport(\"user32.dll\")] static extern void GetMonitorInfoW(IntPtr hMonitor,int[] lpmi);^
%===% [DllImport(\"user32.dll\")] static extern IntPtr MonitorFromWindow(IntPtr hwnd,int dwFlags);^
%===% [DllImport(\"user32.dll\")] static extern void MoveWindow(IntPtr hwnd,int x,int y,int w,int h,int repaint);^
%===% public static void center() {^
%=====% var hwnd=GetConsoleWindow();^
%=====% var rect=new int[4];^
%=====% GetWindowRect(hwnd,rect);^
%=====% var moninf=new int[10];^
%=====% moninf[0]=40;^
%=====% GetMonitorInfoW(MonitorFromWindow(hwnd,2),moninf);^
%=====% MoveWindow(hwnd,^
%=======% %%~j,^
%=======% %%~k,^
%=======% rect[2]-rect[0],^
%=======% rect[3]-rect[1],^
%=======% 0);^
%===% }';^
%=% $w::center();^"%\n%
%=% )%\n%
%=% endlocal%\n%
) else setlocal EnableDelayedExpansion ^&set arg=
What are you thinking about?
Re: Complete control of cmd windows
The old move_window macro is quite okay. As I said, an update of the ConsoleInfo macro is far more sensible here. In the example below the values for centering are just calculated in the batch code.
Code: Select all
@echo off &setlocal enableDelayedExpansion
mode con lines=20 cols=50
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The %ConsoleInfo% macro collects properties of the console window and its environment.
:: It prints a string in the following format to StdOut:
:: cml=N,cmt=N,cmr=N,cmb=N,cwx=N,cwy=N,cfx=N,cfy=N,ccx=N,ccy=N,clx=N,cly=N
:: With:
:: N different integral values of the below properties
:: cml left pixel boundary of the monitor's workspace
:: cmt top pixel boundary of the monitor's workspace
:: cmr right pixel boundary of the monitor's workspace
:: cmb bottom pixel boundary of the monitor's workspace
:: cwx current width of the console window as number of pixels
:: cwy current height of the console window as number of pixels
:: cfx console font width as number of pixels
:: cfy console font height as number of pixels
:: ccx current width of the console window as number of character cells
:: ccy current height of the console window as number of character cells
:: clx largest width of the console window as number of character cells
:: cly largest height of the console window as number of character cells
:: To define variables %cfx% .. %cly%, execute the macro in a FOR /F loop like that:
:: FOR /F %%I IN ('%ConsoleInfo%') DO SET /A "%%I"
set ConsoleInfo=^
powershell -nop -ep Bypass -c ^"^
%=% $w=Add-Type -Name WAPI -PassThru -MemberDefinition '^
%===% [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 GetMonitorInfoW(IntPtr hMonitor, int[] lpmi^);^
%===% [DllImport(\"user32.dll\"^)]^
%=====% public static extern IntPtr MonitorFromWindow(IntPtr hwnd, int dwFlags^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern IntPtr CreateFile(string name, int acc, int share, IntPtr sec, int how, int flags, IntPtr tmplt^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void GetCurrentConsoleFont(IntPtr hOut, int isMax, int[] info^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void CloseHandle(IntPtr h^);^
%=% ';^
^
%=% $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;^
%=% $w::GetMonitorInfoW($w::MonitorFromWindow($hwnd, 2^), $moninf^);^
^
%= The $rect 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. =% ^
%=% $rect=[int[]]::new(4^);^
%=% $w::GetWindowRect($hwnd, $rect^);^
^
%=% $NIL=[IntPtr]::Zero;^
%=% $GENERIC_READ=0x80000000;^
%=% $GENERIC_WRITE=0x40000000;^
%=% $FILE_SHARE_WRITE=0x00000002;^
%=% $OPEN_EXISTING=3;^
^
%= Because the StdOut stream is redirected to a pipe behind the scenes of a FOR /F loop, =% ^
%= we need to explicitly open a handle to the console output device (alias 'CONOUT$'). =% ^
%=% $out=$w::CreateFile('CONOUT$', $GENERIC_READ -bor $GENERIC_WRITE, $FILE_SHARE_WRITE, $NIL, $OPEN_EXISTING, 0, $NIL^);^
%= The $fntinf array is a replacement for the CONSOLE_FONT_INFO structure. The 16 low order bits of the =% ^
%= second element represent the font width, while its 16 high order bits represent the font height. =% ^
%=% $fntinf=[int[]]::new(2^);^
%=% $w::GetCurrentConsoleFont($out, 0, $fntinf^);^
%=% $w::CloseHandle($out^);^
^
%=% $raw=$host.UI.RawUI;^
%=% $cur=$raw.WindowSize;^
%=% $lrg=$raw.MaxPhysicalWindowSize;^
^
%=% 'cml={0},cmt={1},cmr={2},cmb={3},cwx={4},cwy={5},cfx={6},cfy={7},ccx={8},ccy={9},clx={10},cly={11}' -f^
%===% $moninf[5], $moninf[6], $moninf[7], $moninf[8],^
%===% ($rect[2]-$rect[0]^), ($rect[3]-$rect[1]^),^
%===% ($fntinf[1] -band 0xFFFF^), ($fntinf[1] -shr 16^),^
%===% $cur.Width, $cur.Height,^
%===% $lrg.Width, $lrg.Height;^
^"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
for /f %%i in ('%ConsoleInfo%') do set /a "%%i"
echo console monitor boundaries: %cml%, %cmt%, %cmr%, %cmb%
echo console window size: %cwx%, %cwy%
echo console font size: %cfx%, %cfy%
echo console current size: %ccx%, %ccy%
echo console largest size: %clx%, %cly%
echo(
rem for macro definition/readability
(set \n=^^^
%= This creates an escaped Line Feed - DO NOT ALTER =%
)
set move_window=for %%i in (1 2) do if %%i==2 (%\n%
%=% for /f "tokens=1*" %%j in ("^!arg^!") do (%\n%
%=====% powershell.exe -NoProfile -ExecutionPolicy Bypass -Command ^"try{$c=Add-Type -Name WinAPI -PassThru -MemberDefinition '^
%=====% [DllImport(\"user32.dll\"^)] public static extern int SetWindowPos(IntPtr hWnd^, IntPtr hWndInsertAfter^, int X^, int Y^, int cx^, int cy^, uint uFlags^);^
%=====% [DllImport(\"kernel32.dll\"^)] public static extern IntPtr GetConsoleWindow(^);';^
%=====% $x=0; $y=0;^
%=====% if (([Int32]::TryParse(\"%%~j\"^, [ref]$x^) -eq $false^) -or ([Int32]::TryParse(\"%%~k\"^, [ref]$y^) -eq $false^)^){^
%=========% [Console]::Error.WriteLine(\"Syntax Error`r`n Usage:`r`n%%move_window%% X Y`r`n X left side of the window`r`n Y top of the window\"^);^
%=========% exit 1;^
%=====% }^
%=====% exit [int]($c::SetWindowPos($c::GetConsoleWindow(^)^, [IntPtr]::Zero^, $x^, $y^, 0^, 0^, 5^) -eq 0^);}catch{exit 1;}^"%\n%
%=% )%\n%
%=% endlocal%\n%
) else setlocal EnableDelayedExpansion ^&set arg=
:: center the window
set /a "newX=cml+(cmr-cml)/2-cwx/2"
set /a "newY=cmt+(cmb-cmt)/2-cwy/2"
%move_window% %newX% %newY%
pause
-
- Expert
- Posts: 960
- Joined: 15 Jun 2012 13:16
- Location: Italy, Rome
Re: Complete control of cmd windows
good work!
Tested only %ConsoleInfo% for now.
The test fail on "console window size"
tested with mode 50,50 - courier new 7x14 - zoom 100%
reported:
test code:
Tested only %ConsoleInfo% for now.
The test fail on "console window size"
tested with mode 50,50 - courier new 7x14 - zoom 100%
reported:
Code: Select all
console monitor boundaries: 0, 0, 1920, 1040
console window size: 366, 739
console font size: 7, 14
console current size: 50, 50
console largest size: 274, 72
calculate window size: 350 700
misurated 350x730 header 30px
Premere un tasto per continuare . . .
Code: Select all
@echo off & setlocal enableDelayedExpansion & if NOT "%1"=="" goto :subs
Start "Sphere" "%0" .
goto :eof
:subs
rem test with font 7x14 courier new
mode con lines=50 cols=50
call :init
echo console monitor boundaries: %cml%, %cmt%, %cmr%, %cmb%
echo console window size: %cwx%, %cwy%
echo console font size: %cfx%, %cfy%
echo console current size: %ccx%, %ccy%
echo console largest size: %clx%, %cly%
echo(
set /a cws.X=cfx*ccx, cws.Y=cfy*ccy
echo calculate window size: %cws.X% %cws.Y%
echo misurated 350x730 header 30px
pause
goto :eof
:: center the window
set /a "newX=cml+(cmr-cml)/2-cwx/2"
set /a "newY=cmt+(cmb-cmt)/2-cwy/2"
%move_window% %newX% %newY%
pause
rem choose console size
set /A img.x=50, img.y=50
(
rem setting request console size and remove buffers size on max
mode CON: COLS=!img.x! LINES=!img.y!
rem update Consoleinfo, I don't launch powershell again for the bug on win10 for chcp 65001
set /A ConsoleSize.X=img.x, ConsoleSize.Y=img.y
)
rem center the windows
(
rem is strange formula but work well
set /A "center.x=(Screen.Width-img.x*FontSize.X)/2-8"
rem to do : tuning.
set /A "center.y=(Screen.height-img.y*FontSize.Y)/2-8-35"
%move_window% !center.x! !center.y!
)
pause>nul
goto :eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:init
rem clear environment for faster execution of SET command
(
rem set "Path=%SystemRoot%\system32"
for /F "Tokens=1 delims==" %%v in ('set') do if not %%v==ESC if not %%v==TMP if not %%v==Path if not %%v==SystemRoot set "%%v="
)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The %ConsoleInfo% macro collects properties of the console window and its environment.
:: It prints a string in the following format to StdOut:
:: cml=N,cmt=N,cmr=N,cmb=N,cwx=N,cwy=N,cfx=N,cfy=N,ccx=N,ccy=N,clx=N,cly=N
:: With:
:: N different integral values of the below properties
:: cml left pixel boundary of the monitor's workspace
:: cmt top pixel boundary of the monitor's workspace
:: cmr right pixel boundary of the monitor's workspace
:: cmb bottom pixel boundary of the monitor's workspace
:: cwx current width of the console window as number of pixels
:: cwy current height of the console window as number of pixels
:: cfx console font width as number of pixels
:: cfy console font height as number of pixels
:: ccx current width of the console window as number of character cells
:: ccy current height of the console window as number of character cells
:: clx largest width of the console window as number of character cells
:: cly largest height of the console window as number of character cells
:: To define variables %cfx% .. %cly%, execute the macro in a FOR /F loop like that:
:: FOR /F %%I IN ('%ConsoleInfo%') DO SET /A "%%I"
set ConsoleInfo=^
powershell -nop -ep Bypass -c ^"^
%=% $w=Add-Type -Name WAPI -PassThru -MemberDefinition '^
%===% [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 GetMonitorInfoW(IntPtr hMonitor, int[] lpmi^);^
%===% [DllImport(\"user32.dll\"^)]^
%=====% public static extern IntPtr MonitorFromWindow(IntPtr hwnd, int dwFlags^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern IntPtr CreateFile(string name, int acc, int share, IntPtr sec, int how, int flags, IntPtr tmplt^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void GetCurrentConsoleFont(IntPtr hOut, int isMax, int[] info^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void CloseHandle(IntPtr h^);^
%=% ';^
^
%=% $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;^
%=% $w::GetMonitorInfoW($w::MonitorFromWindow($hwnd, 2^), $moninf^);^
^
%= The $rect 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. =% ^
%=% $rect=[int[]]::new(4^);^
%=% $w::GetWindowRect($hwnd, $rect^);^
^
%=% $NIL=[IntPtr]::Zero;^
%=% $GENERIC_READ=0x80000000;^
%=% $GENERIC_WRITE=0x40000000;^
%=% $FILE_SHARE_WRITE=0x00000002;^
%=% $OPEN_EXISTING=3;^
^
%= Because the StdOut stream is redirected to a pipe behind the scenes of a FOR /F loop, =% ^
%= we need to explicitly open a handle to the console output device (alias 'CONOUT$'). =% ^
%=% $out=$w::CreateFile('CONOUT$', $GENERIC_READ -bor $GENERIC_WRITE, $FILE_SHARE_WRITE, $NIL, $OPEN_EXISTING, 0, $NIL^);^
%= The $fntinf array is a replacement for the CONSOLE_FONT_INFO structure. The 16 low order bits of the =% ^
%= second element represent the font width, while its 16 high order bits represent the font height. =% ^
%=% $fntinf=[int[]]::new(2^);^
%=% $w::GetCurrentConsoleFont($out, 0, $fntinf^);^
%=% $w::CloseHandle($out^);^
^
%=% $raw=$host.UI.RawUI;^
%=% $cur=$raw.WindowSize;^
%=% $lrg=$raw.MaxPhysicalWindowSize;^
^
%=% 'cml={0},cmt={1},cmr={2},cmb={3},cwx={4},cwy={5},cfx={6},cfy={7},ccx={8},ccy={9},clx={10},cly={11}' -f^
%===% $moninf[5], $moninf[6], $moninf[7], $moninf[8],^
%===% ($rect[2]-$rect[0]^), ($rect[3]-$rect[1]^),^
%===% ($fntinf[1] -band 0xFFFF^), ($fntinf[1] -shr 16^),^
%===% $cur.Width, $cur.Height,^
%===% $lrg.Width, $lrg.Height;^
^"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
for /f %%i in ('%ConsoleInfo%') do set /a "%%i"
rem echo console monitor boundaries: %cml%, %cmt%, %cmr%, %cmb%
rem echo console window size: %cwx%, %cwy%
rem echo console font size: %cfx%, %cfy%
rem echo console current size: %ccx%, %ccy%
rem echo console largest size: %clx%, %cly%
rem echo(
rem font size in pixels
set /a "FontSize.X=%cfx%, FontSize.Y=%cfy%"
rem max/largest Size of cmd window/console window in chars
set /a "MaxConsoleSize.X=%clx%, MaxConsoleSize.Y=%cly%"
rem Current Size of cmd window/console window in chars
set /a "ConsoleSize.X=%ccx%, ConsoleSize.Y=%ccy%"
rem console window size in pixels
set /a "ConsoleWindowSize.X=%cwx%, ConsoleWindowSize.Y=%cwy%"
rem console monitor boundaries
set /A Monitor.left=%cml%, Monitor.top=%cmt% ,Monitor.right=%cmr% ,Monitor.bottom=%cmb%
rem get resolution of screen
for /f "usebackq tokens=1,2 delims= " %%x in (`mshta "javascript:new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1).Write(screen.width+' '+screen.height);close();noflash"`) do set /A Screen.Width=%%x, Screen.Height=%%y
rem for macro definition/readability
(set \n=^^^
%= This creates an escaped Line Feed - DO NOT ALTER =%
)
set move_window=for %%i in (1 2) do if %%i==2 (%\n%
%=% for /f "tokens=1*" %%j in ("^!arg^!") do (%\n%
%=====% powershell.exe -NoProfile -ExecutionPolicy Bypass -Command ^"try{$c=Add-Type -Name WinAPI -PassThru -MemberDefinition '^
%=====% [DllImport(\"user32.dll\"^)] public static extern int SetWindowPos(IntPtr hWnd^, IntPtr hWndInsertAfter^, int X^, int Y^, int cx^, int cy^, uint uFlags^);^
%=====% [DllImport(\"kernel32.dll\"^)] public static extern IntPtr GetConsoleWindow(^);';^
%=====% $x=0; $y=0;^
%=====% if (([Int32]::TryParse(\"%%~j\"^, [ref]$x^) -eq $false^) -or ([Int32]::TryParse(\"%%~k\"^, [ref]$y^) -eq $false^)^){^
%=========% [Console]::Error.WriteLine(\"Syntax Error`r`n Usage:`r`n%%move_window%% X Y`r`n X left side of the window`r`n Y top of the window\"^);^
%=========% exit 1;^
%=====% }^
%=====% exit [int]($c::SetWindowPos($c::GetConsoleWindow(^)^, [IntPtr]::Zero^, $x^, $y^, 0^, 0^, 5^) -eq 0^);}catch{exit 1;}^"%\n%
%=% )%\n%
%=% endlocal%\n%
) else setlocal EnableDelayedExpansion ^&set arg=
:: center the window
rem set /a "newX=cml+(cmr-cml)/2-cwx/2"
rem set /a "newY=cmt+(cmb-cmt)/2-cwy/2"
rem %rem move_window% %newX% %newY%
rem pause
-
- Expert
- Posts: 960
- Joined: 15 Jun 2012 13:16
- Location: Italy, Rome
Re: Complete control of cmd windows
DPI awareness?
Re: Complete control of cmd windows
DPI awareness doesn't actually matter as long as both the ConsoleInfo and the move_window macros are not DPI aware. Of course the absolute values you get will probably differ. Made them both DPI aware now:
Code: Select all
@echo off &setlocal enableDelayedExpansion
mode con lines=20 cols=50
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The %ConsoleInfo% macro collects properties of the console window and its environment.
:: It prints a string in the following format to StdOut:
:: cml=N,cmt=N,cmr=N,cmb=N,cwx=N,cwy=N,cvx=N,cvy=N,cfx=N,cfy=N,chx=N,chy=N,ccx=N,ccy=N,clx=N,cly=N
:: With:
:: N different integral values of the below properties
:: cml left dots boundary of the monitor's workspace
:: cmt top dots boundary of the monitor's workspace
:: cmr right dots boundary of the monitor's workspace
:: cmb bottom dots boundary of the monitor's workspace
:: cwx current width of the console window as number of dots
:: cwy current height of the console window as number of dots
:: cvx current width of the console viewport as number of dots
:: cvy current height of the console viewport as number of dots
:: cfx console font width as number of pixels
:: cfy console font height as number of pixels
:: chx approximated console charcell width as number of dots
:: chy approximated console charcell height as number of dots
:: ccx current width of the console client window as number of character cells
:: ccy current height of the console client window as number of character cells
:: clx largest width of the console client window as number of character cells
:: cly largest height of the console client window as number of character cells
:: To define variables %cfx% .. %cly%, execute the macro in a FOR /F loop like that:
:: FOR /F %%I IN ('%ConsoleInfo%') DO SET /A "%%I"
set ConsoleInfo=^
powershell -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(\"kernel32.dll\"^)]^
%=====% public static extern IntPtr CreateFile(string name, int acc, int share, IntPtr sec, int how, int flags, IntPtr tmplt^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void GetCurrentConsoleFont(IntPtr hOut, int isMax, int[] info^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void CloseHandle(IntPtr h^);^
%=% ';^
^
%=% $PROCESS_PER_MONITOR_DPI_AWARE=2;^
%=% try {$w::SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE^)} catch {$w::SetProcessDPIAware(^)}^
^
%=% $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^);^
^
%= 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^);^
^
%= The $crect 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 client window. =% ^
%=% $crect=[int[]]::new(4^);^
%=% $w::GetClientRect($hwnd, $crect^);^
^
%=% $NIL=[IntPtr]::Zero;^
%=% $GENERIC_READ=0x80000000;^
%=% $GENERIC_WRITE=0x40000000;^
%=% $FILE_SHARE_WRITE=0x00000002;^
%=% $OPEN_EXISTING=3;^
%= Because the StdOut stream is redirected to a pipe behind the scenes of a FOR /F loop, =% ^
%= we need to explicitly open a handle to the console output device (alias 'CONOUT$'). =% ^
%=% $out=$w::CreateFile('CONOUT$', $GENERIC_READ -bor $GENERIC_WRITE, $FILE_SHARE_WRITE, $NIL, $OPEN_EXISTING, 0, $NIL^);^
%= The $fntinf array is a replacement for the CONSOLE_FONT_INFO structure. The 16 low order bits of the =% ^
%= second element represent the font width, while its 16 high order bits represent the font height. =% ^
%=% $fntinf=[int[]]::new(2^);^
%=% $w::GetCurrentConsoleFont($out, 0, $fntinf^);^
%=% $w::CloseHandle($out^);^
^
%=% $raw=$host.UI.RawUI;^
%=% $cur=$raw.WindowSize;^
%=% $lrg=$raw.MaxPhysicalWindowSize;^
^
%=% 'cml={0},cmt={1},cmr={2},cmb={3},cwx={4},cwy={5},cvx={6},cvy={7},cfx={8},cfy={9},chx={10},chy={11},ccx={12},ccy={13},clx={14},cly={15}' -f^
%===% $moninf[5], $moninf[6], $moninf[7], $moninf[8],^
%===% ($wrect[2]-$wrect[0]^), ($wrect[3]-$wrect[1]^),^
%===% ($crect[2]-$crect[0]^), ($crect[3]-$crect[1]^),^
%===% ($fntinf[1] -band 0xFFFF^), ($fntinf[1] -shr 16^),^
%===% [math]::Round(($crect[2]-$crect[0]^)/$cur.Width^), [math]::Round(($crect[3]-$crect[1]^)/$cur.Height^),^
%===% $cur.Width, $cur.Height,^
%===% $lrg.Width, $lrg.Height;^
^"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
for /f %%i in ('%ConsoleInfo%') do set /a "%%i"
echo console monitor boundaries: %cml%, %cmt%, %cmr%, %cmb%
echo console window size: %cwx%, %cwy%
echo console viewport size: %cvx%, %cvy%
echo console font size: %cfx%, %cfy%
echo console charcell size: %chx%, %chy%
echo console current size: %ccx%, %ccy%
echo console largest size: %clx%, %cly%
echo(
rem for macro definition/readability
(set \n=^^^
%= This creates an escaped Line Feed - DO NOT ALTER =%
)
set move_window=for %%i in (1 2) do if %%i==2 (%\n%
%=% for /f "tokens=1*" %%j in ("^!arg^!") do (%\n%
%=====% powershell.exe -NoProfile -ExecutionPolicy Bypass -Command ^"try{$c=Add-Type -Name WinAPI -PassThru -MemberDefinition '^
%=====% [DllImport(\"user32.dll\"^)] public static extern void SetProcessDPIAware(^);^
%=====% [DllImport(\"shcore.dll\"^)] public static extern void SetProcessDpiAwareness(int value^);^
%=====% [DllImport(\"user32.dll\"^)] public static extern int SetWindowPos(IntPtr hWnd^, IntPtr hWndInsertAfter^, int X^, int Y^, int cx^, int cy^, uint uFlags^);^
%=====% [DllImport(\"kernel32.dll\"^)] public static extern IntPtr GetConsoleWindow(^);';^
%=====% try{$c::SetProcessDpiAwareness(2^)}catch{$c::SetProcessDPIAware(^)}^
%=====% $x=0; $y=0;^
%=====% if (([Int32]::TryParse(\"%%~j\"^, [ref]$x^) -eq $false^) -or ([Int32]::TryParse(\"%%~k\"^, [ref]$y^) -eq $false^)^){^
%=========% [Console]::Error.WriteLine(\"Syntax Error`r`n Usage:`r`n%%move_window%% X Y`r`n X left side of the window`r`n Y top of the window\"^);^
%=========% exit 1;^
%=====% }^
%=====% exit [int]($c::SetWindowPos($c::GetConsoleWindow(^)^, [IntPtr]::Zero^, $x^, $y^, 0^, 0^, 5^) -eq 0^);}catch{exit 1;}^"%\n%
%=% )%\n%
%=% endlocal%\n%
) else setlocal EnableDelayedExpansion ^&set arg=
:: center the window
set /a "newX=cml+(cmr-cml)/2-cwx/2"
set /a "newY=cmt+(cmb-cmt)/2-cwy/2"
%move_window% %newX% %newY%
pause
Re: Complete control of cmd windows
I updated the code above to get additional information:
- Size of the viewport in dots (the viewport is the "inner" client frame that displays the visible part of the console buffer).
- Size of a character cell. I suggest to use this instead of the font size for the calculation of your circle ratio!
Note: The size of a character cell is an approximation because the V2 console allows fractional charcells at the right and bottom edge. If you resize the window it doesn't snap in at full cells like the legacy console did.
- Size of the viewport in dots (the viewport is the "inner" client frame that displays the visible part of the console buffer).
- Size of a character cell. I suggest to use this instead of the font size for the calculation of your circle ratio!
Note: The size of a character cell is an approximation because the V2 console allows fractional charcells at the right and bottom edge. If you resize the window it doesn't snap in at full cells like the legacy console did.
Re: Complete control of cmd windows
One of your previous codes updated to:
- draw spheres rounder
- draw faster
- support file names with special characters (like parentheses)
- close the window after a key is pressed
- draw spheres rounder
- draw faster
- support file names with special characters (like parentheses)
- close the window after a key is pressed
Code: Select all
@echo off
rem save this script in UTF-8
set "me=%~f0"
setlocal enableDelayedExpansion
if "%1"=="" (
rem restart maximized
Start "Sphere" /MAX cmd.exe /c ""!me!" max"
goto :eof
)
if "%1"=="sphere" (
call :sphere %2 %3 %4 %5 %6 %7
goto :eof
)
rem "%1" is "max" if we reach out to this point
call :GetInfo
rem setting request console size and remove buffers size on max
mode CON: COLS=!ConsoleSize.X! LINES=!ConsoleSize.Y!
rem multithread 9 thread
set /A "deltaX=ConsoleSize.X/3, deltaY=ConsoleSize.Y/3, Radius=deltaY/2"
start "" /B cmd.exe /c ""!me!" sphere Red 1 1 !deltaX! !deltaY! !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Green !deltaX! 1 !deltaX!*2 !deltaY! !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Blue !deltaX!*2 1 !deltaX!*3 !deltaY! !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Yellow 1 !deltaY!+1 !deltaX! !deltaY!*2 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Cyan !deltaX! !deltaY!+1 !deltaX!*2 !deltaY!*2 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Magenta !deltaX!*2 !deltaY!+1 !deltaX!*3 !deltaY!*2 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere White 1 !deltaY!*2+1 !deltaX! !deltaY!*3 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Orange !deltaX! !deltaY!*2+1 !deltaX!*2 !deltaY!*3 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Pink !deltaX!*2 !deltaY!*2+1 !deltaX!*3 !deltaY!*3 !Radius!"
pause>nul
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:sphere color Begin.X Begin.Y End.X End.Y Radius
rem title %1 %2 %3 %4 %5 %6
rem pause
call :init
set /A Bimg.x=%2, Bimg.y=%3
set /A Eimg.x=%4, Eimg.y=%5
set /A Radius=%6
rem cell size in dots
set /A xc=CellSize.X, yc=CellSize.Y
rem draw a circle (x-x0)^2+(y-y0)^2=r^2 . Implicit equation for simpler math.
rem set radius and center in cmd windows, assume screen ratio greater than one ie 1280/720=1.777
set /A "R=Radius*yc, X0=((Eimg.x-Bimg.x)/2+Bimg.x)*xc, Y0=Bimg.y*yc+R"
rem setting step for better smoothing colors
set /A "mS=-(R*R), step=255*100000/-mS, stepL=128*100000/-mS"
rem (performance) we compare colors first instead of doing it for each painted cell
if "%1"=="Red" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y !C! 0 0
)
)
%flush%
goto :eof
)
if "%1"=="Green" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y 0 !C! 0
)
)
%flush%
goto :eof
)
if "%1"=="Blue" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y 0 0 !C!
)
)
%flush%
goto :eof
)
if "%1"=="Yellow" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y !C! !C! 0
)
)
%flush%
goto :eof
)
if "%1"=="Cyan" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y 0 !C! !C!
)
)
%flush%
goto :eof
)
if "%1"=="Magenta" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y !C! 0 !C!
)
)
%flush%
goto :eof
)
if "%1"=="White" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y !C! !C! !C!
)
)
%flush%
goto :eof
)
if "%1"=="Orange" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000, CL=-S*stepL/100000"
if !S! leq 0 %plot% %%x %%y !C! !CL! 0
)
)
%flush%
goto :eof
)
if "%1"=="Pink" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000, CL=-S*stepL/100000"
if !S! leq 0 %plot% %%x %%y !C! 0 !CL!
)
)
%flush%
goto :eof
)
%flush%
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:GetInfo
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The %ConsoleInfo% macro collects properties of the console window and its environment.
:: It prints a string in the following format to StdOut:
:: cml=N,cmt=N,cmr=N,cmb=N,cwx=N,cwy=N,cvx=N,cvy=N,cfx=N,cfy=N,chx=N,chy=N,ccx=N,ccy=N,clx=N,cly=N
:: With:
:: N different integral values of the below properties
:: cml left dots boundary of the monitor's workspace
:: cmt top dots boundary of the monitor's workspace
:: cmr right dots boundary of the monitor's workspace
:: cmb bottom dots boundary of the monitor's workspace
:: cwx current width of the console window as number of dots
:: cwy current height of the console window as number of dots
:: cvx current width of the console viewport as number of dots
:: cvy current height of the console viewport as number of dots
:: cfx console font width as number of pixels
:: cfy console font height as number of pixels
:: chx approximated console charcell width as number of dots
:: chy approximated console charcell height as number of dots
:: ccx current width of the console client window as number of character cells
:: ccy current height of the console client window as number of character cells
:: clx largest width of the console client window as number of character cells
:: cly largest height of the console client window as number of character cells
:: To define variables %cfx% .. %cly%, execute the macro in a FOR /F loop like that:
:: FOR /F %%I IN ('%ConsoleInfo%') DO SET /A "%%I"
set ConsoleInfo=^
powershell -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(\"kernel32.dll\"^)]^
%=====% public static extern IntPtr CreateFile(string name, int acc, int share, IntPtr sec, int how, int flags, IntPtr tmplt^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void GetCurrentConsoleFont(IntPtr hOut, int isMax, int[] info^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void CloseHandle(IntPtr h^);^
%=% ';^
^
%=% $PROCESS_PER_MONITOR_DPI_AWARE=2;^
%=% try {$w::SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE^)} catch {$w::SetProcessDPIAware(^)}^
^
%=% $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^);^
^
%= 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^);^
^
%= The $crect 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 client window. =% ^
%=% $crect=[int[]]::new(4^);^
%=% $w::GetClientRect($hwnd, $crect^);^
^
%=% $NIL=[IntPtr]::Zero;^
%=% $GENERIC_READ=0x80000000;^
%=% $GENERIC_WRITE=0x40000000;^
%=% $FILE_SHARE_WRITE=0x00000002;^
%=% $OPEN_EXISTING=3;^
%= Because the StdOut stream is redirected to a pipe behind the scenes of a FOR /F loop, =% ^
%= we need to explicitly open a handle to the console output device (alias 'CONOUT$'). =% ^
%=% $out=$w::CreateFile('CONOUT$', $GENERIC_READ -bor $GENERIC_WRITE, $FILE_SHARE_WRITE, $NIL, $OPEN_EXISTING, 0, $NIL^);^
%= The $fntinf array is a replacement for the CONSOLE_FONT_INFO structure. The 16 low order bits of the =% ^
%= second element represent the font width, while its 16 high order bits represent the font height. =% ^
%=% $fntinf=[int[]]::new(2^);^
%=% $w::GetCurrentConsoleFont($out, 0, $fntinf^);^
%=% $w::CloseHandle($out^);^
^
%=% $raw=$host.UI.RawUI;^
%=% $cur=$raw.WindowSize;^
%=% $lrg=$raw.MaxPhysicalWindowSize;^
^
%=% 'cml={0},cmt={1},cmr={2},cmb={3},cwx={4},cwy={5},cvx={6},cvy={7},cfx={8},cfy={9},chx={10},chy={11},ccx={12},ccy={13},clx={14},cly={15}' -f^
%===% $moninf[5], $moninf[6], $moninf[7], $moninf[8],^
%===% ($wrect[2]-$wrect[0]^), ($wrect[3]-$wrect[1]^),^
%===% ($crect[2]-$crect[0]^), ($crect[3]-$crect[1]^),^
%===% ($fntinf[1] -band 0xFFFF^), ($fntinf[1] -shr 16^),^
%===% [math]::Round(($crect[2]-$crect[0]^)/$cur.Width^), [math]::Round(($crect[3]-$crect[1]^)/$cur.Height^),^
%===% $cur.Width, $cur.Height,^
%===% $lrg.Width, $lrg.Height;^
^"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
for /f %%i in ('%ConsoleInfo%') do set /a "%%i"
rem cell size in dots
set /a "CellSize.X=%chx%, CellSize.Y=%chy%"
rem Current Size of cmd window/console window
set /a "ConsoleSize.X=%ccx%, ConsoleSize.Y=%ccy%"
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:init
rem this code must execute after ConsoleInfo macro, if not this change font family to TERMINAL/RASTER, in window 10
chcp 65001 >nul
rem clear environment for faster execution of SET command
(
for /F "Tokens=1 delims==" %%v in ('set') do set "%%v="
set "Path=%SystemRoot%\system32"
set /a "CellSize.X=%CellSize.X%, CellSize.Y=%CellSize.Y%"
set /a "ConsoleSize.X=%ConsoleSize.X%, ConsoleSize.Y=%ConsoleSize.Y%"
)
rem for ansi sequence
for /F %%a in ('echo prompt $E^| cmd.exe') do set "ESC=%%a"
:: Hide the cursor
<nul set /p "=!ESC![?25l"
rem ALT+219
set "Char=█"
rem set "Char=*"
rem for macro definition/readability
(set \n=^^^
%= This creates an escaped Line Feed - DO NOT ALTER =%
)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: macro Plot=Screen.Setpixel X Y R G B
set "Buffer="
set Plot=for %%# in (1 2) do if %%#==2 (%\n%
for /f "tokens=1-5 delims=, " %%1 in ("^!args^!") do ( %\n%
if not defined Buffer (%\n%
set "Buffer=^!ESC^![%%2;%%1H^!ESC^![38;2;%%3;%%4;%%5m^!Char^!" %\n%
) else ( %\n%
if "^!Buffer:~100,1^!"=="" ( %\n%
set "Buffer=^!Buffer^!^!ESC^![%%2;%%1H^!ESC^![38;2;%%3;%%4;%%5m^!Char^!" %\n%
) else ( %\n%
^<nul set /p "=^!Buffer^!^!ESC^![%%2;%%1H^!ESC^![38;2;%%3;%%4;%%5m^!Char^!^!ESC^![0m" %\n%
set "Buffer=" %\n%
) %\n%
) %\n%
)) else set args=
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Flush flush the variable buffer.
set Flush=^<nul set /p "=^!Buffer^!^!ESC^![0m" ^& set "Buffer="
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
- Expert
- Posts: 960
- Joined: 15 Jun 2012 13:16
- Location: Italy, Rome
Re: Complete control of cmd windows
great!
I'm testing everything
I'm testing everything
Re: Complete control of cmd windows
Similarly using a centered window.
I've also been able to get rid of the \n in both the MoveWindow and Plot macros.
Code: Select all
@echo off
rem save this script in UTF-8
set "me=%~f0"
setlocal enableDelayedExpansion
if "%1"=="sphere" (
call :sphere %2 %3 %4 %5 %6 %7
goto :eof
)
title Spheres
mode CON: COLS=100 LINES=40
call :GetInfoAndCenter
rem multithread 9 thread
set /A "deltaX=ConsoleSize.X/3, deltaY=ConsoleSize.Y/3, Radius=deltaY/2"
start "" /B cmd.exe /c ""!me!" sphere Red 1 1 !deltaX! !deltaY! !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Green !deltaX! 1 !deltaX!*2 !deltaY! !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Blue !deltaX!*2 1 !deltaX!*3 !deltaY! !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Yellow 1 !deltaY!+1 !deltaX! !deltaY!*2 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Cyan !deltaX! !deltaY!+1 !deltaX!*2 !deltaY!*2 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Magenta !deltaX!*2 !deltaY!+1 !deltaX!*3 !deltaY!*2 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere White 1 !deltaY!*2+1 !deltaX! !deltaY!*3 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Orange !deltaX! !deltaY!*2+1 !deltaX!*2 !deltaY!*3 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Pink !deltaX!*2 !deltaY!*2+1 !deltaX!*3 !deltaY!*3 !Radius!"
pause>nul
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:sphere color Begin.X Begin.Y End.X End.Y Radius
rem title %1 %2 %3 %4 %5 %6
rem pause
call :init
set /A Bimg.x=%2, Bimg.y=%3
set /A Eimg.x=%4, Eimg.y=%5
set /A Radius=%6
rem cell size in dots
set /A xc=CellSize.X, yc=CellSize.Y
rem draw a circle (x-x0)^2+(y-y0)^2=r^2 . Implicit equation for simpler math.
rem set radius and center in cmd windows, assume screen ratio greater than one ie 1280/720=1.777
set /A "R=Radius*yc, X0=((Eimg.x-Bimg.x)/2+Bimg.x)*xc, Y0=Bimg.y*yc+R"
rem setting step for better smoothing colors
set /A "mS=-(R*R), step=255*100000/-mS, stepL=128*100000/-mS"
rem (performance) we compare colors first instead of doing it for each painted cell
if "%1"=="Red" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y !C! 0 0
)
)
%flush%
goto :eof
)
if "%1"=="Green" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y 0 !C! 0
)
)
%flush%
goto :eof
)
if "%1"=="Blue" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y 0 0 !C!
)
)
%flush%
goto :eof
)
if "%1"=="Yellow" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y !C! !C! 0
)
)
%flush%
goto :eof
)
if "%1"=="Cyan" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y 0 !C! !C!
)
)
%flush%
goto :eof
)
if "%1"=="Magenta" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y !C! 0 !C!
)
)
%flush%
goto :eof
)
if "%1"=="White" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y !C! !C! !C!
)
)
%flush%
goto :eof
)
if "%1"=="Orange" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000, CL=-S*stepL/100000"
if !S! leq 0 %plot% %%x %%y !C! !CL! 0
)
)
%flush%
goto :eof
)
if "%1"=="Pink" (
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000, CL=-S*stepL/100000"
if !S! leq 0 %plot% %%x %%y !C! 0 !CL!
)
)
%flush%
goto :eof
)
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:GetInfoAndCenter
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The %ConsoleInfo% macro collects properties of the console window and its environment.
:: It prints a string in the following format to StdOut:
:: cml=N,cmt=N,cmr=N,cmb=N,cwx=N,cwy=N,cvx=N,cvy=N,cfx=N,cfy=N,chx=N,chy=N,ccx=N,ccy=N,clx=N,cly=N
:: With:
:: N different integral values of the below properties
:: cml left dots boundary of the monitor's workspace
:: cmt top dots boundary of the monitor's workspace
:: cmr right dots boundary of the monitor's workspace
:: cmb bottom dots boundary of the monitor's workspace
:: cwx current width of the console window as number of dots
:: cwy current height of the console window as number of dots
:: cvx current width of the console viewport as number of dots
:: cvy current height of the console viewport as number of dots
:: cfx console font width as number of pixels
:: cfy console font height as number of pixels
:: chx approximated console charcell width as number of dots
:: chy approximated console charcell height as number of dots
:: ccx current width of the console client window as number of character cells
:: ccy current height of the console client window as number of character cells
:: clx largest width of the console client window as number of character cells
:: cly largest height of the console client window as number of character cells
:: To define variables %cfx% .. %cly%, execute the macro in a FOR /F loop like that:
:: FOR /F %%I IN ('%ConsoleInfo%') DO SET /A "%%I"
set ConsoleInfo=^
powershell -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(\"kernel32.dll\"^)]^
%=====% public static extern IntPtr CreateFile(string name, int acc, int share, IntPtr sec, int how, int flags, IntPtr tmplt^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void GetCurrentConsoleFont(IntPtr hOut, int isMax, int[] info^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void CloseHandle(IntPtr h^);^
%=% ';^
^
%=% $PROCESS_PER_MONITOR_DPI_AWARE=2;^
%=% try {$w::SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE^)} catch {$w::SetProcessDPIAware(^)}^
^
%=% $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^);^
^
%= 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^);^
^
%= The $crect 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 client window. =% ^
%=% $crect=[int[]]::new(4^);^
%=% $w::GetClientRect($hwnd, $crect^);^
^
%=% $NIL=[IntPtr]::Zero;^
%=% $GENERIC_READ=0x80000000;^
%=% $GENERIC_WRITE=0x40000000;^
%=% $FILE_SHARE_WRITE=0x00000002;^
%=% $OPEN_EXISTING=3;^
%= Because the StdOut stream is redirected to a pipe behind the scenes of a FOR /F loop, =% ^
%= we need to explicitly open a handle to the console output device (alias 'CONOUT$'). =% ^
%=% $out=$w::CreateFile('CONOUT$', $GENERIC_READ -bor $GENERIC_WRITE, $FILE_SHARE_WRITE, $NIL, $OPEN_EXISTING, 0, $NIL^);^
%= The $fntinf array is a replacement for the CONSOLE_FONT_INFO structure. The 16 low order bits of the =% ^
%= second element represent the font width, while its 16 high order bits represent the font height. =% ^
%=% $fntinf=[int[]]::new(2^);^
%=% $w::GetCurrentConsoleFont($out, 0, $fntinf^);^
%=% $w::CloseHandle($out^);^
^
%=% $raw=$host.UI.RawUI;^
%=% $cur=$raw.WindowSize;^
%=% $lrg=$raw.MaxPhysicalWindowSize;^
^
%=% 'cml={0},cmt={1},cmr={2},cmb={3},cwx={4},cwy={5},cvx={6},cvy={7},cfx={8},cfy={9},chx={10},chy={11},ccx={12},ccy={13},clx={14},cly={15}' -f^
%===% $moninf[5], $moninf[6], $moninf[7], $moninf[8],^
%===% ($wrect[2]-$wrect[0]^), ($wrect[3]-$wrect[1]^),^
%===% ($crect[2]-$crect[0]^), ($crect[3]-$crect[1]^),^
%===% ($fntinf[1] -band 0xFFFF^), ($fntinf[1] -shr 16^),^
%===% [math]::Round(($crect[2]-$crect[0]^)/$cur.Width^), [math]::Round(($crect[3]-$crect[1]^)/$cur.Height^),^
%===% $cur.Width, $cur.Height,^
%===% $lrg.Width, $lrg.Height;^
^"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: %MoveWindow% X Y
:: X left side of the window
:: Y top of the window
set MoveWindow=for %%i in (1 2) do if %%i==2 (^
%=% for /f "tokens=1*" %%j in ("^!arg^!") do (powershell.exe -nop -ep Bypass -Command ^"^
%===% try {$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(\"user32.dll\"^)]^
%=======% public static extern int SetWindowPos(IntPtr hWnd^, IntPtr hWndInsertAfter^, int X^, int Y^, int cx^, int cy^, uint uFlags^);^
%=====% [DllImport(\"kernel32.dll\"^)]^
%=======% public static extern IntPtr GetConsoleWindow(^);^
%===% ';^
%===% $PROCESS_PER_MONITOR_DPI_AWARE=2;^
%===% try {$w::SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE^)} catch {$w::SetProcessDPIAware(^)}^
%===% $x=0; $y=0;^
%===% if (([Int32]::TryParse(\"%%~j\"^, [ref]$x^) -eq $false^) -or ([Int32]::TryParse(\"%%~k\"^, [ref]$y^) -eq $false^)^){^
%=====% [Console]::Error.WriteLine(\"Syntax Error`r`n Usage:`r`n%%MoveWindow%% X Y`r`n X left side of the window`r`n Y top of the window\"^);^
%=====% exit 1;^
%===% }^
%===% exit [int]($w::SetWindowPos($w::GetConsoleWindow(^)^, [IntPtr]::Zero^, $x^, $y^, 0^, 0^, 5^) -eq 0^)} catch {exit 1}^"^
%=% )^
%=% ^&endlocal^
) else setlocal EnableDelayedExpansion ^&set arg=
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
for /f %%i in ('%ConsoleInfo%') do set /a "%%i"
:: center the window
set /a "newX=cml+(cmr-cml)/2-cwx/2, newY=cmt+(cmb-cmt)/2-cwy/2"
%MoveWindow% %newX% %newY%
rem cell size in dots
set /a "CellSize.X=%chx%, CellSize.Y=%chy%"
rem Current Size of cmd window/console window
set /a "ConsoleSize.X=%ccx%, ConsoleSize.Y=%ccy%"
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:init
rem this code must execute after ConsoleInfo macro, if not this change font family to TERMINAL/RASTER, in window 10
chcp 65001 >nul
rem clear environment for faster execution of SET command
(
for /F "Tokens=1 delims==" %%v in ('set') do set "%%v="
set "Path=%SystemRoot%\system32"
set /a "CellSize.X=%CellSize.X%, CellSize.Y=%CellSize.Y%"
set /a "ConsoleSize.X=%ConsoleSize.X%, ConsoleSize.Y=%ConsoleSize.Y%"
)
rem for ansi sequence
for /F %%a in ('echo prompt $E^| cmd.exe') do set "ESC=%%a"
:: Hide the cursor
<nul set /p "=!ESC![?25l"
rem ALT+219
set "Char=█"
rem set "Char=*"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: macro Plot=Screen.Setpixel X Y R G B
set "Buffer="
rem (performance) variables ESC and Char are already defined, we expand them
rem only once during macro definition rather than each time the macro is called;
rem execute "likely" code in the IF branch, and "unlikely" code in the ELSE branch
set Plot=for %%# in (1 2) do if %%#==2 (^
%=% for /f "tokens=1-5 delims=, " %%1 in ("^!args^!") do (^
%===% if defined Buffer (^
%=====% if "^!Buffer:~100^!"=="" (^
%=======% set "Buffer=^!Buffer^!%ESC%[%%2;%%1H%ESC%[38;2;%%3;%%4;%%5m%Char%"^
%=====% ) else (^
%=======% ^<nul set /p "=^!Buffer^!%ESC%[%%2;%%1H%ESC%[38;2;%%3;%%4;%%5m%Char%%ESC%[0m"^
%=======% ^& set "Buffer="^
%=====% )^
%===% ) else (^
%=====% set "Buffer=%ESC%[%%2;%%1H%ESC%[38;2;%%3;%%4;%%5m%Char%"^
%===% )^
%=% )) else set args=
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Flush flush the variable buffer.
set Flush=^<nul set /p "=^!Buffer^!%ESC%[0m" ^& set "Buffer="
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
- Expert
- Posts: 960
- Joined: 15 Jun 2012 13:16
- Location: Italy, Rome
Re: Complete control of cmd windows
I have found an error on dimension reported.
The simple test:
zoom 125%
font size 7x14 consolas
size of console window in char 130x30
effettive font size (misurated with paint) 8x18
viewport.X=130x8=1040 - viewport.Y=30x18=540 -> 1040x540
console windows size (misurated) 1040x577, header (misurated)=37pix -> 1040x(540+37)
value returned by ConsoleInfo
the calcolate coords is incorrect because cwx and cwy are wrong
The simple test:
zoom 125%
font size 7x14 consolas
size of console window in char 130x30
effettive font size (misurated with paint) 8x18
viewport.X=130x8=1040 - viewport.Y=30x18=540 -> 1040x540
console windows size (misurated) 1040x577, header (misurated)=37pix -> 1040x(540+37)
value returned by ConsoleInfo
Code: Select all
console monitor boundaries: 0, 0, 1920, 1030
console window size: 1058, 587
console viewport size: 1040, 540
console font size: 6, 14
console charcell size: 8, 18
console current size: 130, 30
console largest size: 240, 55
Code: Select all
console monitor boundaries is OK
console window size NOT OK
console viewport size is OK
console font size NOT OK
console charcell is OK
console current size is OK
console largest size is OK
Code: Select all
:: center the window
set /a "newX=cml+(cmr-cml)/2-cwx/2"
set /a "newY=cmt+(cmb-cmt)/2-cwy/2"
-
- Expert
- Posts: 960
- Joined: 15 Jun 2012 13:16
- Location: Italy, Rome
Re: Complete control of cmd windows
for reduce code you can use this part
Code: Select all
rem setting step for better smoothing colors
set /A "mS=-(R*R), step=255*100000/-mS, stepL=128*100000/-mS"
if "%1"=="Red" set "RGB=^!C^! 0 0"
if "%1"=="Green" set "RGB=0 ^!C^! 0"
if "%1"=="Blue" set "RGB=0 0 ^!C^!"
if "%1"=="Yellow" set "RGB=^!C^! ^!C^! 0"
if "%1"=="Cyan" set "RGB=0 ^!C^! ^!C^!"
if "%1"=="Magenta" set "RGB=^!C^! 0 ^!C^!"
if "%1"=="White" set "RGB=^!C^! ^!C^! ^!C^!"
if "%1"=="Orange" set "RGB=^!C^! ^!CL^! 0"
if "%1"=="Pink" set "RGB=^!C^! 0 ^!CL^!"
rem (performance) we compare colors first instead of doing it for each painted cell
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y %RGB%
)
)
%flush%
goto :eof
Re: Complete control of cmd windows
It's a mess if you try inferring dots from pixels. I actually trust the values I get from the API because the results are promising. Centering works well for me.
And in order to avoid working with the font size in pixels (reported by the Console API), I calculate the size of the character cells in dots from values reported by the GDI API. This is more reliable and makes spheres round with all fonts and font sizes I tried.
And in order to avoid working with the font size in pixels (reported by the Console API), I calculate the size of the character cells in dots from values reported by the GDI API. This is more reliable and makes spheres round with all fonts and font sizes I tried.
Yeah, good ideafor reduce code you can use this part
-
- Expert
- Posts: 960
- Joined: 15 Jun 2012 13:16
- Location: Italy, Rome
Re: Complete control of cmd windows
Yes, the centering is still good although the data seem incorrect.aGerman wrote: ↑09 Oct 2022 16:12It's a mess if you try inferring dots from pixels. I actually trust the values I get from the API because the results are promising. Centering works well for me.
And in order to avoid working with the font size in pixels (reported by the Console API), I calculate the size of the character cells in dots from values reported by the GDI API. This is more relying and makes spheres round with all fonts and font sizes I tried.
Yeah, good ideafor reduce code you can use this part
to understand better I did this test:
- uses 100% zoom and 8x8 raster fonts
Code: Select all
@echo off
rem save this script in UTF-8
set "me=%~f0"
setlocal enableDelayedExpansion
if "%1"=="sphere" (
call :sphere %2 %3 %4 %5 %6 %7
goto :eof
)
title Spheres
mode CON: COLS=100 LINES=50
call :GetInfo
set /A Newsize.X=clx-1, Newsize.Y=cly-2
mode CON: COLS=!Newsize.X! LINES=!Newsize.Y!
call :GetInfo
call :AndCenter
rem multithread 9 thread
set /A "deltaX=ConsoleSize.X/3, deltaY=ConsoleSize.Y/3, Radius=deltaY/2"
start "" /B cmd.exe /c ""!me!" sphere Red 1 1 !deltaX! !deltaY! !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Green !deltaX! 1 !deltaX!*2 !deltaY! !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Blue !deltaX!*2 1 !deltaX!*3 !deltaY! !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Yellow 1 !deltaY!+1 !deltaX! !deltaY!*2 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Cyan !deltaX! !deltaY!+1 !deltaX!*2 !deltaY!*2 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Magenta !deltaX!*2 !deltaY!+1 !deltaX!*3 !deltaY!*2 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere White 1 !deltaY!*2+1 !deltaX! !deltaY!*3 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Orange !deltaX! !deltaY!*2+1 !deltaX!*2 !deltaY!*3 !Radius!"
start "" /B cmd.exe /c ""!me!" sphere Pink !deltaX!*2 !deltaY!*2+1 !deltaX!*3 !deltaY!*3 !Radius!"
pause>nul
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:sphere color Begin.X Begin.Y End.X End.Y Radius
rem title %1 %2 %3 %4 %5 %6
rem pause
call :init
set /A Bimg.x=%2, Bimg.y=%3
set /A Eimg.x=%4, Eimg.y=%5
set /A Radius=%6
rem cell size in dots
set /A xc=CellSize.X, yc=CellSize.Y
rem draw a circle (x-x0)^2+(y-y0)^2=r^2 . Implicit equation for simpler math.
rem set radius and center in cmd windows, assume screen ratio greater than one ie 1280/720=1.777
set /A "R=Radius*yc, X0=((Eimg.x-Bimg.x)/2+Bimg.x)*xc, Y0=Bimg.y*yc+R"
rem setting step for better smoothing colors
set /A "mS=-(R*R), step=255*100000/-mS, stepL=128*100000/-mS"
if "%1"=="Red" set "RGB=^!C^! 0 0"
if "%1"=="Green" set "RGB=0 ^!C^! 0"
if "%1"=="Blue" set "RGB=0 0 ^!C^!"
if "%1"=="Yellow" set "RGB=^!C^! ^!C^! 0"
if "%1"=="Cyan" set "RGB=0 ^!C^! ^!C^!"
if "%1"=="Magenta" set "RGB=^!C^! 0 ^!C^!"
if "%1"=="White" set "RGB=^!C^! ^!C^! ^!C^!"
if "%1"=="Orange" set "RGB=^!C^! ^!CL^! 0"
if "%1"=="Pink" set "RGB=^!C^! 0 ^!CL^!"
rem (performance) we compare colors first instead of doing it for each painted cell
For /L %%y in (!Bimg.y!,1,!Eimg.y!) do (
For /L %%x in (!Bimg.x!,1,!Eimg.x!) do (
set /A "px=%%x*xc, py=%%y*yc, x=px-x0, y=py-y0, S=y*y+x*x-R*R, C=-S*step/100000"
if !S! leq 0 %plot% %%x %%y %RGB%
)
)
%flush%
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:GetInfo
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The %ConsoleInfo% macro collects properties of the console window and its environment.
:: It prints a string in the following format to StdOut:
:: cml=N,cmt=N,cmr=N,cmb=N,cwx=N,cwy=N,cvx=N,cvy=N,cfx=N,cfy=N,chx=N,chy=N,ccx=N,ccy=N,clx=N,cly=N
:: With:
:: N different integral values of the below properties
:: cml left dots boundary of the monitor's workspace
:: cmt top dots boundary of the monitor's workspace
:: cmr right dots boundary of the monitor's workspace
:: cmb bottom dots boundary of the monitor's workspace
:: cwx current width of the console window as number of dots
:: cwy current height of the console window as number of dots
:: cvx current width of the console viewport as number of dots
:: cvy current height of the console viewport as number of dots
:: cfx console font width as number of pixels
:: cfy console font height as number of pixels
:: chx approximated console charcell width as number of dots
:: chy approximated console charcell height as number of dots
:: ccx current width of the console client window as number of character cells
:: ccy current height of the console client window as number of character cells
:: clx largest width of the console client window as number of character cells
:: cly largest height of the console client window as number of character cells
:: To define variables %cfx% .. %cly%, execute the macro in a FOR /F loop like that:
:: FOR /F %%I IN ('%ConsoleInfo%') DO SET /A "%%I"
set ConsoleInfo=^
powershell -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(\"kernel32.dll\"^)]^
%=====% public static extern IntPtr CreateFile(string name, int acc, int share, IntPtr sec, int how, int flags, IntPtr tmplt^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void GetCurrentConsoleFont(IntPtr hOut, int isMax, int[] info^);^
%===% [DllImport(\"kernel32.dll\"^)]^
%=====% public static extern void CloseHandle(IntPtr h^);^
%=% ';^
^
%=% $PROCESS_PER_MONITOR_DPI_AWARE=2;^
%=% try {$w::SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE^)} catch {$w::SetProcessDPIAware(^)}^
^
%=% $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^);^
^
%= 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^);^
^
%= The $crect 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 client window. =% ^
%=% $crect=[int[]]::new(4^);^
%=% $w::GetClientRect($hwnd, $crect^);^
^
%=% $NIL=[IntPtr]::Zero;^
%=% $GENERIC_READ=0x80000000;^
%=% $GENERIC_WRITE=0x40000000;^
%=% $FILE_SHARE_WRITE=0x00000002;^
%=% $OPEN_EXISTING=3;^
%= Because the StdOut stream is redirected to a pipe behind the scenes of a FOR /F loop, =% ^
%= we need to explicitly open a handle to the console output device (alias 'CONOUT$'). =% ^
%=% $out=$w::CreateFile('CONOUT$', $GENERIC_READ -bor $GENERIC_WRITE, $FILE_SHARE_WRITE, $NIL, $OPEN_EXISTING, 0, $NIL^);^
%= The $fntinf array is a replacement for the CONSOLE_FONT_INFO structure. The 16 low order bits of the =% ^
%= second element represent the font width, while its 16 high order bits represent the font height. =% ^
%=% $fntinf=[int[]]::new(2^);^
%=% $w::GetCurrentConsoleFont($out, 0, $fntinf^);^
%=% $w::CloseHandle($out^);^
^
%=% $raw=$host.UI.RawUI;^
%=% $cur=$raw.WindowSize;^
%=% $lrg=$raw.MaxPhysicalWindowSize;^
^
%=% 'cml={0},cmt={1},cmr={2},cmb={3},cwx={4},cwy={5},cvx={6},cvy={7},cfx={8},cfy={9},chx={10},chy={11},ccx={12},ccy={13},clx={14},cly={15}' -f^
%===% $moninf[5], $moninf[6], $moninf[7], $moninf[8],^
%===% ($wrect[2]-$wrect[0]^), ($wrect[3]-$wrect[1]^),^
%===% ($crect[2]-$crect[0]^), ($crect[3]-$crect[1]^),^
%===% ($fntinf[1] -band 0xFFFF^), ($fntinf[1] -shr 16^),^
%===% [math]::Round(($crect[2]-$crect[0]^)/$cur.Width^), [math]::Round(($crect[3]-$crect[1]^)/$cur.Height^),^
%===% $cur.Width, $cur.Height,^
%===% $lrg.Width, $lrg.Height;^
^"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: %MoveWindow% X Y
:: X left side of the window
:: Y top of the window
set MoveWindow=for %%i in (1 2) do if %%i==2 (^
%=% for /f "tokens=1*" %%j in ("^!arg^!") do (powershell.exe -nop -ep Bypass -Command ^"^
%===% try {$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(\"user32.dll\"^)]^
%=======% public static extern int SetWindowPos(IntPtr hWnd^, IntPtr hWndInsertAfter^, int X^, int Y^, int cx^, int cy^, uint uFlags^);^
%=====% [DllImport(\"kernel32.dll\"^)]^
%=======% public static extern IntPtr GetConsoleWindow(^);^
%===% ';^
%===% $PROCESS_PER_MONITOR_DPI_AWARE=2;^
%===% try {$w::SetProcessDpiAwareness($PROCESS_PER_MONITOR_DPI_AWARE^)} catch {$w::SetProcessDPIAware(^)}^
%===% $x=0; $y=0;^
%===% if (([Int32]::TryParse(\"%%~j\"^, [ref]$x^) -eq $false^) -or ([Int32]::TryParse(\"%%~k\"^, [ref]$y^) -eq $false^)^){^
%=====% [Console]::Error.WriteLine(\"Syntax Error`r`n Usage:`r`n%%MoveWindow%% X Y`r`n X left side of the window`r`n Y top of the window\"^);^
%=====% exit 1;^
%===% }^
%===% exit [int]($w::SetWindowPos($w::GetConsoleWindow(^)^, [IntPtr]::Zero^, $x^, $y^, 0^, 0^, 5^) -eq 0^)} catch {exit 1}^"^
%=% )^
%=% ^&endlocal^
) else setlocal EnableDelayedExpansion ^&set arg=
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
for /f %%i in ('%ConsoleInfo%') do set /a "%%i"
rem cell size in dots
set /a "CellSize.X=%chx%, CellSize.Y=%chy%"
rem Current Size of cmd window/console window
set /a "ConsoleSize.X=%ccx%, ConsoleSize.Y=%ccy%"
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:AndCenter
:: center the window
set /a "newX=cml+(cmr-cml)/2-cwx/2, newY=cmt+(cmb-cmt)/2-cwy/2"
%MoveWindow% %newX% %newY%
title Move to %newX%,%newY%
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:init
rem this code must execute after ConsoleInfo macro, if not this change font family to TERMINAL/RASTER, in window 10
chcp 65001 >nul
rem clear environment for faster execution of SET command
(
for /F "Tokens=1 delims==" %%v in ('set') do set "%%v="
set "Path=%SystemRoot%\system32"
set /a "CellSize.X=%CellSize.X%, CellSize.Y=%CellSize.Y%"
set /a "ConsoleSize.X=%ConsoleSize.X%, ConsoleSize.Y=%ConsoleSize.Y%"
)
rem for ansi sequence
for /F %%a in ('echo prompt $E^| cmd.exe') do set "ESC=%%a"
:: Hide the cursor
<nul set /p "=!ESC![?25l"
rem ALT+219
set "Char=█"
rem set "Char=*"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: macro Plot=Screen.Setpixel X Y R G B
set "Buffer="
rem (performance) variables ESC and Char are already defined, we expand them
rem only once during macro definition rather than each time the macro is called;
rem execute "likely" code in the IF branch, and "unlikely" code in the ELSE branch
set Plot=for %%# in (1 2) do if %%#==2 (^
%=% for /f "tokens=1-5 delims=, " %%1 in ("^!args^!") do (^
%===% if defined Buffer (^
%=====% if "^!Buffer:~100^!"=="" (^
%=======% set "Buffer=^!Buffer^!%ESC%[%%2;%%1H%ESC%[38;2;%%3;%%4;%%5m%Char%"^
%=====% ) else (^
%=======% ^<nul set /p "=^!Buffer^!%ESC%[%%2;%%1H%ESC%[38;2;%%3;%%4;%%5m%Char%%ESC%[0m"^
%=======% ^& set "Buffer="^
%=====% )^
%===% ) else (^
%=====% set "Buffer=%ESC%[%%2;%%1H%ESC%[38;2;%%3;%%4;%%5m%Char%"^
%===% )^
%=% )) else set args=
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Flush flush the variable buffer.
set Flush=^<nul set /p "=^!Buffer^!%ESC%[0m" ^& set "Buffer="
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
The X position is negative!