Common/Console.ps1
#---------------------------------------------------------------------------------------------------------------------- # MIT License # # Copyright (c) 2021 Mark Schofield # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. #---------------------------------------------------------------------------------------------------------------------- #Requires -PSEdition Core Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $CSharpCode = @' private const uint GENERIC_READ = 0x80000000; private const uint GENERIC_WRITE = 0x40000000; private const uint FILE_SHARE_READ = 0x00000001; private const uint FILE_SHARE_WRITE = 0x00000002; private const uint OPEN_EXISTING = 3; [DllImport("kernel32.dll", SetLastError = true, CharSet=CharSet.Unicode, ExactSpelling = true)] private static extern SafeFileHandle CreateFileW(string fileName, uint desiredAccess, uint shareMode, IntPtr securityAttributes, uint creationDisposition, uint flagsAndAttributes, IntPtr templateFile); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] public static extern uint GetConsoleMode(SafeFileHandle consoleHandle, out uint mode); public static SafeFileHandle GetConIn() { SafeFileHandle fileHandle = CreateFileW("CONIN$", GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); if (fileHandle.IsInvalid) { throw new System.ComponentModel.Win32Exception(); } return fileHandle; } public static SafeFileHandle GetConOut() { SafeFileHandle fileHandle = CreateFileW("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); if (fileHandle.IsInvalid) { throw new System.ComponentModel.Win32Exception(); } return fileHandle; } '@ $script:Console = $null $script:IsVirtualTerminalProcessingEnabled = if ($IsWindows) { $null } else { $true } function GetConsole { if (-not $script:Console) { $script:Console = Add-Type -Language CSharp -MemberDefinition $CSharpCode -Name NativeMethods -Namespace Console -PassThru -UsingNamespace 'Microsoft.Win32.SafeHandles' -ErrorAction SilentlyContinue if (-not $script:Console) { throw "Fatal error: Unable to compile the necessary C# code." } } $script:Console } <# .Synopsis Returns whether virtual terminal processing is enabled for the current console. .Outputs `$true` if virtual terminal processing is enabled, `$false` otherwise. #> function IsVirtualTerminalProcessingEnabled { if ($null -eq $script:IsVirtualTerminalProcessingEnabled) { $Console = GetConsole $ConOut = $Console::GetConOut(); try { $ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x04 $Mode = 0 if (($Console::GetConsoleMode($ConOut, [ref] $Mode) -eq 0) -or (-not($Mode -band $ENABLE_VIRTUAL_TERMINAL_PROCESSING))) { $script:IsVirtualTerminalProcessingEnabled = $false } else { $script:IsVirtualTerminalProcessingEnabled = $true } } finally { $ConOut.Close() } } $script:IsVirtualTerminalProcessingEnabled; } <# .Synopsis Returns the control codes to set the foreground color to the specified value. #> function ColorToControlCode{ param( [System.Drawing.Color]$Color ) if (IsVirtualTerminalProcessingEnabled) { "`e" + '[38;2;' + ('{0:d3}' -f $Color.R) + ';' + ('{0:d3}' -f $Color.G) + ';' + ('{0:d3}' -f $Color.B) + 'm' } } <# .Synopsis Returns the control codes to reset foreground attributes, if virtual terminal processing is enable. #> function ResetForegroundControlCode{ if (IsVirtualTerminalProcessingEnabled) { "`e[39m" } } |