Last active
March 19, 2023 13:39
-
-
Save Jaykul/f9aac8753b5fe39fa24a96bf7f4dc6b7 to your computer and use it in GitHub Desktop.
Virtual terminal queries (DECRQSS) return values as INPUT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-ColorMode { | |
<# | |
.SYNOPSIS | |
Tests for FullColor (RGB) mode and X11/XTerm (XColor) modes by writing SGR and verifying it with a DECRQSS | |
Returns "Uknown" if there's no DECRQSS support, or "FullColor" and/or "XColor" otherwise | |
#> | |
[CmdletBinding()] | |
param() | |
$ColorMode = @{ | |
'48:2:255:0:255' = 'FullColor' | |
'48:5:254' = 'XColor' | |
'48;2;255;0;255' = 'FullColorCompatible' | |
'48;5;254' = 'XColorCompatible' | |
} | |
$SupportedModes = @(foreach($SGR in $ColorMode.Keys) { | |
$DECRQSS = -join @( | |
# Set the background color | |
"`e[0m`e[$($SGR)m" | |
# Output the DECRQSS query | |
"`eP`$qm`e`\" | |
# Reset the background | |
"`e[49m" | |
) | |
# strip the DCS and ST from the ends of the response and return just the SGR value as the Response | |
$Result = Get-VtResponse $DECRQSS | Select-CapturedString '(?:\u001BP|\u0090)(?<Result>\d+)\$r(?:0;)?(?<Code>.*)m(?:\u001B[\\\t])' | |
Write-Verbose "$($Result.Result)r$($Result.Code)m" | |
# the result code is supposed to be 1 no matter what, no idea what other values represent, really | |
if ($Result.Result -ne 1) { | |
Write-Verbose "Request Status String (DECRQSS) not supported (returned $($Result.Result))" | |
continue | |
} | |
if ($Result.Code -ne $SGR) { | |
Write-Verbose "Received unexpected result, our '$($SGR)' color mode wasn't supported (returned $($Result.Result))" | |
continue | |
} | |
$SGR | |
}) | |
$ColorMode[$SupportedModes] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-VtResponse { | |
<# | |
.SYNOPSIS | |
Write a VT ANSI escape sequence to the host and capture the response | |
.EXAMPLE | |
$Row, $Col = (Get-VtResponse "`e[6n") -split ';' -replace "[`e\[R]" | |
Gets the current cursor position into $Row and $Col | |
#> | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory)] | |
$Sequence | |
) | |
[console]::write($sequence) | |
@(while ([console]::KeyAvailable) { | |
[console]::ReadKey($true).KeyChar | |
}) -join "" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Select-CapturedString { | |
<# | |
.Synopsis | |
Collect named capture groups from regular expression matches | |
(I still don't like the name of this function) | |
.Description | |
Takes string data and a regular expression containing named captures, | |
and outputs all of the resulting captures in one (or more) hashtable(s) | |
.Example | |
netstat | Select-CapturedString "(?<Protocol>\w{3})\s+(?<LocalIP>(\d{1,3}\.){3}\d{1,3}):(?<LocalPort>\d+)\s+(?<ForeignIP>.*):(?<ForeignPort>\d+)\s+(?<State>\w+)?" | |
This is an example of how to use it for parsing when all the values are on one line | |
.Example | |
"Revoked Certificates: | |
Serial Number: 011F63068E6BCD8CABF644026B80A903 | |
Revocation Date: Jul 8 06:22:01 2012 GMT | |
Serial Number: 01205F0018B6758D741B3DB43CFB26C2 | |
Revocation Date: Feb 18 06:11:14 2013 GMT | |
Serial Number: 012607175D820413ED0750E96B833A8F | |
Revocation Date: Jun 11 03:12:11 2015 GMT | |
" | Select-CapturedString "(?m)Serial Number:\s+(?<SerialNumber>.*)\s*$|Revocation Date:\s+(?<RevocationDate>.*)\s*$" -Auto | |
SerialNumber RevocationDate | |
------------ -------------- | |
011F63068E6BCD8CABF644026B80A903 Jul 8 06:22:01 2012 GMT | |
01205F0018B6758D741B3DB43CFB26C2 Feb 18 06:11:14 2013 GMT | |
012607175D820413ED0750E96B833A8F Jun 11 03:12:11 2015 GMT | |
When your values are on multiple lines, you can use the -AutoGroup switch to automatically collect sets of matches. | |
#> | |
param( | |
# The text to search for captures | |
[Parameter(ValueFromPipeline=$true)] | |
[string]$text, | |
# A regular expression containing named capture groups (see examples) | |
[Parameter(Position=1)] | |
[regex]$re, | |
# By default, each match is returned as a single object. | |
# When set, empty captures are ignored, and properties are collected until the capture groups repeat, allowing the collection of many lines using an OR regex (see Example 2) | |
[switch]$AutoGroup, | |
# If set, hide properties with empty values (default to the same as $AutoGroup) | |
[switch]$HideEmpty = $AutoGroup | |
) | |
begin { | |
[string[]]$FullData = $text | |
} | |
process { | |
[string[]]$FullData += $text | |
} | |
end { | |
$text = $FullData -join "`n" | |
if ($VerbosePreference -eq "Continue") { | |
Write-Verbose "Regex $re" | |
Write-Verbose "Data $(-join $text.GetEnumerator().ForEach{ if (27 -ge $_) { [char](0x2400 + $_) } else { "$_" } })" | |
} | |
$names = $re.GetGroupNames().Where{ $_ -ne 0 } | |
$result = [ordered]@{} | |
foreach ($match in $re.Matches($text).Where{$_.Success}) { | |
Write-Verbose (-join $match.Value.GetEnumerator().ForEach{ if (27 -ge $_) { [char](0x2400 + $_) } else { "$_" } }) | |
foreach ($name in $names) { | |
if (-not $HideEmpty -or $match.Groups[$name].Value) { | |
if ($AutoGroup -and $result.ContainsKey($name)) { | |
[PSCustomObject]$result | |
$result = [ordered]@{} | |
} | |
$result.$name = $match.Groups[$name].Value | |
} | |
} | |
if (!$AutoGroup) { | |
[PSCustomObject]$result | |
$result = [ordered]@{} | |
} | |
} | |
if ($result) { | |
[PSCustomObject]$result | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Test-RgbMode { | |
<# | |
.SYNOPSIS | |
Writes an RGB color using 48;2;;;m and verifies it with a DECRQSS for SGR | |
#> | |
[CmdletBinding()] | |
param() | |
$RGBMagentaBackground = '48;2;255;0;255' | |
[Console]::Write( -join @( | |
# Set the background color | |
"`e[0;${RGBMagentaBackground}m" | |
# Output the DECRQSS query | |
"`eP`$qm`e`\" | |
# Reset the background | |
"`e[49m" | |
)) | |
# Terminal responses show up as fake console input | |
$Response = @(while ([console]::KeyAvailable) { | |
[console]::ReadKey($true).KeyChar | |
}) -join "" | |
# strip the DCS and ST from the ends of the response and return just the SGR value as the Response | |
$Result, $Response = $Response -replace '^(?:\u001BP|\u0090)(\d+)\$r(?:0;)?(.*)m(?:\u001B[\\\t])$','$1,$2' -split ',' | |
Write-Verbose "$($Result)r$($Response)m" | |
# the result code is supposed to be 1 (no idea what other values represent, really) | |
if ($Result -ne 1) { | |
Write-Warning "Request Status String (DECRQSS) not supported (returned $Result)" | |
$False | |
} else { | |
# If the response isn't what we put in, then there's no RGB support | |
$Response -eq $RGBMagentaBackground | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment