mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-10 08:11:06 +00:00
Compare commits
13 Commits
dev/miniks
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
491ec14291 | ||
|
|
90271426e9 | ||
|
|
f5939ebd61 | ||
|
|
5074335392 | ||
|
|
8ffff8ea37 | ||
|
|
57ad2d57fd | ||
|
|
f1441a589c | ||
|
|
988fe0ba60 | ||
|
|
de1de4425e | ||
|
|
8d52ba0990 | ||
|
|
a0782bfd6c | ||
|
|
fa5b9b06bd | ||
|
|
7067910862 |
@@ -46,6 +46,14 @@ steps:
|
||||
clean: true
|
||||
maximumCpuCount: true
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Check MSIX for common regressions'
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: |
|
||||
$Package = Get-ChildItem -Recurse -Filter "CascadiaPackage_*.msix"
|
||||
.\build\scripts\Test-WindowsTerminalPackage.ps1 -Verbose -Path $Package.FullName
|
||||
|
||||
- task: VSTest@2
|
||||
displayName: 'Run Unit Tests'
|
||||
inputs:
|
||||
|
||||
79
build/scripts/Test-WindowsTerminalPackage.ps1
Normal file
79
build/scripts/Test-WindowsTerminalPackage.ps1
Normal file
@@ -0,0 +1,79 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true,
|
||||
HelpMessage="Path to the .appx/.msix to validate")]
|
||||
[string]
|
||||
$Path,
|
||||
|
||||
[Parameter(HelpMessage="Path to Windows Kit")]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$WindowsKitPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
If ($null -Eq (Get-Item $WindowsKitPath -EA:SilentlyContinue)) {
|
||||
Write-Error "Could not find a windows SDK at at `"$WindowsKitPath`".`nMake sure that WindowsKitPath points to a valid SDK."
|
||||
Exit 1
|
||||
}
|
||||
|
||||
$makeAppx = "$WindowsKitPath\x86\MakeAppx.exe"
|
||||
$makePri = "$WindowsKitPath\x86\MakePri.exe"
|
||||
|
||||
Function Expand-ApplicationPackage {
|
||||
Param(
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
|
||||
$sentinelFile = New-TemporaryFile
|
||||
$directory = New-Item -Type Directory "$($sentinelFile.FullName)_Package"
|
||||
Remove-Item $sentinelFile -Force -EA:Ignore
|
||||
|
||||
& $makeAppx unpack /p $Path /d $directory /nv /o
|
||||
|
||||
If ($LastExitCode -Ne 0) {
|
||||
Throw "Failed to expand AppX"
|
||||
}
|
||||
|
||||
$directory
|
||||
}
|
||||
|
||||
Write-Verbose "Expanding $Path"
|
||||
$AppxPackageRoot = Expand-ApplicationPackage $Path
|
||||
$AppxPackageRootPath = $AppxPackageRoot.FullName
|
||||
|
||||
Write-Verbose "Expanded to $AppxPackageRootPath"
|
||||
|
||||
Try {
|
||||
& $makePri dump /if "$AppxPackageRootPath\resources.pri" /of "$AppxPackageRootPath\resources.pri.xml" /o
|
||||
If ($LastExitCode -Ne 0) {
|
||||
Throw "Failed to dump PRI"
|
||||
}
|
||||
|
||||
$Manifest = [xml](Get-Content "$AppxPackageRootPath\AppxManifest.xml")
|
||||
$PRIFile = [xml](Get-Content "$AppxPackageRootPath\resources.pri.xml")
|
||||
|
||||
### Check the activatable class entries for a few DLLs we need.
|
||||
$inProcServers = $Manifest.Package.Extensions.Extension.InProcessServer.Path
|
||||
$RequiredInProcServers = ("TerminalApp.dll", "TerminalControl.dll", "TerminalConnection.dll")
|
||||
|
||||
Write-Verbose "InProc Servers: $inProcServers"
|
||||
|
||||
ForEach ($req in $RequiredInProcServers) {
|
||||
If ($req -NotIn $inProcServers) {
|
||||
Throw "Failed to find $req in InProcServer list $inProcServers"
|
||||
}
|
||||
}
|
||||
|
||||
### Check that we have an App.xbf (which is a proxy for our resources having been merged)
|
||||
$resourceXpath = '/PriInfo/ResourceMap/ResourceMapSubtree[@name="Files"]/NamedResource[@name="App.xbf"]'
|
||||
$AppXbf = $PRIFile.SelectSingleNode($resourceXpath)
|
||||
If ($null -eq $AppXbf) {
|
||||
Throw "Failed to find App.xbf (TerminalApp project) in resources.pri"
|
||||
}
|
||||
} Finally {
|
||||
Remove-Item -Recurse -Force $AppxPackageRootPath
|
||||
}
|
||||
97
conpty.txt
Normal file
97
conpty.txt
Normal file
@@ -0,0 +1,97 @@
|
||||
[25l[2J[m[HMicrosoft Windows [Version 10.0.18936.1001]]0;C:\WINDOWS\system32\cmd.exe[?25h
|
||||
(c) 2019 Microsoft Corporation. All rights reserved.
|
||||
[30m[107m
|
||||
[11:54:25.95][97m[46m>c:\Users\migrie\dev\private\OpenConsole[36m[49m>[m [35m
|
||||
[1][m [43m[dev/migrie/f/passthrough-2019][m [94mmigrie[m@[32mMIGRIE-SURFBOOK[m>wsl.exe
|
||||
]0;C:\WINDOWS\system32\cmd.exe - wsl.exe[92mzadjii@migrie-surfbook[m:[94m/mnt/c/Users/migrie/dev/private/OpenConsole[m$ ]0;zadjii@migrie-surfbook: /mnt/c/Users/migrie/dev/private/OpenConsolevi README.md
|
||||
[25l[?2004h[22;0;0t[?2004h[H[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X[H[?25h[25l[38;2;128;128;128m[48;2;28;28;28m[30;1H"README.md" 177L, 11259C[96X[?25h[96C[25l[?2004l[?2004h[30;25H[?25h[25l[?2004l[?2004h[2;1H▽[?25h[25l[>c]10;?]11;?
|
||||
[H[?25h[38;2;0;95;0m[48;2;175;215;0m README.md [38;2;175;215;0m[48;2;18;18;18m [38;2;255;255;255m[97X[38;2;18;18;18m[97C◀[38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m buffers [38;2;78;78;78m[48;2;38;38;38m
|
||||
1 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Welcome\! [22m[38;2;128;128;128m[104X[38;2;78;78;78m[48;2;38;38;38m
|
||||
2 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m This repository contains the source code for:[22m[38;2;128;128;128m[66X[38;2;78;78;78m[48;2;38;38;38m
|
||||
3 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
4 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m Windows Terminal[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
5 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m The Windows console host ([38;2;0;175;175mconhost.exe[38;2;128;128;128m)[74X[38;2;78;78;78m[48;2;38;38;38m
|
||||
6 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m Components shared between the two projects[70X[38;2;78;78;78m[48;2;38;38;38m
|
||||
7 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mColorTool[38;2;128;128;128m[103X[38;2;78;78;78m[48;2;38;38;38m
|
||||
8 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [m[112X[112C[38;2;128;128;128m[48;2;28;28;28m[38;2;78;78;78m[48;2;38;38;38m
|
||||
8 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mSample projects[38;2;128;128;128m that show how to consume the Window[61X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28ms Console APIs[102X[38;2;78;78;78m[48;2;38;38;38m
|
||||
9 [38;2;28;28;28m[48;2;78;78;78m [38;2;128;128;128m[48;2;28;28;28m[114X[38;2;78;78;78m[48;2;38;38;38m
|
||||
10 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m Other related repositories include:[22m[38;2;128;128;128m[76X[38;2;78;78;78m[48;2;38;38;38m
|
||||
11 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mConsole API Documentation[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
12 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
13 [38;2;128;128;128m[48;2;28;28;28m###[1m[38;2;215;95;0m Build Status[22m[38;2;128;128;128m[100X[38;2;78;78;78m[48;2;38;38;38m
|
||||
14 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
15 [38;2;128;128;128m[48;2;28;28;28mProject|Build Status[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
16 [38;2;128;128;128m[48;2;28;28;28m---|---[109X[38;2;78;78;78m[48;2;38;38;38m
|
||||
17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[18X[m[18C[77X[77C[38;2;128;128;128m[48;2;28;28;28m[38;2;78;78;78m[48;2;38;38;38m
|
||||
17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[95X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[106X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[97C[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004h[38;2;215;0;0m[48;2;215;95;0m[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m [38;2;18;18;18m<[38;2;255;255;255m markdown [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 3% [1m␊ 6/177 ㏑[22m : 46 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]trailing [38;2;215;0;0m◀]0;/mnt/c/Users/migrie/dev/private/OpenConsole/README.md[25l[38;2;255;255;255m[48;2;18;18;18m[38;2;158;158;158m[48;2;48;48;48m[29;11H+0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m <[7;50H[?25h[25l[38;2;128;128;128m[48;2;28;28;28m[30;110H^[[7;50H[?25h[25l[30;110H [7;50H[?25h[25l[?2004h[30;1H:[109X[?25hq
|
||||
[?2004l]0;[?2004l[120X[120C[25l[23;0;0t[m[HMicrosoft Windows [Version 10.0.18936.1001][77X
|
||||
(c) 2019 Microsoft Corporation. All rights reserved.[68X
|
||||
[120X[30m[107m
|
||||
[11:54:25.95][97m[46m>c:\Users\migrie\dev\private\OpenConsole[36m[49m>[m[66X[35m
|
||||
[1][m [43m[dev/migrie/f/passthrough-2019][m [94mmigrie[m@[32mMIGRIE-SURFBOOK[m>wsl.exe[54X[92m
|
||||
zadjii@migrie-surfbook[m:[94m/mnt/c/Users/migrie/dev/private/OpenConsole[m$ vi README.md [39X[92m
|
||||
zadjii@migrie-surfbook[m:[94m/mnt/c/Users/migrie/dev/private/OpenConsole[m$ [52X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X[7;69H]0;zadjii@migrie-surfbook: /mnt/c/Users/migrie/dev/private/OpenConsole[?25h
|
||||
273
conpty001.txt
Normal file
273
conpty001.txt
Normal file
@@ -0,0 +1,273 @@
|
||||
[25l[2J[m[HMicrosoft Windows [Version 10.0.18936.1001]]0;C:\WINDOWS\system32\cmd.exe[?25h
|
||||
(c) 2019 Microsoft Corporation. All rights reserved.
|
||||
[59X[30m[107m
|
||||
[12:00:25.93][97m[46m>c:\Users\migrie\dev\private\OpenConsole[36m[49m>[m [35m
|
||||
[1][m [43m[dev/migrie/f/passthrough-2019][m [94mmigrie[m@[32mMIGRIE-SURFBOOK[m>wsl.exe
|
||||
]0;C:\WINDOWS\system32\cmd.exe - wsl.exe[92mzadjii@migrie-surfbook[m:[94m/mnt/c/Users/migrie/dev/private/OpenConsole[m$ ]0;zadjii@migrie-surfbook: /mnt/c/Users/migrie/dev/private/OpenConsolevi README.md
|
||||
[25l[?2004h[22;0;0t[?2004h[H[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X[H[?25h[25l[38;2;128;128;128m[48;2;28;28;28m[30;1H"README.md" 177L, 11259C[96X[?25h[96C[25l[?2004l[?2004h[30;25H[?25h[25l[?2004l[?2004h[2;1H▽[?25h[25l
|
||||
[H[?25h[>c]10;?]11;?[38;2;0;95;0m[48;2;175;215;0m README.md [38;2;175;215;0m[48;2;18;18;18m [38;2;255;255;255m[97X[38;2;18;18;18m[97C◀[38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m buffers [38;2;78;78;78m[48;2;38;38;38m
|
||||
1 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Welcome\! [22m[38;2;128;128;128m[104X[38;2;78;78;78m[48;2;38;38;38m
|
||||
2 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m This repository contains the source code for:[22m[38;2;128;128;128m[66X[38;2;78;78;78m[48;2;38;38;38m
|
||||
3 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
4 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m Windows Terminal[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
5 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m The Windows console host ([38;2;0;175;175mconhost.exe[38;2;128;128;128m)[74X[38;2;78;78;78m[48;2;38;38;38m
|
||||
6 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m Components shared between the two projects[70X[38;2;78;78;78m[48;2;38;38;38m
|
||||
7 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mColorTool[38;2;128;128;128m[103X[38;2;78;78;78m[48;2;38;38;38m
|
||||
8 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [m[112X[112C[38;2;128;128;128m[48;2;28;28;28m[38;2;78;78;78m[48;2;38;38;38m
|
||||
8 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mSample projects[38;2;128;128;128m that show how to consume the Window[61X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28ms Console APIs[102X[38;2;78;78;78m[48;2;38;38;38m
|
||||
9 [38;2;28;28;28m[48;2;78;78;78m [38;2;128;128;128m[48;2;28;28;28m[114X[38;2;78;78;78m[48;2;38;38;38m
|
||||
10 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m Other related repositories include:[22m[38;2;128;128;128m[76X[38;2;78;78;78m[48;2;38;38;38m
|
||||
11 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mConsole API Documentation[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
12 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
13 [38;2;128;128;128m[48;2;28;28;28m###[1m[38;2;215;95;0m Build Status[22m[38;2;128;128;128m[100X[38;2;78;78;78m[48;2;38;38;38m
|
||||
14 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
15 [38;2;128;128;128m[48;2;28;28;28mProject|Build Status[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
16 [38;2;128;128;128m[48;2;28;28;28m---|---[109X[38;2;78;78;78m[48;2;38;38;38m
|
||||
17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[18X[m[18C[77X[77C[38;2;128;128;128m[48;2;28;28;28m[38;2;78;78;78m[48;2;38;38;38m
|
||||
17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[95X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[106X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[97C[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004l[?2004h[?2004h[38;2;215;0;0m[48;2;215;95;0m[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m [38;2;18;18;18m<[38;2;255;255;255m markdown [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 3% [1m␊ 6/177 ㏑[22m : 46 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]trailing [38;2;215;0;0m◀]0;/mnt/c/Users/migrie/dev/private/OpenConsole/README.md[25l[38;2;255;255;255m[48;2;18;18;18m[38;2;158;158;158m[48;2;48;48;48m[29;11H+0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m <[7;50H[?25h[25l[38;2;128;128;128m[48;2;28;28;28m[30;110H~@k[?25h[25l[38;2;175;0;0m[8;9H[[38;2;95;95;175mColorTool[38;2;175;0;0m]([38;2;0;175;175mhttps://github.com/Microsoft/Terminal/tree/master/src/tools/ColorTool[38;2;175;0;0m)[38;2;128;128;128m[22X[38;2;95;95;175m[9;9HSample projects[38;2;128;128;128m that show how to consume the Window[53X[10;9Hnsole APIs[94X[11;9H[104X[1m[38;2;215;95;0m
|
||||
Other related repositories include:[22m[38;2;128;128;128m[68X[38;2;95;95;175m[13;9HConsole API Documentation[38;2;128;128;128m[79X[14;9H[104X[1m[38;2;215;95;0m
|
||||
Build Status[22m[38;2;128;128;128m[92X[16;9H[104X
|
||||
ect|Build Status[88X[18;9H---[101X[19;9Hinal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[87X[20;9H[104X
|
||||
rTool|[98X[22;9H[104X
|
||||
[104X[1m[38;2;215;95;0m
|
||||
rminal & Console Overview[22m[38;2;128;128;128m[79X[25;9H[104X
|
||||
se take a few minutes to review the overview below before diving into the code:[25X[27;9H[104X[1m[38;2;215;95;0m
|
||||
indows Terminal[22m[38;2;128;128;128m[89X[38;2;175;215;0m[48;2;48;48;48m[29;9H▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 3% [1m␊ 7/177 ㏑[22m : 46 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;9Hmd" 177L, 11259C[88X[8;50H[?25h[25l[30;110H~@k[?25h[25l[38;2;78;78;78m[48;2;38;38;38m[8;1H 7 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mColorTool[38;2;128;128;128m[103X[38;2;78;78;78m[48;2;38;38;38m
|
||||
8 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;175;0;0m[[38;2;95;95;175mSample projects[38;2;175;0;0m]([38;2;0;175;175mhttps://github.com/Microsoft/Terminal/tree/master/samples[38;2;175;0;0m)[38;2;128;128;128m that show how to consume the Window[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28ms Console APIs[102X[38;2;78;78;78m[48;2;38;38;38m
|
||||
9 [38;2;28;28;28m[48;2;78;78;78m [38;2;128;128;128m[48;2;28;28;28m[114X[38;2;78;78;78m[48;2;38;38;38m
|
||||
10 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m Other related repositories include:[22m[38;2;128;128;128m[76X[38;2;78;78;78m[48;2;38;38;38m
|
||||
11 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mConsole API Documentation[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
12 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
13 [38;2;128;128;128m[48;2;28;28;28m###[1m[38;2;215;95;0m Build Status[22m[38;2;128;128;128m[100X[38;2;78;78;78m[48;2;38;38;38m
|
||||
14 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
15 [38;2;128;128;128m[48;2;28;28;28mProject|Build Status[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
16 [38;2;128;128;128m[48;2;28;28;28m---|---[109X[38;2;78;78;78m[48;2;38;38;38m
|
||||
17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[95X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[106X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 4% [1m␊ 8/177 ㏑[22m : 46 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]trailing [38;2;215;0;0m◀[38;2;128;128;128m[48;2;28;28;28m
|
||||
"README.md" 177L, 11259C[96X[9;50H[?25h[25l[30;110H~@k[?25h[25l[38;2;78;78;78m[48;2;38;38;38m[9;1H 8 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mSample projects[38;2;128;128;128m that show how to consume the Window[61X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28ms Console APIs[102X[38;2;78;78;78m[48;2;38;38;38m
|
||||
9 [38;2;28;28;28m[48;2;78;78;78m [38;2;128;128;128m[48;2;28;28;28m[114X[38;2;78;78;78m[48;2;38;38;38m
|
||||
10 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m Other related repositories include:[22m[38;2;128;128;128m[76X[38;2;78;78;78m[48;2;38;38;38m
|
||||
11 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mConsole API Documentation[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
12 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
13 [38;2;128;128;128m[48;2;28;28;28m###[1m[38;2;215;95;0m Build Status[22m[38;2;128;128;128m[100X[38;2;78;78;78m[48;2;38;38;38m
|
||||
14 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
15 [38;2;128;128;128m[48;2;28;28;28mProject|Build Status[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
16 [38;2;128;128;128m[48;2;28;28;28m---|---[109X[38;2;78;78;78m[48;2;38;38;38m
|
||||
17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[95X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[106X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 5% [1m␊ 9/177 ㏑[22m : 2 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]trailing [38;2;215;0;0m◀[38;2;128;128;128m[48;2;28;28;28m
|
||||
"README.md" 177L, 11259C[96X[11;6H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[1m[29;89H10/177 ㏑[22m : 40 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;89H[24X[12;44H[?25h[25l[30;110H~@k[?25h[25l[38;2;175;0;0m[13;9H[[38;2;95;95;175mConsole API Documentation[38;2;175;0;0m]([38;2;0;175;175mhttps://github.com/MicrosoftDocs/Console-Docs[38;2;175;0;0m)[38;2;128;128;128m[30X[14;9H[104X[1m[38;2;215;95;0m
|
||||
Build Status[22m[38;2;128;128;128m[92X[16;9H[104X
|
||||
ect|Build Status[88X[18;9H---[101X[19;9Hinal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[87X[20;9H[104X
|
||||
rTool|[98X[22;9H[104X
|
||||
[104X[1m[38;2;215;95;0m
|
||||
rminal & Console Overview[22m[38;2;128;128;128m[79X[25;9H[104X
|
||||
se take a few minutes to review the overview below before diving into the code:[25X[27;9H[104X[1m[38;2;215;95;0m
|
||||
indows Terminal[22m[38;2;128;128;128m[89X[38;2;175;215;0m[48;2;48;48;48m[29;9H▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 6% [1m␊ 11/177 ㏑[22m : 46 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;9Hmd" 177L, 11259C[88X[13;50H[?25h[25l[30;110H~@k[?25h[25l[38;2;95;95;175m[13;9HConsole API Documentation[38;2;128;128;128m[79X[14;9H[104X[1m[38;2;215;95;0m
|
||||
Build Status[22m[38;2;128;128;128m[92X[16;9H[104X
|
||||
ect|Build Status[88X[18;9H---[101X[19;9Hinal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[87X[20;9H[104X
|
||||
rTool|[98X[22;9H[104X
|
||||
[104X[1m[38;2;215;95;0m
|
||||
rminal & Console Overview[22m[38;2;128;128;128m[79X[25;9H[104X
|
||||
se take a few minutes to review the overview below before diving into the code:[25X[27;9H[104X[1m[38;2;215;95;0m
|
||||
indows Terminal[22m[38;2;128;128;128m[89X[38;2;175;215;0m[48;2;48;48;48m[29;9H▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 6% [1m␊ 12/177 ㏑[22m : 1 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;9Hmd" 177L, 11259C[88X[14;5H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[29;83H7% [1m␊ 13/177 ㏑[22m : 16 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;83H[30X[15;20H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[1m[29;90H4/177 ㏑[22m : 1 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;90H[23X[16;5H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[29;83H8% [1m␊ 15/177 ㏑[22m : 20 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;83H[30X[17;24H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[29;83H9% [1m␊ 16/177 ㏑[22m : 7 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;83H[30X[18;11H[?25h[25l[30;110H~@k[?25h[25l[38;2;175;0;0m[38;2;78;78;78m[48;2;38;38;38m[19;1H 17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;175;0;0m[]([38;2;0;175;175mhtt[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;0;175;175m[48;2;28;28;28mps://dev.azure.com/ms/Terminal/_build?definitionId=136[38;2;175;0;0m)[38;2;128;128;128m[61X[38;2;78;78;78m[48;2;38;38;38m
|
||||
18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[106X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 9% [1m␊ 17/177 ㏑[22m : 46 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]trailing [38;2;215;0;0m◀[38;2;128;128;128m[48;2;28;28;28m
|
||||
"README.md" 177L, 11259C[96X[19;50H[?25h[25l[30;110H~@k[?25h[25l[38;2;175;0;0m[38;2;78;78;78m[48;2;38;38;38m[19;1H 17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[95X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[38;2;175;0;0m[38;2;128;128;128m[103X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 10% [1m␊ 18/177 ㏑[22m : 46 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]trailing [38;2;215;0;0m◀[38;2;128;128;128m[48;2;28;28;28m
|
||||
"README.md" 177L, 11259C[96X[21;50H[?25h[25l[30;110H~@k[?25h[25l[38;2;78;78;78m[48;2;38;38;38m[21;1H 18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[106X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 10% [1m␊ 19/177 ㏑[22m : 1 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]trailing [38;2;215;0;0m◀[38;2;128;128;128m[48;2;28;28;28m
|
||||
"README.md" 177L, 11259C[96X[23;5H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[29;83H1% [1m␊ 20/177 ㏑[22m : 29 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;83H[30X[24;33H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[1m[29;90H1/177 ㏑[22m : 1 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;90H[23X[25;5H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[38;2;78;78;78m[48;2;38;38;38m[2;1H 2 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m This repository contains the source code for:[22m[38;2;128;128;128m[66X[38;2;78;78;78m[48;2;38;38;38m
|
||||
3 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
4 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m Windows Terminal[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
5 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m The Windows console host ([38;2;0;175;175mconhost.exe[38;2;128;128;128m)[74X[38;2;78;78;78m[48;2;38;38;38m
|
||||
6 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m Components shared between the two projects[70X[38;2;78;78;78m[48;2;38;38;38m
|
||||
7 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mColorTool[38;2;128;128;128m[103X[38;2;78;78;78m[48;2;38;38;38m
|
||||
8 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mSample projects[38;2;128;128;128m that show how to consume the Window[61X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28ms Console APIs[102X[38;2;78;78;78m[48;2;38;38;38m
|
||||
9 [38;2;28;28;28m[48;2;78;78;78m [38;2;128;128;128m[48;2;28;28;28m[114X[38;2;78;78;78m[48;2;38;38;38m
|
||||
10 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m Other related repositories include:[22m[38;2;128;128;128m[76X[38;2;78;78;78m[48;2;38;38;38m
|
||||
11 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mConsole API Documentation[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
12 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
13 [38;2;128;128;128m[48;2;28;28;28m###[1m[38;2;215;95;0m Build Status[22m[38;2;128;128;128m[100X[38;2;78;78;78m[48;2;38;38;38m
|
||||
14 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
15 [38;2;128;128;128m[48;2;28;28;28mProject|Build Status[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
16 [38;2;128;128;128m[48;2;28;28;28m---|---[109X[38;2;78;78;78m[48;2;38;38;38m
|
||||
17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[95X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[106X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[38;2;78;78;78m[48;2;38;38;38m
|
||||
25 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 12% [1m␊ 22/177 ㏑[22m : 46 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]trailing [38;2;215;0;0m◀[38;2;128;128;128m[48;2;28;28;28m
|
||||
[120X[25;50H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[38;2;78;78;78m[48;2;38;38;38m[2;1H 5 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m The Windows console host ([38;2;0;175;175mconhost.exe[38;2;128;128;128m)[74X[38;2;78;78;78m[48;2;38;38;38m
|
||||
6 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m Components shared between the two projects[70X[38;2;78;78;78m[48;2;38;38;38m
|
||||
7 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mColorTool[38;2;128;128;128m[103X[38;2;78;78;78m[48;2;38;38;38m
|
||||
8 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mSample projects[38;2;128;128;128m that show how to consume the Window[61X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28ms Console APIs[102X[38;2;78;78;78m[48;2;38;38;38m
|
||||
9 [38;2;28;28;28m[48;2;78;78;78m [38;2;128;128;128m[48;2;28;28;28m[114X[38;2;78;78;78m[48;2;38;38;38m
|
||||
10 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m Other related repositories include:[22m[38;2;128;128;128m[76X[38;2;78;78;78m[48;2;38;38;38m
|
||||
11 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mConsole API Documentation[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
12 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
13 [38;2;128;128;128m[48;2;28;28;28m###[1m[38;2;215;95;0m Build Status[22m[38;2;128;128;128m[100X[38;2;78;78;78m[48;2;38;38;38m
|
||||
14 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
15 [38;2;128;128;128m[48;2;28;28;28mProject|Build Status[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
16 [38;2;128;128;128m[48;2;28;28;28m---|---[109X[38;2;78;78;78m[48;2;38;38;38m
|
||||
17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[95X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[106X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[38;2;78;78;78m[48;2;38;38;38m
|
||||
25 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
26 [38;2;128;128;128m[48;2;28;28;28mWindows Terminal is a new, modern, feature-rich, productive terminal application for command-line users. It includes[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m many of the features most frequently requested by the Windows command-line community including support for tabs, ri[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28mch text, globalization, configurability, theming & styling, and more.[47X[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m < [38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 12% [1m␊ 23/177 ㏑[22m : 1 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]trailing [38;2;215;0;0m◀[38;2;128;128;128m[48;2;28;28;28m
|
||||
[120X[23;5H[?25h[25l[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[29;83H3% [1m␊ 24/177 ㏑[22m : 19 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [9]tr[38;2;128;128;128m[48;2;28;28;28m[30;83H[30X[24;23H[?25h[25l[38;2;8;8;8m[48;2;215;95;0m[38;2;48;48;48m[48;2;18;18;18m[29;55H◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 13% [1m␊ 24/177 ㏑[22m : 19 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [64[24;23H[?25h[25l[38;2;128;128;128m[48;2;28;28;28m[30;110H~@k[?25h[25l[38;2;0;95;0m[48;2;175;215;0m[38;2;78;78;78m[48;2;38;38;38m[2;1H 1 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Welcome\! [22m[38;2;128;128;128m[104X[38;2;78;78;78m[48;2;38;38;38m
|
||||
2 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m This repository contains the source code for:[22m[38;2;128;128;128m[66X[38;2;78;78;78m[48;2;38;38;38m
|
||||
3 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
4 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m Windows Terminal[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
5 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m The Windows console host ([38;2;0;175;175mconhost.exe[38;2;128;128;128m)[74X[38;2;78;78;78m[48;2;38;38;38m
|
||||
6 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m Components shared between the two projects[70X[38;2;78;78;78m[48;2;38;38;38m
|
||||
7 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mColorTool[38;2;128;128;128m[103X[38;2;78;78;78m[48;2;38;38;38m
|
||||
8 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mSample projects[38;2;128;128;128m that show how to consume the Window[61X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28ms Console APIs[102X[38;2;78;78;78m[48;2;38;38;38m
|
||||
9 [38;2;28;28;28m[48;2;78;78;78m [38;2;128;128;128m[48;2;28;28;28m[114X[38;2;78;78;78m[48;2;38;38;38m
|
||||
10 [38;2;128;128;128m[48;2;28;28;28m####[1m[38;2;215;95;0m Other related repositories include:[22m[38;2;128;128;128m[76X[38;2;78;78;78m[48;2;38;38;38m
|
||||
11 [38;2;0;135;255m[48;2;28;28;28m *[38;2;128;128;128m [38;2;95;95;175mConsole API Documentation[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
12 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
13 [38;2;128;128;128m[48;2;28;28;28m###[1m[38;2;215;95;0m Build Status[22m[38;2;128;128;128m[100X[38;2;78;78;78m[48;2;38;38;38m
|
||||
14 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
15 [38;2;128;128;128m[48;2;28;28;28mProject|Build Status[96X[38;2;78;78;78m[48;2;38;38;38m
|
||||
16 [38;2;128;128;128m[48;2;28;28;28m---|---[109X[38;2;78;78;78m[48;2;38;38;38m
|
||||
17 [38;2;128;128;128m[48;2;28;28;28mTerminal|[38;2;95;95;175mBuild Status[38;2;128;128;128m[95X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
18 [38;2;128;128;128m[48;2;28;28;28mColorTool|[106X[38;2;78;78;78m[48;2;38;38;38m
|
||||
[38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
19 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
20 [38;2;128;128;128m[48;2;28;28;28m#[1m[38;2;215;95;0m Terminal & Console Overview[22m[38;2;128;128;128m[87X[38;2;78;78;78m[48;2;38;38;38m
|
||||
21 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
22 [38;2;128;128;128m[48;2;28;28;28mPlease take a few minutes to review the overview below before diving into the code:[33X[38;2;78;78;78m[48;2;38;38;38m
|
||||
23 [38;2;128;128;128m[48;2;28;28;28m[116X[38;2;78;78;78m[48;2;38;38;38m
|
||||
24 [38;2;128;128;128m[48;2;28;28;28m##[1m[38;2;215;95;0m Windows Terminal[22m[38;2;128;128;128m[97X[38;2;0;95;0m[48;2;175;215;0m
|
||||
[1mNORMAL[22m [38;2;175;215;0m[48;2;48;48;48m▶[38;2;158;158;158m +0 ~0 -0 ⎇ dev/migrie/f/passthrough-2019 [38;2;48;48;48m[48;2;18;18;18m▶[38;2;255;255;255m <[38;2;48;48;48m◀[38;2;158;158;158m[48;2;48;48;48m [unix] [38;2;175;215;0m◀[38;2;0;95;0m[48;2;175;215;0m 1,397 words « 3% [1m␊ 6/177 ㏑[22m : 3 [38;2;215;95;0m◀[38;2;8;8;8m[48;2;215;95;0m Ξ [64]trailing [38;2;215;0;0m◀[38;2;128;128;128m[48;2;28;28;28m
|
||||
[120X[7;7H[?25h[25l[30;110H^[[7;7H[?25h[25l[30;110H [7;7H[?25h[25l[?2004h[30;1H:[109X[?25hq
|
||||
[?2004l]0;[?2004l[120X[120C[25l[23;0;0t[m[HMicrosoft Windows [Version 10.0.18936.1001][77X
|
||||
(c) 2019 Microsoft Corporation. All rights reserved.[68X
|
||||
[120X[30m[107m
|
||||
[12:00:25.93][97m[46m>c:\Users\migrie\dev\private\OpenConsole[36m[49m>[m[66X[35m
|
||||
[1][m [43m[dev/migrie/f/passthrough-2019][m [94mmigrie[m@[32mMIGRIE-SURFBOOK[m>wsl.exe[54X[92m
|
||||
zadjii@migrie-surfbook[m:[94m/mnt/c/Users/migrie/dev/private/OpenConsole[m$ vi README.md [39X[92m
|
||||
zadjii@migrie-surfbook[m:[94m/mnt/c/Users/migrie/dev/private/OpenConsole[m$ [52X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
[120X
|
||||
9
passthough.txt
Normal file
9
passthough.txt
Normal file
File diff suppressed because one or more lines are too long
38
passthrough001.txt
Normal file
38
passthrough001.txt
Normal file
File diff suppressed because one or more lines are too long
@@ -260,24 +260,6 @@
|
||||
<PRIResource Include="Resources\en-US\Resources.resw" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(OpenConsoleDir)src\wap-common.build.post.props" />
|
||||
<!--
|
||||
Microsoft.UI.Xaml contains some <Content> resource files that need to be included in our package.
|
||||
For some reason, they're not rolled up through dependent projects; if they were, their paths would
|
||||
be wrong.
|
||||
|
||||
WAP Packaging projects don't actually support nuget package references, so we added one manually.
|
||||
|
||||
This does mean that version changes to Microsoft.UI.Xaml must be manually reflected
|
||||
here.
|
||||
-->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<!-- End workaround -->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WindowsTerminal\WindowsTerminal.vcxproj" />
|
||||
<ProjectReference Include="..\..\host\exe\Host.EXE.vcxproj" />
|
||||
|
||||
@@ -61,26 +61,13 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void App::Create(uint64_t hWnd)
|
||||
void App::Create()
|
||||
{
|
||||
// Assert that we've already loaded our settings. We have to do
|
||||
// this as a MTA, before the app is Create()'d
|
||||
WINRT_ASSERT(_loadedInitialSettings);
|
||||
TraceLoggingRegister(g_hTerminalAppProvider);
|
||||
_Create(hWnd);
|
||||
}
|
||||
|
||||
App::~App()
|
||||
{
|
||||
TraceLoggingUnregister(g_hTerminalAppProvider);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create all of the initial UI elements of the Terminal app.
|
||||
// * Initializes the first terminal control, using the default profile,
|
||||
// and adds it to our list of tabs.
|
||||
void App::_Create(uint64_t parentHwnd)
|
||||
{
|
||||
/* !!! TODO
|
||||
This is not the correct way to host a XAML page. This exists today because we valued
|
||||
getting a .xaml over tearing out all of the terminal logic and splitting it across App
|
||||
@@ -92,15 +79,21 @@ namespace winrt::TerminalApp::implementation
|
||||
_root = terminalPage.as<winrt::Windows::UI::Xaml::Controls::Control>();
|
||||
_tabContent = terminalPage->TabContent();
|
||||
_tabRow = terminalPage->TabRow();
|
||||
_tabView = terminalPage->TabView();
|
||||
_newTabButton = terminalPage->NewTabButton();
|
||||
_tabView = _tabRow.TabView();
|
||||
_newTabButton = _tabRow.NewTabButton();
|
||||
|
||||
_minMaxCloseControl = terminalPage->MinMaxCloseControl();
|
||||
_minMaxCloseControl.ParentWindowHandle(parentHwnd);
|
||||
|
||||
if (!_settings->GlobalSettings().GetShowTabsInTitlebar())
|
||||
if (_settings->GlobalSettings().GetShowTabsInTitlebar())
|
||||
{
|
||||
_minMaxCloseControl.Visibility(Visibility::Collapsed);
|
||||
// Remove the TabView from the page. We'll hang on to it, we need to
|
||||
// put it in the titlebar.
|
||||
uint32_t index = 0;
|
||||
if (terminalPage->Root().Children().IndexOf(_tabRow, index))
|
||||
{
|
||||
terminalPage->Root().Children().RemoveAt(index);
|
||||
}
|
||||
|
||||
// Inform the host that our titlebar content has changed.
|
||||
_setTitleBarContentHandlers(*this, _tabRow);
|
||||
}
|
||||
|
||||
// Event Bindings (Early)
|
||||
@@ -118,6 +111,14 @@ namespace winrt::TerminalApp::implementation
|
||||
_tabContent.SizeChanged({ this, &App::_OnContentSizeChanged });
|
||||
}
|
||||
|
||||
App::~App()
|
||||
{
|
||||
if (g_hTerminalAppProvider)
|
||||
{
|
||||
TraceLoggingUnregister(g_hTerminalAppProvider);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Show a ContentDialog with a single button to dismiss. Uses the
|
||||
// FrameworkElements provided as the title and content of this dialog, and
|
||||
@@ -456,16 +457,6 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Windows::System::Launcher::LaunchUriAsync({ feedbackUriValue });
|
||||
}
|
||||
|
||||
Windows::UI::Xaml::Controls::Border App::GetDragBar() noexcept
|
||||
{
|
||||
if (_minMaxCloseControl)
|
||||
{
|
||||
return _minMaxCloseControl.DragBar();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the about button is clicked. See _ShowAboutDialog for more info.
|
||||
// Arguments:
|
||||
@@ -493,6 +484,7 @@ namespace winrt::TerminalApp::implementation
|
||||
bindings.NewTab([this]() { _OpenNewTab(std::nullopt); });
|
||||
bindings.DuplicateTab([this]() { _DuplicateTabViewItem(); });
|
||||
bindings.CloseTab([this]() { _CloseFocusedTab(); });
|
||||
bindings.ClosePane([this]() { _CloseFocusedPane(); });
|
||||
bindings.NewTabWithProfile([this](const auto index) { _OpenNewTab({ index }); });
|
||||
bindings.ScrollUp([this]() { _Scroll(-1); });
|
||||
bindings.ScrollDown([this]() { _Scroll(1); });
|
||||
@@ -505,6 +497,7 @@ namespace winrt::TerminalApp::implementation
|
||||
bindings.SwitchToTab([this](const auto index) { _SelectTab({ index }); });
|
||||
bindings.OpenSettings([this]() { _OpenSettings(); });
|
||||
bindings.ResizePane([this](const auto direction) { _ResizePane(direction); });
|
||||
bindings.MoveFocus([this](const auto direction) { _MoveFocus(direction); });
|
||||
bindings.CopyText([this](const auto trimWhitespace) { _CopyText(trimWhitespace); });
|
||||
bindings.PasteText([this]() { _PasteText(); });
|
||||
}
|
||||
@@ -741,13 +734,16 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update the current theme of the application. This will manually update
|
||||
// all of the elements in our UI to match the given theme.
|
||||
// - Update the current theme of the application. This will trigger our
|
||||
// RequestedThemeChanged event, to have our host change the theme of the
|
||||
// root of the application.
|
||||
// Arguments:
|
||||
// - newTheme: The ElementTheme to apply to our elements.
|
||||
void App::_ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme)
|
||||
{
|
||||
_root.RequestedTheme(newTheme);
|
||||
// Propagate the event to the host layer, so it can update its own UI
|
||||
_requestedThemeChangedHandlers(*this, newTheme);
|
||||
}
|
||||
|
||||
UIElement App::GetRoot() noexcept
|
||||
@@ -911,20 +907,16 @@ namespace winrt::TerminalApp::implementation
|
||||
// currently displayed, it will be shown.
|
||||
// Arguments:
|
||||
// - settings: the TerminalSettings object to use to create the TerminalControl with.
|
||||
void App::_CreateNewTabFromSettings(GUID profileGuid, TerminalSettings settings, std::optional<uint64_t> serverHandle)
|
||||
void App::_CreateNewTabFromSettings(GUID profileGuid, TerminalSettings settings)
|
||||
{
|
||||
// Initialize the new tab
|
||||
|
||||
TerminalConnection::ITerminalConnection connection = nullptr;
|
||||
// Create a Conhost connection based on the values in our settings object.
|
||||
if (!serverHandle)
|
||||
{
|
||||
connection = TerminalConnection::ConhostConnection(settings.Commandline(), settings.StartingDirectory(), 30, 80, winrt::guid());
|
||||
}
|
||||
else
|
||||
{
|
||||
connection = TerminalConnection::ConhostConnection(serverHandle.value(), 30, 80, winrt::guid());
|
||||
}
|
||||
auto connection = TerminalConnection::ConhostConnection(settings.Commandline(),
|
||||
settings.StartingDirectory(),
|
||||
30,
|
||||
80,
|
||||
winrt::guid());
|
||||
|
||||
TermControl term{ settings, connection };
|
||||
|
||||
@@ -993,6 +985,17 @@ namespace winrt::TerminalApp::implementation
|
||||
_RemoveTabViewItem(focusedTab->GetTabViewItem());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Close the currently focused pane. If the pane is the last pane in the
|
||||
// tab, the tab will also be closed. This will happen when we handle the
|
||||
// tab's Closed event.
|
||||
void App::_CloseFocusedPane()
|
||||
{
|
||||
int focusedTabIndex = _GetFocusedTabIndex();
|
||||
std::shared_ptr<Tab> focusedTab{ _tabs[focusedTabIndex] };
|
||||
focusedTab->ClosePane();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Move the viewport of the terminal of the currently focused tab up or
|
||||
// down a number of lines. Negative values of `delta` will move the
|
||||
@@ -1036,6 +1039,20 @@ namespace winrt::TerminalApp::implementation
|
||||
_tabs[focusedTabIndex]->ResizePane(direction);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempt to move focus between panes, as to focus the child on
|
||||
// the other side of the separator. See Pane::NavigateFocus for details.
|
||||
// - Moves the focus of the currently focused tab.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void App::_MoveFocus(const Direction& direction)
|
||||
{
|
||||
const auto focusedTabIndex = _GetFocusedTabIndex();
|
||||
_tabs[focusedTabIndex]->NavigateFocus(direction);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Copy text from the focused terminal to the Windows Clipboard
|
||||
// Arguments:
|
||||
@@ -1166,33 +1183,6 @@ namespace winrt::TerminalApp::implementation
|
||||
return { L"Windows Terminal" };
|
||||
}
|
||||
|
||||
void App::IncomingConnection(uint64_t serverHandle)
|
||||
{
|
||||
_root.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this, serverHandle]() {
|
||||
// Getting Guid for default profile
|
||||
const auto globalSettings = _settings->GlobalSettings();
|
||||
auto profileGuid = globalSettings.GetDefaultProfile();
|
||||
TerminalSettings settings = _settings->MakeSettings(profileGuid);
|
||||
|
||||
_CreateNewTabFromSettings(profileGuid, settings, serverHandle);
|
||||
});
|
||||
}
|
||||
|
||||
void App::IncomingConnection(hstring cmdline, hstring workingDir)
|
||||
{
|
||||
_root.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this, cmdline, workingDir]() {
|
||||
// Getting Guid for default profile
|
||||
const auto globalSettings = _settings->GlobalSettings();
|
||||
auto profileGuid = globalSettings.GetDefaultProfile();
|
||||
TerminalSettings settings = _settings->MakeSettings(profileGuid);
|
||||
|
||||
settings.Commandline(cmdline);
|
||||
settings.StartingDirectory(workingDir);
|
||||
|
||||
_CreateNewTabFromSettings(profileGuid, settings);
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Additional responses to clicking on a TabView's item. Currently, just remove tab with middle click
|
||||
// Arguments:
|
||||
@@ -1243,7 +1233,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (focusedTabIndex >= _tabs.size())
|
||||
{
|
||||
focusedTabIndex = _tabs.size() - 1;
|
||||
focusedTabIndex = static_cast<int>(_tabs.size()) - 1;
|
||||
}
|
||||
|
||||
if (focusedTabIndex < 0)
|
||||
@@ -1338,7 +1328,11 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto controlSettings = _settings->MakeSettings(realGuid);
|
||||
|
||||
// Create a Conhost connection based on the values in our settings object.
|
||||
TerminalConnection::ITerminalConnection controlConnection = TerminalConnection::ConhostConnection(controlSettings.Commandline(), controlSettings.StartingDirectory(), 30, 80, winrt::guid());
|
||||
auto controlConnection = TerminalConnection::ConhostConnection(controlSettings.Commandline(),
|
||||
controlSettings.StartingDirectory(),
|
||||
30,
|
||||
80,
|
||||
winrt::guid());
|
||||
|
||||
TermControl newControl{ controlSettings, controlConnection };
|
||||
|
||||
@@ -1439,4 +1433,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// These macros will define them both for you.
|
||||
DEFINE_EVENT(App, TitleChanged, _titleChangeHandlers, TerminalControl::TitleChangedEventArgs);
|
||||
DEFINE_EVENT(App, LastTabClosed, _lastTabClosedHandlers, winrt::TerminalApp::LastTabClosedEventArgs);
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(App, SetTitleBarContent, _setTitleBarContentHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::UIElement);
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(App, RequestedThemeChanged, _requestedThemeChangedHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::ElementTheme);
|
||||
}
|
||||
|
||||
@@ -27,10 +27,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
Windows::UI::Xaml::UIElement GetRoot() noexcept;
|
||||
|
||||
// Gets the current dragglable area in the non client region of the top level window
|
||||
Windows::UI::Xaml::Controls::Border GetDragBar() noexcept;
|
||||
|
||||
void Create(uint64_t hParentWnd);
|
||||
void Create();
|
||||
void LoadSettings();
|
||||
|
||||
Windows::Foundation::Point GetLaunchDimensions(uint32_t dpi);
|
||||
@@ -40,12 +37,11 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
hstring GetTitle();
|
||||
|
||||
void IncomingConnection(uint64_t serverHandle);
|
||||
void IncomingConnection(hstring cmdline, hstring workingDir);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
DECLARE_EVENT(TitleChanged, _titleChangeHandlers, winrt::Microsoft::Terminal::TerminalControl::TitleChangedEventArgs);
|
||||
DECLARE_EVENT(LastTabClosed, _lastTabClosedHandlers, winrt::TerminalApp::LastTabClosedEventArgs);
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(SetTitleBarContent, _setTitleBarContentHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::UIElement);
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(RequestedThemeChanged, _requestedThemeChangedHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::ElementTheme);
|
||||
|
||||
private:
|
||||
// If you add controls here, but forget to null them either here or in
|
||||
@@ -56,10 +52,9 @@ namespace winrt::TerminalApp::implementation
|
||||
// (which is a root when the tabs are in the titlebar.)
|
||||
Windows::UI::Xaml::Controls::Control _root{ nullptr };
|
||||
Microsoft::UI::Xaml::Controls::TabView _tabView{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Grid _tabRow{ nullptr };
|
||||
TerminalApp::TabRowControl _tabRow{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Grid _tabContent{ nullptr };
|
||||
Windows::UI::Xaml::Controls::SplitButton _newTabButton{ nullptr };
|
||||
winrt::TerminalApp::MinMaxCloseControl _minMaxCloseControl{ nullptr };
|
||||
|
||||
std::vector<std::shared_ptr<Tab>> _tabs;
|
||||
|
||||
@@ -74,7 +69,6 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
std::atomic<bool> _settingsReloadQueued{ false };
|
||||
|
||||
void _Create(uint64_t parentHWnd);
|
||||
void _CreateNewTabFlyout();
|
||||
|
||||
fire_and_forget _ShowDialog(const winrt::Windows::Foundation::IInspectable& titleElement,
|
||||
@@ -103,11 +97,12 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _RegisterTerminalEvents(Microsoft::Terminal::TerminalControl::TermControl term, std::shared_ptr<Tab> hostingTab);
|
||||
|
||||
void _CreateNewTabFromSettings(GUID profileGuid, winrt::Microsoft::Terminal::Settings::TerminalSettings settings, std::optional<uint64_t> serverHandle = std::nullopt);
|
||||
void _CreateNewTabFromSettings(GUID profileGuid, winrt::Microsoft::Terminal::Settings::TerminalSettings settings);
|
||||
|
||||
void _OpenNewTab(std::optional<int> profileIndex);
|
||||
void _DuplicateTabViewItem();
|
||||
void _CloseFocusedTab();
|
||||
void _CloseFocusedPane();
|
||||
void _SelectNextTab(const bool bMoveRight);
|
||||
void _SelectTab(const int tabIndex);
|
||||
|
||||
@@ -125,6 +120,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// MSFT:20641986: Add keybindings for New Window
|
||||
void _ScrollPage(int delta);
|
||||
void _ResizePane(const Direction& direction);
|
||||
void _MoveFocus(const Direction& direction);
|
||||
|
||||
void _OnLoaded(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
void _OnTabSelectionChanged(const IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& eventArgs);
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
namespace TerminalApp
|
||||
{
|
||||
delegate void LastTabClosedEventArgs();
|
||||
[default_interface]
|
||||
runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
|
||||
[default_interface] runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
|
||||
{
|
||||
App();
|
||||
|
||||
@@ -16,22 +15,20 @@ namespace TerminalApp
|
||||
// then it might look like TermApp just failed to activate, which will
|
||||
// cause you to chase down the rabbit hole of "why is TermApp not
|
||||
// registered?" when it definitely is.
|
||||
void Create(UInt64 hParentWnd);
|
||||
void Create();
|
||||
|
||||
void LoadSettings();
|
||||
|
||||
Windows.UI.Xaml.UIElement GetRoot();
|
||||
Windows.UI.Xaml.Controls.Border GetDragBar{ get; };
|
||||
|
||||
Windows.Foundation.Point GetLaunchDimensions(UInt32 dpi);
|
||||
Boolean GetShowTabsInTitlebar();
|
||||
|
||||
event Microsoft.Terminal.TerminalControl.TitleChangedEventArgs TitleChanged;
|
||||
event LastTabClosedEventArgs LastTabClosed;
|
||||
event Windows.Foundation.TypedEventHandler<App, Windows.UI.Xaml.UIElement> SetTitleBarContent;
|
||||
event Windows.Foundation.TypedEventHandler<App, Windows.UI.Xaml.ElementTheme> RequestedThemeChanged;
|
||||
|
||||
String GetTitle();
|
||||
|
||||
void IncomingConnection(UInt64 serverHandle);
|
||||
void IncomingConnection(String cmdline, String workingDir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,9 @@ namespace winrt::TerminalApp::implementation
|
||||
case ShortcutAction::CloseTab:
|
||||
_CloseTabHandlers();
|
||||
return true;
|
||||
case ShortcutAction::ClosePane:
|
||||
_ClosePaneHandlers();
|
||||
return true;
|
||||
|
||||
case ShortcutAction::ScrollUp:
|
||||
_ScrollUpHandlers();
|
||||
@@ -169,7 +172,18 @@ namespace winrt::TerminalApp::implementation
|
||||
case ShortcutAction::ResizePaneDown:
|
||||
_ResizePaneHandlers(Direction::Down);
|
||||
return true;
|
||||
|
||||
case ShortcutAction::MoveFocusLeft:
|
||||
_MoveFocusHandlers(Direction::Left);
|
||||
return true;
|
||||
case ShortcutAction::MoveFocusRight:
|
||||
_MoveFocusHandlers(Direction::Right);
|
||||
return true;
|
||||
case ShortcutAction::MoveFocusUp:
|
||||
_MoveFocusHandlers(Direction::Up);
|
||||
return true;
|
||||
case ShortcutAction::MoveFocusDown:
|
||||
_MoveFocusHandlers(Direction::Down);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -238,6 +252,7 @@ namespace winrt::TerminalApp::implementation
|
||||
DEFINE_EVENT(AppKeyBindings, NewWindow, _NewWindowHandlers, TerminalApp::NewWindowEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, CloseWindow, _CloseWindowHandlers, TerminalApp::CloseWindowEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, CloseTab, _CloseTabHandlers, TerminalApp::CloseTabEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, ClosePane, _ClosePaneHandlers, TerminalApp::ClosePaneEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, SwitchToTab, _SwitchToTabHandlers, TerminalApp::SwitchToTabEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, NextTab, _NextTabHandlers, TerminalApp::NextTabEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, PrevTab, _PrevTabHandlers, TerminalApp::PrevTabEventArgs);
|
||||
@@ -251,5 +266,6 @@ namespace winrt::TerminalApp::implementation
|
||||
DEFINE_EVENT(AppKeyBindings, ScrollDownPage, _ScrollDownPageHandlers, TerminalApp::ScrollDownPageEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, OpenSettings, _OpenSettingsHandlers, TerminalApp::OpenSettingsEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, ResizePane, _ResizePaneHandlers, TerminalApp::ResizePaneEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, MoveFocus, _MoveFocusHandlers, TerminalApp::MoveFocusEventArgs);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace winrt::TerminalApp::implementation
|
||||
DECLARE_EVENT(NewWindow, _NewWindowHandlers, TerminalApp::NewWindowEventArgs);
|
||||
DECLARE_EVENT(CloseWindow, _CloseWindowHandlers, TerminalApp::CloseWindowEventArgs);
|
||||
DECLARE_EVENT(CloseTab, _CloseTabHandlers, TerminalApp::CloseTabEventArgs);
|
||||
DECLARE_EVENT(ClosePane, _ClosePaneHandlers, TerminalApp::ClosePaneEventArgs);
|
||||
DECLARE_EVENT(SwitchToTab, _SwitchToTabHandlers, TerminalApp::SwitchToTabEventArgs);
|
||||
DECLARE_EVENT(NextTab, _NextTabHandlers, TerminalApp::NextTabEventArgs);
|
||||
DECLARE_EVENT(PrevTab, _PrevTabHandlers, TerminalApp::PrevTabEventArgs);
|
||||
@@ -61,6 +62,7 @@ namespace winrt::TerminalApp::implementation
|
||||
DECLARE_EVENT(ScrollDownPage, _ScrollDownPageHandlers, TerminalApp::ScrollDownPageEventArgs);
|
||||
DECLARE_EVENT(OpenSettings, _OpenSettingsHandlers, TerminalApp::OpenSettingsEventArgs);
|
||||
DECLARE_EVENT(ResizePane, _ResizePaneHandlers, TerminalApp::ResizePaneEventArgs);
|
||||
DECLARE_EVENT(MoveFocus, _MoveFocusHandlers, TerminalApp::MoveFocusEventArgs);
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace TerminalApp
|
||||
NewWindow,
|
||||
CloseWindow,
|
||||
CloseTab,
|
||||
ClosePane,
|
||||
NextTab,
|
||||
PrevTab,
|
||||
SplitVertical,
|
||||
@@ -53,6 +54,10 @@ namespace TerminalApp
|
||||
ResizePaneRight,
|
||||
ResizePaneUp,
|
||||
ResizePaneDown,
|
||||
MoveFocusLeft,
|
||||
MoveFocusRight,
|
||||
MoveFocusUp,
|
||||
MoveFocusDown,
|
||||
OpenSettings
|
||||
};
|
||||
|
||||
@@ -64,6 +69,7 @@ namespace TerminalApp
|
||||
delegate void NewWindowEventArgs();
|
||||
delegate void CloseWindowEventArgs();
|
||||
delegate void CloseTabEventArgs();
|
||||
delegate void ClosePaneEventArgs();
|
||||
delegate void NextTabEventArgs();
|
||||
delegate void PrevTabEventArgs();
|
||||
delegate void SplitVerticalEventArgs();
|
||||
@@ -77,9 +83,9 @@ namespace TerminalApp
|
||||
delegate void ScrollDownPageEventArgs();
|
||||
delegate void OpenSettingsEventArgs();
|
||||
delegate void ResizePaneEventArgs(Direction direction);
|
||||
delegate void MoveFocusEventArgs(Direction direction);
|
||||
|
||||
[default_interface]
|
||||
runtimeclass AppKeyBindings : Microsoft.Terminal.Settings.IKeyBindings
|
||||
[default_interface] runtimeclass AppKeyBindings : Microsoft.Terminal.Settings.IKeyBindings
|
||||
{
|
||||
AppKeyBindings();
|
||||
|
||||
@@ -94,6 +100,7 @@ namespace TerminalApp
|
||||
event NewWindowEventArgs NewWindow;
|
||||
event CloseWindowEventArgs CloseWindow;
|
||||
event CloseTabEventArgs CloseTab;
|
||||
event ClosePaneEventArgs ClosePane;
|
||||
event SwitchToTabEventArgs SwitchToTab;
|
||||
event NextTabEventArgs NextTab;
|
||||
event PrevTabEventArgs PrevTab;
|
||||
@@ -107,5 +114,6 @@ namespace TerminalApp
|
||||
event ScrollDownPageEventArgs ScrollDownPage;
|
||||
event OpenSettingsEventArgs OpenSettings;
|
||||
event ResizePaneEventArgs ResizePane;
|
||||
event MoveFocusEventArgs MoveFocus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ static constexpr std::string_view NewTabWithProfile8Key{ "newTabProfile8" };
|
||||
static constexpr std::string_view NewWindowKey{ "newWindow" };
|
||||
static constexpr std::string_view CloseWindowKey{ "closeWindow" };
|
||||
static constexpr std::string_view CloseTabKey{ "closeTab" };
|
||||
static constexpr std::string_view ClosePaneKey{ "closePane" };
|
||||
static constexpr std::string_view SwitchtoTabKey{ "switchToTab" };
|
||||
static constexpr std::string_view NextTabKey{ "nextTab" };
|
||||
static constexpr std::string_view PrevTabKey{ "prevTab" };
|
||||
@@ -55,6 +56,10 @@ static constexpr std::string_view ResizePaneLeftKey{ "resizePaneLeft" };
|
||||
static constexpr std::string_view ResizePaneRightKey{ "resizePaneRight" };
|
||||
static constexpr std::string_view ResizePaneUpKey{ "resizePaneUp" };
|
||||
static constexpr std::string_view ResizePaneDownKey{ "resizePaneDown" };
|
||||
static constexpr std::string_view MoveFocusLeftKey{ "moveFocusLeft" };
|
||||
static constexpr std::string_view MoveFocusRightKey{ "moveFocusRight" };
|
||||
static constexpr std::string_view MoveFocusUpKey{ "moveFocusUp" };
|
||||
static constexpr std::string_view MoveFocusDownKey{ "moveFocusDown" };
|
||||
|
||||
// Specifically use a map here over an unordered_map. We want to be able to
|
||||
// iterate over these entries in-order when we're serializing the keybindings.
|
||||
@@ -82,6 +87,7 @@ static const std::map<std::string_view, ShortcutAction, std::less<>> commandName
|
||||
{ NewWindowKey, ShortcutAction::NewWindow },
|
||||
{ CloseWindowKey, ShortcutAction::CloseWindow },
|
||||
{ CloseTabKey, ShortcutAction::CloseTab },
|
||||
{ ClosePaneKey, ShortcutAction::ClosePane },
|
||||
{ NextTabKey, ShortcutAction::NextTab },
|
||||
{ PrevTabKey, ShortcutAction::PrevTab },
|
||||
{ IncreaseFontSizeKey, ShortcutAction::IncreaseFontSize },
|
||||
@@ -105,6 +111,10 @@ static const std::map<std::string_view, ShortcutAction, std::less<>> commandName
|
||||
{ ResizePaneRightKey, ShortcutAction::ResizePaneRight },
|
||||
{ ResizePaneUpKey, ShortcutAction::ResizePaneUp },
|
||||
{ ResizePaneDownKey, ShortcutAction::ResizePaneDown },
|
||||
{ MoveFocusLeftKey, ShortcutAction::MoveFocusLeft },
|
||||
{ MoveFocusRightKey, ShortcutAction::MoveFocusRight },
|
||||
{ MoveFocusUpKey, ShortcutAction::MoveFocusUp },
|
||||
{ MoveFocusDownKey, ShortcutAction::MoveFocusDown },
|
||||
{ OpenSettingsKey, ShortcutAction::OpenSettings },
|
||||
};
|
||||
|
||||
|
||||
@@ -287,8 +287,8 @@ void CascadiaSettings::_CreateDefaultKeybindings()
|
||||
KeyChord{ KeyModifiers::Ctrl | KeyModifiers::Shift,
|
||||
static_cast<int>('D') });
|
||||
|
||||
keyBindings.SetKeyBinding(ShortcutAction::CloseTab,
|
||||
KeyChord{ KeyModifiers::Ctrl,
|
||||
keyBindings.SetKeyBinding(ShortcutAction::ClosePane,
|
||||
KeyChord{ KeyModifiers::Ctrl | KeyModifiers::Shift,
|
||||
static_cast<int>('W') });
|
||||
|
||||
keyBindings.SetKeyBinding(ShortcutAction::CopyText,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// MinMaxCloseControl.xaml.cpp
|
||||
// Implementation of the MinMaxCloseControl class
|
||||
//
|
||||
@@ -8,6 +10,7 @@
|
||||
#include "MinMaxCloseControl.h"
|
||||
|
||||
#include "MinMaxCloseControl.g.cpp"
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
@@ -16,59 +19,37 @@ namespace winrt::TerminalApp::implementation
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
uint64_t MinMaxCloseControl::ParentWindowHandle() const
|
||||
void MinMaxCloseControl::Maximize()
|
||||
{
|
||||
return reinterpret_cast<uint64_t>(_window);
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"WindowStateMaximized", false);
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::ParentWindowHandle(uint64_t handle)
|
||||
void MinMaxCloseControl::RestoreDown()
|
||||
{
|
||||
_window = reinterpret_cast<HWND>(handle);
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"WindowStateNormal", false);
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::_OnMaximize(byte flag)
|
||||
// These event handlers simply forward each buttons click events up to the
|
||||
// events we've exposed.
|
||||
void MinMaxCloseControl::_MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
RoutedEventArgs const& e)
|
||||
{
|
||||
if (_window)
|
||||
{
|
||||
POINT point1 = {};
|
||||
::GetCursorPos(&point1);
|
||||
const LPARAM lParam = MAKELPARAM(point1.x, point1.y);
|
||||
WINDOWPLACEMENT placement = { sizeof(placement) };
|
||||
::GetWindowPlacement(_window, &placement);
|
||||
if (placement.showCmd == SW_SHOWNORMAL)
|
||||
{
|
||||
winrt::Windows::UI::Xaml::VisualStateManager::GoToState(this->Maximize(), L"WindowStateMaximized", false);
|
||||
::PostMessage(_window, WM_SYSCOMMAND, SC_MAXIMIZE | flag, lParam);
|
||||
}
|
||||
else if (placement.showCmd == SW_SHOWMAXIMIZED)
|
||||
{
|
||||
winrt::Windows::UI::Xaml::VisualStateManager::GoToState(this->Maximize(), L"WindowStateNormal", false);
|
||||
::PostMessage(_window, WM_SYSCOMMAND, SC_RESTORE | flag, lParam);
|
||||
}
|
||||
}
|
||||
_minimizeClickHandlers(*this, e);
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::Maximize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
|
||||
void MinMaxCloseControl::_MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
RoutedEventArgs const& e)
|
||||
{
|
||||
_OnMaximize(HTMAXBUTTON);
|
||||
_maximizeClickHandlers(*this, e);
|
||||
}
|
||||
void MinMaxCloseControl::_CloseClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
RoutedEventArgs const& e)
|
||||
{
|
||||
_closeClickHandlers(*this, e);
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::DragBar_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e)
|
||||
{
|
||||
_OnMaximize(HTCAPTION);
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
|
||||
{
|
||||
if (_window)
|
||||
{
|
||||
::PostMessage(_window, WM_SYSCOMMAND, SC_MINIMIZE | HTMINBUTTON, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
|
||||
{
|
||||
::PostQuitMessage(0);
|
||||
}
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(MinMaxCloseControl, MinimizeClick, _minimizeClickHandlers, TerminalApp::MinMaxCloseControl, RoutedEventArgs);
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(MinMaxCloseControl, MaximizeClick, _maximizeClickHandlers, TerminalApp::MinMaxCloseControl, RoutedEventArgs);
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(MinMaxCloseControl, CloseClick, _closeClickHandlers, TerminalApp::MinMaxCloseControl, RoutedEventArgs);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Declaration of the MainUserControl class.
|
||||
//
|
||||
|
||||
@@ -8,6 +10,7 @@
|
||||
#include "winrt/Windows.UI.Xaml.Markup.h"
|
||||
#include "winrt/Windows.UI.Xaml.Interop.h"
|
||||
#include "MinMaxCloseControl.g.h"
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
@@ -15,17 +18,19 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
MinMaxCloseControl();
|
||||
|
||||
void Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void Maximize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void DragBar_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e);
|
||||
void Maximize();
|
||||
void RestoreDown();
|
||||
|
||||
uint64_t ParentWindowHandle() const;
|
||||
void ParentWindowHandle(uint64_t handle);
|
||||
void _MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void _MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void _CloseClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
|
||||
private:
|
||||
void _OnMaximize(byte flag);
|
||||
HWND _window{ nullptr }; // non-owning handle; should not be freed in the dtor.
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(MinimizeClick, _minimizeClickHandlers, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(MaximizeClick, _maximizeClickHandlers, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(CloseClick, _closeClickHandlers, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
namespace TerminalApp
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface]
|
||||
runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel
|
||||
[default_interface] runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel
|
||||
{
|
||||
MinMaxCloseControl();
|
||||
|
||||
Windows.UI.Xaml.Controls.Grid Content{ get; };
|
||||
Windows.UI.Xaml.Controls.Border DragBar{ get; };
|
||||
void Maximize();
|
||||
void RestoreDown();
|
||||
|
||||
UInt64 ParentWindowHandle;
|
||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MinimizeClick;
|
||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MaximizeClick;
|
||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> CloseClick;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<StackPanel
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information. -->
|
||||
<StackPanel
|
||||
x:Class="TerminalApp.MinMaxCloseControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -129,13 +131,7 @@
|
||||
</ResourceDictionary>
|
||||
</StackPanel.Resources>
|
||||
|
||||
<Grid x:Name="Content"></Grid>
|
||||
<Border Height="36.0"
|
||||
MinWidth="160.0"
|
||||
x:Name="DragBar"
|
||||
Background="{ThemeResource SystemChromeLowColor}"
|
||||
DoubleTapped="DragBar_DoubleTapped"/>
|
||||
<Button Height="36.0" Width="45.0" x:Name="Minimize" Style="{StaticResource CaptionButton}" Click="Minimize_Click"
|
||||
<Button Height="36.0" MinWidth="45.0" Width="45.0" x:Name="MinimizeButton" Style="{StaticResource CaptionButton}" Click="_MinimizeClick"
|
||||
AutomationProperties.Name="Minimize">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
@@ -143,7 +139,7 @@
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
</Button>
|
||||
<Button Height="36.0" Width="45.0" x:Name="Maximize" Style="{StaticResource CaptionButton}" Click="Maximize_Click"
|
||||
<Button Height="36.0" MinWidth="45.0" Width="45.0" x:Name="MaximizeButton" Style="{StaticResource CaptionButton}" Click="_MaximizeClick"
|
||||
AutomationProperties.Name="Maximize">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
@@ -152,7 +148,7 @@
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
</Button>
|
||||
<Button Height="36.0" Width="45.0" x:Name="Close" Style="{StaticResource CaptionButton}" Click="Close_Click"
|
||||
<Button Height="36.0" MinWidth="45.0" Width="45.0" x:Name="CloseButton" Style="{StaticResource CaptionButton}" Click="_CloseClick"
|
||||
AutomationProperties.Name="Close">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
|
||||
@@ -187,6 +187,95 @@ bool Pane::ResizePane(const Direction& direction)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to handle moving focus to one of our children. If our split
|
||||
// direction isn't appropriate for the move direction, then we'll return
|
||||
// false, to try and let our parent handle the move. If our child we'd move
|
||||
// focus to is already focused, we'll also return false, to again let our
|
||||
// parent try and handle the focus movement.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - true if we handled this focus move request.
|
||||
bool Pane::_NavigateFocus(const Direction& direction)
|
||||
{
|
||||
if (!DirectionMatchesSplit(direction, _splitState))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool focusSecond = (direction == Direction::Right) || (direction == Direction::Down);
|
||||
|
||||
const auto newlyFocusedChild = focusSecond ? _secondChild : _firstChild;
|
||||
|
||||
// If the child we want to move focus to is _already_ focused, return false,
|
||||
// to try and let our parent figure it out.
|
||||
if (newlyFocusedChild->WasLastFocused())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Transfer focus to our child, and update the focus of our tree.
|
||||
newlyFocusedChild->_FocusFirstChild();
|
||||
UpdateFocus();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to move focus to one of our children. If we have a focused child,
|
||||
// we'll try to move the focus in the direction requested.
|
||||
// - If there isn't a pane that exists as a child of this pane in the correct
|
||||
// direction, we'll return false. This will indicate to our parent that they
|
||||
// should try and move the focus themselves. In this way, the focus can move
|
||||
// up and down the tree to the correct pane.
|
||||
// - This method is _very_ similar to ResizePane. Both are trying to find the
|
||||
// right separator to move (focus) in a direction.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - true if we or a child handled this focus move request.
|
||||
bool Pane::NavigateFocus(const Direction& direction)
|
||||
{
|
||||
// If we're a leaf, do nothing. We can't possibly have a descendant with a
|
||||
// separator the correct direction.
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if either our first or second child is the currently focused leaf.
|
||||
// If it is, and the requested move direction matches our separator, then
|
||||
// we're the pane that needs to handle this focus move.
|
||||
const bool firstIsFocused = _firstChild->_IsLeaf() && _firstChild->_lastFocused;
|
||||
const bool secondIsFocused = _secondChild->_IsLeaf() && _secondChild->_lastFocused;
|
||||
if (firstIsFocused || secondIsFocused)
|
||||
{
|
||||
return _NavigateFocus(direction);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If neither of our children were the focused leaf, then recurse into
|
||||
// our children and see if they can handle the focus move.
|
||||
// For each child, if it has a focused descendant, try having that child
|
||||
// handle the focus move.
|
||||
// If the child wasn't able to handle the focus move, it's possible that
|
||||
// there were no descendants with a separator the correct direction. If
|
||||
// our separator _is_ the correct direction, then we should be the pane
|
||||
// to move focus into our other child. Otherwise, just return false, as
|
||||
// we couldn't handle it either.
|
||||
if ((!_firstChild->_IsLeaf()) && _firstChild->_HasFocusedChild())
|
||||
{
|
||||
return _firstChild->NavigateFocus(direction) || _NavigateFocus(direction);
|
||||
}
|
||||
else if ((!_secondChild->_IsLeaf()) && _secondChild->_HasFocusedChild())
|
||||
{
|
||||
return _secondChild->NavigateFocus(direction) || _NavigateFocus(direction);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when our attached control is closed. Triggers listeners to our close
|
||||
// event, if we're a leaf pane.
|
||||
@@ -219,6 +308,18 @@ void Pane::_ControlClosedHandler()
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Fire our Closed event to tell our parent that we should be removed.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::Close()
|
||||
{
|
||||
// Fire our Closed event to tell our parent that we should be removed.
|
||||
_closedHandlers();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the root UIElement of this pane. There may be a single TermControl as a
|
||||
// child, or an entire tree of grids and panes as children of this element.
|
||||
|
||||
@@ -47,10 +47,13 @@ public:
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::TerminalSettings& settings, const GUID& profile);
|
||||
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
|
||||
bool ResizePane(const winrt::TerminalApp::Direction& direction);
|
||||
bool NavigateFocus(const winrt::TerminalApp::Direction& direction);
|
||||
|
||||
void SplitHorizontal(const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
|
||||
void SplitVertical(const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
|
||||
|
||||
void Close();
|
||||
|
||||
DECLARE_EVENT(Closed, _closedHandlers, winrt::Microsoft::Terminal::TerminalControl::ConnectionClosedEventArgs);
|
||||
|
||||
private:
|
||||
@@ -80,7 +83,9 @@ private:
|
||||
void _CreateRowColDefinitions(const winrt::Windows::Foundation::Size& rootSize);
|
||||
void _CreateSplitContent();
|
||||
void _ApplySplitDefinitions();
|
||||
|
||||
bool _Resize(const winrt::TerminalApp::Direction& direction);
|
||||
bool _NavigateFocus(const winrt::TerminalApp::Direction& direction);
|
||||
|
||||
void _CloseChild(const bool closeFirst);
|
||||
|
||||
|
||||
@@ -237,4 +237,30 @@ void Tab::ResizePane(const winrt::TerminalApp::Direction& direction)
|
||||
_rootPane->ResizePane(direction);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempt to move focus between panes, as to focus the child on
|
||||
// the other side of the separator. See Pane::NavigateFocus for details.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Tab::NavigateFocus(const winrt::TerminalApp::Direction& direction)
|
||||
{
|
||||
_rootPane->NavigateFocus(direction);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Closes the currently focused pane in this tab. If it's the last pane in
|
||||
// this tab, our Closed event will be fired (at a later time) for anyone
|
||||
// registered as a handler of our close event.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Tab::ClosePane()
|
||||
{
|
||||
auto focused = _rootPane->GetFocusedPane();
|
||||
focused->Close();
|
||||
}
|
||||
|
||||
DEFINE_EVENT(Tab, Closed, _closedHandlers, ConnectionClosedEventArgs);
|
||||
|
||||
@@ -25,11 +25,14 @@ public:
|
||||
void UpdateFocus();
|
||||
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
|
||||
void ResizePane(const winrt::TerminalApp::Direction& direction);
|
||||
void NavigateFocus(const winrt::TerminalApp::Direction& direction);
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::TerminalSettings& settings, const GUID& profile);
|
||||
winrt::hstring GetFocusedTitle() const;
|
||||
void SetTabText(const winrt::hstring& text);
|
||||
|
||||
void ClosePane();
|
||||
|
||||
DECLARE_EVENT(Closed, _closedHandlers, winrt::Microsoft::Terminal::TerminalControl::ConnectionClosedEventArgs);
|
||||
|
||||
private:
|
||||
|
||||
26
src/cascadia/TerminalApp/TabRowControl.cpp
Normal file
26
src/cascadia/TerminalApp/TabRowControl.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "TabRowControl.h"
|
||||
|
||||
#include "TabRowControl.g.cpp"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
TabRowControl::TabRowControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Bound in the Xaml editor to the [+] button.
|
||||
// Arguments:
|
||||
// <unused>
|
||||
void TabRowControl::OnNewTabButtonClick(IInspectable const&, Controls::SplitButtonClickEventArgs const&)
|
||||
{
|
||||
}
|
||||
}
|
||||
25
src/cascadia/TerminalApp/TabRowControl.h
Normal file
25
src/cascadia/TerminalApp/TabRowControl.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "winrt/Microsoft.UI.Xaml.Controls.h"
|
||||
|
||||
#include "TabRowControl.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct TabRowControl : TabRowControlT<TabRowControl>
|
||||
{
|
||||
TabRowControl();
|
||||
|
||||
void OnNewTabButtonClick(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::SplitButtonClickEventArgs const& args);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
struct TabRowControl : TabRowControlT<TabRowControl, implementation::TabRowControl>
|
||||
{
|
||||
};
|
||||
}
|
||||
12
src/cascadia/TerminalApp/TabRowControl.idl
Normal file
12
src/cascadia/TerminalApp/TabRowControl.idl
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass TabRowControl : Windows.UI.Xaml.Controls.Grid
|
||||
{
|
||||
TabRowControl();
|
||||
Windows.UI.Xaml.Controls.SplitButton NewTabButton { get; };
|
||||
Microsoft.UI.Xaml.Controls.TabView TabView { get; };
|
||||
}
|
||||
}
|
||||
31
src/cascadia/TerminalApp/TabRowControl.xaml
Normal file
31
src/cascadia/TerminalApp/TabRowControl.xaml
Normal file
@@ -0,0 +1,31 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information. -->
|
||||
<Grid
|
||||
x:Class="TerminalApp.TabRowControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<mux:TabView x:Name="TabView" VerticalAlignment="Bottom">
|
||||
|
||||
<mux:TabView.RightCustomContent>
|
||||
<SplitButton
|
||||
x:Name="NewTabButton"
|
||||
Click="OnNewTabButtonClick"
|
||||
Background="{ThemeResource SystemChromeLowColor}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Left">
|
||||
<Viewbox MaxHeight="15"
|
||||
MaxWidth="15">
|
||||
<SymbolIcon Symbol="Add" />
|
||||
</Viewbox>
|
||||
</SplitButton>
|
||||
</mux:TabView.RightCustomContent>
|
||||
|
||||
</mux:TabView>
|
||||
|
||||
</Grid>
|
||||
@@ -30,6 +30,8 @@
|
||||
<ClInclude Include="TerminalPage.h" />
|
||||
<ClInclude Include="MinMaxCloseControl.h" />
|
||||
<ClInclude Include="AppKeyBindings.h" />
|
||||
<ClInclude Include="TitlebarControl.h" />
|
||||
<ClInclude Include="TabRowControl.h" />
|
||||
<ClInclude Include="App.h" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
@@ -103,4 +105,32 @@
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<!--
|
||||
This is a terrible, terrible rule. There exists a bug in Visual Studio 2019 16.2 and 16.3 previews
|
||||
where ResolveAssemblyReferences will try and fail to parse a .lib when it produces a .winmd.
|
||||
To fix that, we have to _temporarily_ replace the %(Implementation) on any winmd-producing
|
||||
static library references with the empty string so as to make ResolveAssemblyReferences
|
||||
not try to read it.
|
||||
|
||||
Upstream problem report:
|
||||
https://developercommunity.visualstudio.com/content/problem/629524/static-library-reference-causes-there-was-a-proble.html
|
||||
-->
|
||||
<Target Name="_RemoveTerminalAppLibImplementationFromReference" BeforeTargets="ResolveAssemblyReferences">
|
||||
<ItemGroup>
|
||||
<_TerminalAppLibProjectReference Include="@(_ResolvedProjectReferencePaths)" Condition="'%(Filename)' == 'TerminalApp'" />
|
||||
<_ResolvedProjectReferencePaths Remove="@(_TerminalAppLibProjectReference)" />
|
||||
<_ResolvedProjectReferencePaths Include="@(_TerminalAppLibProjectReference)">
|
||||
<Implementation />
|
||||
</_ResolvedProjectReferencePaths>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_RestoreTerminalAppLibImplementationFromReference" AfterTargets="ResolveAssemblyReferences">
|
||||
<ItemGroup>
|
||||
<_ResolvedProjectReferencePaths Remove="@(_TerminalAppLibProjectReference)" />
|
||||
<_ResolvedProjectReferencePaths Include="@(_TerminalAppLibProjectReference)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<!-- End "terrible, terrible rule" -->
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -15,13 +15,4 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Bound in the Xaml editor to the [+] button.
|
||||
// Arguments:
|
||||
// - sender
|
||||
// - event arguments
|
||||
void TerminalPage::OnNewTabButtonClick(IInspectable const&, Controls::SplitButtonClickEventArgs const&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace winrt::TerminalApp::implementation
|
||||
struct TerminalPage : TerminalPageT<TerminalPage>
|
||||
{
|
||||
TerminalPage();
|
||||
|
||||
void OnNewTabButtonClick(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::SplitButtonClickEventArgs const& args);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface]
|
||||
runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page
|
||||
[default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page
|
||||
{
|
||||
TerminalPage();
|
||||
}
|
||||
|
||||
@@ -10,39 +10,13 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid x:Name="Root" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid x:Name="TabRow" Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<mux:TabView x:Name="TabView" Grid.Column="0" />
|
||||
|
||||
<SplitButton
|
||||
x:Name="NewTabButton"
|
||||
Grid.Column="1"
|
||||
Click="OnNewTabButtonClick"
|
||||
Background="{ThemeResource SystemChromeLowColor}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Left">
|
||||
<Viewbox MaxHeight="15"
|
||||
MaxWidth="15">
|
||||
<SymbolIcon Symbol="Add" />
|
||||
</Viewbox>
|
||||
</SplitButton>
|
||||
|
||||
<local:MinMaxCloseControl
|
||||
x:Name="MinMaxCloseControl"
|
||||
Grid.Column="3"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
<local:TabRowControl x:Name="TabRow" Grid.Row="0" />
|
||||
|
||||
<Grid x:Name="TabContent" Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
|
||||
</Grid>
|
||||
|
||||
89
src/cascadia/TerminalApp/TitlebarControl.cpp
Normal file
89
src/cascadia/TerminalApp/TitlebarControl.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// TitlebarControl.xaml.cpp
|
||||
// Implementation of the TitlebarControl class
|
||||
//
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "TitlebarControl.h"
|
||||
|
||||
#include "TitlebarControl.g.cpp"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
TitlebarControl::TitlebarControl(uint64_t handle) :
|
||||
_window{ reinterpret_cast<HWND>(handle) }
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Register our event handlers on the MMC buttons.
|
||||
MinMaxCloseControl().MinimizeClick({ this, &TitlebarControl::Minimize_Click });
|
||||
MinMaxCloseControl().MaximizeClick({ this, &TitlebarControl::Maximize_Click });
|
||||
MinMaxCloseControl().CloseClick({ this, &TitlebarControl::Close_Click });
|
||||
}
|
||||
|
||||
Windows::UI::Xaml::UIElement TitlebarControl::Content()
|
||||
{
|
||||
return ContentRoot().Children().Size() > 0 ? ContentRoot().Children().GetAt(0) : nullptr;
|
||||
}
|
||||
|
||||
void TitlebarControl::Content(Windows::UI::Xaml::UIElement content)
|
||||
{
|
||||
ContentRoot().Children().Clear();
|
||||
ContentRoot().Children().Append(content);
|
||||
}
|
||||
|
||||
void TitlebarControl::Root_SizeChanged(const IInspectable& sender, Windows::UI::Xaml::SizeChangedEventArgs const& e)
|
||||
{
|
||||
const auto windowWidth = ActualWidth();
|
||||
const auto minMaxCloseWidth = MinMaxCloseControl().ActualWidth();
|
||||
const auto dragBarMinWidth = DragBar().MinWidth();
|
||||
const auto maxWidth = windowWidth - minMaxCloseWidth - dragBarMinWidth;
|
||||
ContentRoot().MaxWidth(maxWidth);
|
||||
}
|
||||
|
||||
void TitlebarControl::_OnMaximizeOrRestore(byte flag)
|
||||
{
|
||||
POINT point1 = {};
|
||||
::GetCursorPos(&point1);
|
||||
const LPARAM lParam = MAKELPARAM(point1.x, point1.y);
|
||||
WINDOWPLACEMENT placement = { sizeof(placement) };
|
||||
::GetWindowPlacement(_window, &placement);
|
||||
if (placement.showCmd == SW_SHOWNORMAL)
|
||||
{
|
||||
MinMaxCloseControl().Maximize();
|
||||
::PostMessage(_window, WM_SYSCOMMAND, SC_MAXIMIZE | flag, lParam);
|
||||
}
|
||||
else if (placement.showCmd == SW_SHOWMAXIMIZED)
|
||||
{
|
||||
MinMaxCloseControl().RestoreDown();
|
||||
::PostMessage(_window, WM_SYSCOMMAND, SC_RESTORE | flag, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
void TitlebarControl::Maximize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
|
||||
{
|
||||
_OnMaximizeOrRestore(HTMAXBUTTON);
|
||||
}
|
||||
|
||||
void TitlebarControl::DragBar_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e)
|
||||
{
|
||||
_OnMaximizeOrRestore(HTCAPTION);
|
||||
}
|
||||
|
||||
void TitlebarControl::Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
|
||||
{
|
||||
if (_window)
|
||||
{
|
||||
::PostMessage(_window, WM_SYSCOMMAND, SC_MINIMIZE | HTMINBUTTON, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void TitlebarControl::Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
|
||||
{
|
||||
::PostQuitMessage(0);
|
||||
}
|
||||
|
||||
}
|
||||
41
src/cascadia/TerminalApp/TitlebarControl.h
Normal file
41
src/cascadia/TerminalApp/TitlebarControl.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Declaration of the MainUserControl class.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "winrt/Windows.UI.Xaml.h"
|
||||
#include "winrt/Windows.UI.Xaml.Markup.h"
|
||||
#include "winrt/Windows.UI.Xaml.Interop.h"
|
||||
#include "TitlebarControl.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct TitlebarControl : TitlebarControlT<TitlebarControl>
|
||||
{
|
||||
TitlebarControl(uint64_t handle);
|
||||
|
||||
Windows::UI::Xaml::UIElement Content();
|
||||
void Content(Windows::UI::Xaml::UIElement content);
|
||||
|
||||
void Root_SizeChanged(const IInspectable& sender, Windows::UI::Xaml::SizeChangedEventArgs const& e);
|
||||
|
||||
void Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void Maximize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void DragBar_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e);
|
||||
|
||||
private:
|
||||
void _OnMaximizeOrRestore(byte flag);
|
||||
HWND _window{ nullptr }; // non-owning handle; should not be freed in the dtor.
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
struct TitlebarControl : TitlebarControlT<TitlebarControl, implementation::TitlebarControl>
|
||||
{
|
||||
};
|
||||
}
|
||||
13
src/cascadia/TerminalApp/TitlebarControl.idl
Normal file
13
src/cascadia/TerminalApp/TitlebarControl.idl
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass TitlebarControl : Windows.UI.Xaml.Controls.Grid
|
||||
{
|
||||
TitlebarControl(UInt64 parentWindowHandle);
|
||||
|
||||
Windows.UI.Xaml.UIElement Content;
|
||||
Windows.UI.Xaml.Controls.Border DragBar { get; };
|
||||
}
|
||||
}
|
||||
45
src/cascadia/TerminalApp/TitlebarControl.xaml
Normal file
45
src/cascadia/TerminalApp/TitlebarControl.xaml
Normal file
@@ -0,0 +1,45 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information. -->
|
||||
<Grid
|
||||
x:Class="TerminalApp.TitlebarControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Name="Root"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
SizeChanged="Root_SizeChanged"
|
||||
d:DesignHeight="36"
|
||||
Background="{ThemeResource SystemChromeLowColor}"
|
||||
d:DesignWidth="400">
|
||||
|
||||
<!-- TODO:GH#1988
|
||||
This xaml should probably be a template thing, where the background is a
|
||||
resource that the app hosting this control can override. Then, it App.xaml,
|
||||
we'd make sure to set the resource for our background to the appropriate
|
||||
color. SystemControlForegroundAccentBrush also works nicely, to use the
|
||||
accent color. (which is GH#1963)-->
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid x:Name="ContentRoot" Grid.Column="0" />
|
||||
|
||||
<Border
|
||||
x:Name="DragBar"
|
||||
Grid.Column="1"
|
||||
MinWidth="45.0"
|
||||
DoubleTapped="DragBar_DoubleTapped"/>
|
||||
|
||||
<local:MinMaxCloseControl
|
||||
Grid.Column="2"
|
||||
x:Name="MinMaxCloseControl"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
|
||||
@@ -35,6 +35,12 @@
|
||||
<Page Include="../TerminalPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="../TitlebarControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="../TabRowControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Headers ======================== -->
|
||||
@@ -47,6 +53,12 @@
|
||||
<DependentUpon>../TerminalPage.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../TitlebarControl.h">
|
||||
<DependentUpon>../TitlebarControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../TabRowControl.h">
|
||||
<DependentUpon>../TabRowControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../Tab.h" />
|
||||
<ClInclude Include="../Pane.h" />
|
||||
<ClInclude Include="../ColorScheme.h" />
|
||||
@@ -72,6 +84,12 @@
|
||||
<DependentUpon>../TerminalPage.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../TitlebarControl.cpp">
|
||||
<DependentUpon>../TitlebarControl.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../TabRowControl.cpp">
|
||||
<DependentUpon>../TabRowControl.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../Tab.cpp" />
|
||||
<ClCompile Include="../Pane.cpp" />
|
||||
<ClCompile Include="../ColorScheme.cpp" />
|
||||
@@ -116,6 +134,14 @@
|
||||
<DependentUpon>../TerminalPage.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="../TitlebarControl.idl">
|
||||
<DependentUpon>../TitlebarControl.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="../TabRowControl.idl">
|
||||
<DependentUpon>../TabRowControl.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
@@ -232,7 +258,7 @@
|
||||
<Implementation>Microsoft.UI.Xaml.dll</Implementation>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
<Private>false</Private>
|
||||
<Private>true</Private>
|
||||
</Reference>
|
||||
<ReferenceCopyLocalPaths Include="$(_MUXRoot)runtimes\win10-$(Native-Platform)\native\Microsoft.UI.Xaml.dll" />
|
||||
<ReferenceCopyLocalPaths Include="$(_MUXRoot)runtimes\win10-$(Native-Platform)\native\Microsoft.UI.Xaml.pri" />
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <conpty-universal.h>
|
||||
#include "../../types/inc/Utils.hpp"
|
||||
#include "../../types/inc/UTF8OutPipeReader.hpp"
|
||||
|
||||
using namespace ::Microsoft::Console;
|
||||
|
||||
@@ -37,23 +38,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
}
|
||||
|
||||
ConhostConnection::ConhostConnection(const uint64_t server,
|
||||
const uint32_t initialRows,
|
||||
const uint32_t initialCols,
|
||||
const guid& initialGuid) :
|
||||
_initialRows{ initialRows },
|
||||
_initialCols{ initialCols },
|
||||
_commandline{},
|
||||
_startingDirectory{},
|
||||
_guid{ initialGuid },
|
||||
_hServer{ reinterpret_cast<HANDLE>(server) }
|
||||
{
|
||||
if (_guid == guid{})
|
||||
{
|
||||
_guid = Utils::CreateGuid();
|
||||
}
|
||||
}
|
||||
|
||||
winrt::guid ConhostConnection::Guid() const noexcept
|
||||
{
|
||||
return _guid;
|
||||
@@ -88,12 +72,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
startingDirectory = _startingDirectory;
|
||||
}
|
||||
|
||||
std::optional<HANDLE> server;
|
||||
if (_hServer)
|
||||
{
|
||||
server = _hServer.get();
|
||||
}
|
||||
|
||||
EnvironmentVariableMapW extraEnvVars;
|
||||
{
|
||||
// Convert connection Guid to string and ignore the enclosing '{}'.
|
||||
@@ -111,7 +89,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
startingDirectory,
|
||||
static_cast<short>(_initialCols),
|
||||
static_cast<short>(_initialRows),
|
||||
server,
|
||||
&_inPipe,
|
||||
&_outPipe,
|
||||
&_signalPipe,
|
||||
@@ -213,39 +190,37 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
DWORD ConhostConnection::_OutputThread()
|
||||
{
|
||||
const size_t bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
DWORD dwRead;
|
||||
UTF8OutPipeReader pipeReader{ _outPipe.get() };
|
||||
std::string_view strView{};
|
||||
|
||||
// process the data of the output pipe in a loop
|
||||
while (true)
|
||||
{
|
||||
dwRead = 0;
|
||||
bool fSuccess = false;
|
||||
|
||||
fSuccess = !!ReadFile(_outPipe.get(), buffer, bufferSize, &dwRead, nullptr);
|
||||
if (!fSuccess)
|
||||
HRESULT result = pipeReader.Read(strView);
|
||||
if (FAILED(result) || result == S_FALSE)
|
||||
{
|
||||
if (_closing.load())
|
||||
{
|
||||
// This is okay, break out to kill the thread
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_disconnectHandlers();
|
||||
return (DWORD)-1;
|
||||
}
|
||||
|
||||
_disconnectHandlers();
|
||||
return (DWORD)-1;
|
||||
}
|
||||
if (dwRead == 0)
|
||||
|
||||
if (strView.empty())
|
||||
{
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert buffer to hstring
|
||||
char* pchStr = (char*)(buffer);
|
||||
std::string str{ pchStr, dwRead };
|
||||
auto hstr = winrt::to_hstring(str);
|
||||
auto hstr{ winrt::to_hstring(strView) };
|
||||
|
||||
// Pass the output to our registered event handlers
|
||||
_outputHandlers(hstr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
struct ConhostConnection : ConhostConnectionT<ConhostConnection>
|
||||
{
|
||||
ConhostConnection(const hstring& cmdline, const hstring& startingDirectory, const uint32_t rows, const uint32_t cols, const guid& guid);
|
||||
ConhostConnection(const uint64_t server, const uint32_t rows, const uint32_t cols, const guid& guid);
|
||||
|
||||
winrt::event_token TerminalOutput(TerminalConnection::TerminalOutputEventArgs const& handler);
|
||||
void TerminalOutput(winrt::event_token const& token) noexcept;
|
||||
@@ -42,7 +41,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
wil::unique_handle _hOutputThread;
|
||||
wil::unique_process_information _piConhost;
|
||||
wil::unique_handle _hJob;
|
||||
wil::unique_handle _hServer;
|
||||
|
||||
static DWORD WINAPI StaticOutputThreadProc(LPVOID lpParameter);
|
||||
DWORD _OutputThread();
|
||||
|
||||
@@ -9,7 +9,6 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
runtimeclass ConhostConnection : ITerminalConnection
|
||||
{
|
||||
ConhostConnection(String cmdline, String startingDirectory, UInt32 rows, UInt32 columns, Guid guid);
|
||||
ConhostConnection(UInt64 server, UInt32 rows, UInt32 columns, Guid guid);
|
||||
|
||||
Guid Guid { get; };
|
||||
};
|
||||
|
||||
@@ -606,9 +606,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
if (bindings)
|
||||
{
|
||||
KeyChord chord(
|
||||
WI_IsAnyFlagSet(modifiers, CTRL_PRESSED),
|
||||
WI_IsAnyFlagSet(modifiers, ALT_PRESSED),
|
||||
WI_IsFlagSet(modifiers, SHIFT_PRESSED),
|
||||
modifiers.IsCtrlPressed(),
|
||||
modifiers.IsAltPressed(),
|
||||
modifiers.IsShiftPressed(),
|
||||
vkey);
|
||||
handled = bindings.TryKeyChord(chord);
|
||||
}
|
||||
@@ -1473,8 +1473,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// find out which modifiers (ctrl, alt, shift) are pressed in events that
|
||||
// don't necessarily include that state.
|
||||
// Return Value:
|
||||
// - The combined ControlKeyState flags as a bitfield.
|
||||
DWORD TermControl::_GetPressedModifierKeys() const
|
||||
// - The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
|
||||
ControlKeyStates TermControl::_GetPressedModifierKeys() const
|
||||
{
|
||||
CoreWindow window = CoreWindow::GetForCurrentThread();
|
||||
// DONT USE
|
||||
@@ -1488,24 +1488,28 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
struct KeyModifier
|
||||
{
|
||||
VirtualKey vkey;
|
||||
DWORD flag;
|
||||
ControlKeyStates flags;
|
||||
};
|
||||
|
||||
constexpr std::array<KeyModifier, 5> modifiers{ {
|
||||
{ VirtualKey::RightMenu, RIGHT_ALT_PRESSED },
|
||||
{ VirtualKey::LeftMenu, LEFT_ALT_PRESSED },
|
||||
{ VirtualKey::RightControl, RIGHT_CTRL_PRESSED },
|
||||
{ VirtualKey::LeftControl, LEFT_CTRL_PRESSED },
|
||||
{ VirtualKey::Shift, SHIFT_PRESSED },
|
||||
{ VirtualKey::RightMenu, ControlKeyStates::RightAltPressed },
|
||||
{ VirtualKey::LeftMenu, ControlKeyStates::LeftAltPressed },
|
||||
{ VirtualKey::RightControl, ControlKeyStates::RightCtrlPressed },
|
||||
{ VirtualKey::LeftControl, ControlKeyStates::LeftCtrlPressed },
|
||||
{ VirtualKey::Shift, ControlKeyStates::ShiftPressed },
|
||||
} };
|
||||
|
||||
DWORD flags = 0;
|
||||
ControlKeyStates flags;
|
||||
|
||||
for (const auto& mod : modifiers)
|
||||
{
|
||||
const auto state = window.GetKeyState(mod.vkey);
|
||||
const auto isDown = WI_IsFlagSet(state, CoreVirtualKeyStates::Down);
|
||||
flags |= isDown ? mod.flag : 0;
|
||||
|
||||
if (isDown)
|
||||
{
|
||||
flags |= mod.flags;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
|
||||
@@ -122,7 +122,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
void _ApplyUISettings();
|
||||
void _InitializeBackgroundBrush();
|
||||
void _BackgroundColorChanged(const uint32_t color);
|
||||
void _ApplyConnectionSettings();
|
||||
void _InitializeTerminal();
|
||||
void _UpdateFont();
|
||||
void _KeyDownHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
@@ -153,7 +152,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
void _ScrollbarUpdater(Windows::UI::Xaml::Controls::Primitives::ScrollBar scrollbar, const int viewTop, const int viewHeight, const int bufferSize);
|
||||
static Windows::UI::Xaml::Thickness _ParseThicknessFromPadding(const hstring padding);
|
||||
|
||||
DWORD _GetPressedModifierKeys() const;
|
||||
::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() const;
|
||||
|
||||
const COORD _GetTerminalPosition(winrt::Windows::Foundation::Point cursorPosition);
|
||||
const unsigned int _NumberOfClicks(winrt::Windows::Foundation::Point clickPos, Timestamp clickTime);
|
||||
|
||||
112
src/cascadia/TerminalCore/ControlKeyStates.hpp
Normal file
112
src/cascadia/TerminalCore/ControlKeyStates.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Microsoft::Terminal::Core
|
||||
{
|
||||
class ControlKeyStates;
|
||||
}
|
||||
|
||||
constexpr Microsoft::Terminal::Core::ControlKeyStates operator|(Microsoft::Terminal::Core::ControlKeyStates lhs, Microsoft::Terminal::Core::ControlKeyStates rhs) noexcept;
|
||||
|
||||
// This class is functionally equivalent to PowerShell's System.Management.Automation.Host.ControlKeyStates enum:
|
||||
// https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.host.controlkeystates
|
||||
// It's flagging values are compatible to those used by the NT console subsystem (<um/wincon.h>),
|
||||
// as these are being used throughout older parts of this project.
|
||||
class Microsoft::Terminal::Core::ControlKeyStates
|
||||
{
|
||||
struct StaticValue
|
||||
{
|
||||
DWORD v;
|
||||
};
|
||||
|
||||
public:
|
||||
static constexpr StaticValue RightAltPressed{ RIGHT_ALT_PRESSED };
|
||||
static constexpr StaticValue LeftAltPressed{ LEFT_ALT_PRESSED };
|
||||
static constexpr StaticValue RightCtrlPressed{ RIGHT_CTRL_PRESSED };
|
||||
static constexpr StaticValue LeftCtrlPressed{ LEFT_CTRL_PRESSED };
|
||||
static constexpr StaticValue ShiftPressed{ SHIFT_PRESSED };
|
||||
static constexpr StaticValue NumlockOn{ NUMLOCK_ON };
|
||||
static constexpr StaticValue ScrolllockOn{ SCROLLLOCK_ON };
|
||||
static constexpr StaticValue CapslockOn{ CAPSLOCK_ON };
|
||||
static constexpr StaticValue EnhancedKey{ ENHANCED_KEY };
|
||||
|
||||
constexpr ControlKeyStates() noexcept :
|
||||
_value(0) {}
|
||||
|
||||
constexpr ControlKeyStates(StaticValue value) noexcept :
|
||||
_value(value.v) {}
|
||||
|
||||
explicit constexpr ControlKeyStates(DWORD value) noexcept :
|
||||
_value(value) {}
|
||||
|
||||
ControlKeyStates& operator|=(ControlKeyStates rhs) noexcept
|
||||
{
|
||||
_value |= rhs.Value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr DWORD Value() const noexcept
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
constexpr bool IsShiftPressed() const noexcept
|
||||
{
|
||||
return IsAnyFlagSet(ShiftPressed);
|
||||
}
|
||||
|
||||
constexpr bool IsAltPressed() const noexcept
|
||||
{
|
||||
return IsAnyFlagSet(RightAltPressed | LeftAltPressed);
|
||||
}
|
||||
|
||||
constexpr bool IsCtrlPressed() const noexcept
|
||||
{
|
||||
return IsAnyFlagSet(RightCtrlPressed | LeftCtrlPressed);
|
||||
}
|
||||
|
||||
constexpr bool IsAltGrPressed() const noexcept
|
||||
{
|
||||
return AreAllFlagsSet(RightAltPressed | LeftCtrlPressed);
|
||||
}
|
||||
|
||||
constexpr bool IsModifierPressed() const noexcept
|
||||
{
|
||||
return IsAnyFlagSet(RightAltPressed | LeftAltPressed | RightCtrlPressed | LeftCtrlPressed | ShiftPressed);
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr bool AreAllFlagsSet(ControlKeyStates mask) const noexcept
|
||||
{
|
||||
return (Value() & mask.Value()) == mask.Value();
|
||||
}
|
||||
|
||||
constexpr bool IsAnyFlagSet(ControlKeyStates mask) const noexcept
|
||||
{
|
||||
return (Value() & mask.Value()) != 0;
|
||||
}
|
||||
|
||||
DWORD _value;
|
||||
};
|
||||
|
||||
constexpr Microsoft::Terminal::Core::ControlKeyStates operator|(Microsoft::Terminal::Core::ControlKeyStates lhs, Microsoft::Terminal::Core::ControlKeyStates rhs) noexcept
|
||||
{
|
||||
return Microsoft::Terminal::Core::ControlKeyStates{ lhs.Value() | rhs.Value() };
|
||||
}
|
||||
|
||||
constexpr Microsoft::Terminal::Core::ControlKeyStates operator&(Microsoft::Terminal::Core::ControlKeyStates lhs, Microsoft::Terminal::Core::ControlKeyStates rhs) noexcept
|
||||
{
|
||||
return Microsoft::Terminal::Core::ControlKeyStates{ lhs.Value() & rhs.Value() };
|
||||
}
|
||||
|
||||
constexpr bool operator==(Microsoft::Terminal::Core::ControlKeyStates lhs, Microsoft::Terminal::Core::ControlKeyStates rhs) noexcept
|
||||
{
|
||||
return lhs.Value() == rhs.Value();
|
||||
}
|
||||
|
||||
constexpr bool operator!=(Microsoft::Terminal::Core::ControlKeyStates lhs, Microsoft::Terminal::Core::ControlKeyStates rhs) noexcept
|
||||
{
|
||||
return lhs.Value() != rhs.Value();
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ControlKeyStates.hpp"
|
||||
|
||||
namespace Microsoft::Terminal::Core
|
||||
{
|
||||
class ITerminalInput
|
||||
@@ -9,7 +12,7 @@ namespace Microsoft::Terminal::Core
|
||||
public:
|
||||
virtual ~ITerminalInput() {}
|
||||
|
||||
virtual bool SendKeyEvent(const WORD vkey, const DWORD modifiers) = 0;
|
||||
virtual bool SendKeyEvent(const WORD vkey, const ControlKeyStates states) = 0;
|
||||
|
||||
// void SendMouseEvent(uint row, uint col, KeyModifiers modifiers);
|
||||
[[nodiscard]] virtual HRESULT UserResize(const COORD size) noexcept = 0;
|
||||
|
||||
@@ -197,11 +197,11 @@ void Terminal::Write(std::wstring_view stringView)
|
||||
// real character out of the event.
|
||||
// Arguments:
|
||||
// - vkey: The vkey of the key pressed.
|
||||
// - modifiers: The current ControlKeyState flags.
|
||||
// - states: The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
|
||||
// Return Value:
|
||||
// - true if we translated the key event, and it should not be processed any further.
|
||||
// - false if we did not translate the key, and it should be processed into a character.
|
||||
bool Terminal::SendKeyEvent(const WORD vkey, const DWORD modifiers)
|
||||
bool Terminal::SendKeyEvent(const WORD vkey, const ControlKeyStates states)
|
||||
{
|
||||
if (_snapOnInput && _scrollOffset != 0)
|
||||
{
|
||||
@@ -210,8 +210,6 @@ bool Terminal::SendKeyEvent(const WORD vkey, const DWORD modifiers)
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
|
||||
KeyEvent keyEv{ true, 0, vkey, 0, UNICODE_NULL, modifiers };
|
||||
|
||||
// AltGr key combinations don't always contain any meaningful,
|
||||
// pretranslated unicode character during WM_KEYDOWN.
|
||||
// E.g. on a German keyboard AltGr+Q should result in a "@" character,
|
||||
@@ -219,50 +217,58 @@ bool Terminal::SendKeyEvent(const WORD vkey, const DWORD modifiers)
|
||||
// By returning false though, we can abort handling this WM_KEYDOWN
|
||||
// event and let the WM_CHAR handler kick in, which will be
|
||||
// provided with an appropriate unicode character.
|
||||
if (keyEv.IsAltGrPressed())
|
||||
if (states.IsAltGrPressed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto ctrlPressed = keyEv.IsCtrlPressed();
|
||||
const auto altPressed = keyEv.IsAltPressed();
|
||||
const auto shiftPressed = keyEv.IsShiftPressed();
|
||||
|
||||
// Alt key sequences _require_ the char to be in the keyevent. If alt is
|
||||
// pressed, manually get the character that's being typed, and put it in the
|
||||
// KeyEvent.
|
||||
// DON'T manually handle Alt+Space - the system will use this to bring up
|
||||
// the system menu for restore, min/maximimize, size, move, close
|
||||
wchar_t ch = UNICODE_NULL;
|
||||
if (altPressed && vkey != VK_SPACE)
|
||||
if (states.IsAltPressed() && vkey != VK_SPACE)
|
||||
{
|
||||
ch = static_cast<wchar_t>(LOWORD(MapVirtualKey(vkey, MAPVK_VK_TO_CHAR)));
|
||||
// MapVirtualKey will give us the capitalized version of the char.
|
||||
// However, if shift isn't pressed, we want to send the lowercase version.
|
||||
// (See GH#637)
|
||||
if (!shiftPressed)
|
||||
if (!states.IsShiftPressed())
|
||||
{
|
||||
ch = towlower(ch);
|
||||
}
|
||||
}
|
||||
|
||||
// Manually handle Ctrl+H. Ctrl+H should be handled as Backspace. To do this
|
||||
// correctly, the keyEvents's char needs to be set to Backspace.
|
||||
// 0x48 is the VKEY for 'H', which isn't named
|
||||
if (ctrlPressed && vkey == 0x48)
|
||||
if (states.IsCtrlPressed())
|
||||
{
|
||||
ch = UNICODE_BACKSPACE;
|
||||
}
|
||||
// Manually handle Ctrl+Space here. The terminalInput translator requires
|
||||
// the char to be set to Space for space handling to work correctly.
|
||||
if (ctrlPressed && vkey == VK_SPACE)
|
||||
{
|
||||
ch = UNICODE_SPACE;
|
||||
switch (vkey)
|
||||
{
|
||||
case 0x48:
|
||||
// Manually handle Ctrl+H. Ctrl+H should be handled as Backspace. To do this
|
||||
// correctly, the keyEvents's char needs to be set to Backspace.
|
||||
// 0x48 is the VKEY for 'H', which isn't named
|
||||
ch = UNICODE_BACKSPACE;
|
||||
break;
|
||||
case VK_SPACE:
|
||||
// Manually handle Ctrl+Space here. The terminalInput translator requires
|
||||
// the char to be set to Space for space handling to work correctly.
|
||||
ch = UNICODE_SPACE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
keyEv.SetCharData(ch);
|
||||
// Manually handle Escape here. If we let it fall through, it'll come
|
||||
// back up through the character handler. It's registered as a translation
|
||||
// in TerminalInput, so we'll let TerminalInput control it.
|
||||
if (vkey == VK_ESCAPE)
|
||||
{
|
||||
ch = UNICODE_ESC;
|
||||
}
|
||||
|
||||
const bool manuallyHandled = ch != UNICODE_NULL;
|
||||
|
||||
KeyEvent keyEv{ true, 0, vkey, 0, ch, states.Value() };
|
||||
const bool translated = _terminalInput->HandleKey(&keyEv);
|
||||
|
||||
return translated && manuallyHandled;
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
|
||||
#pragma region ITerminalInput
|
||||
// These methods are defined in Terminal.cpp
|
||||
bool SendKeyEvent(const WORD vkey, const DWORD modifiers) override;
|
||||
bool SendKeyEvent(const WORD vkey, const Microsoft::Terminal::Core::ControlKeyStates states) override;
|
||||
[[nodiscard]] HRESULT UserResize(const COORD viewportSize) noexcept override;
|
||||
void UserScrollViewport(const int viewTop) override;
|
||||
int GetScrollOffset() override;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\ControlKeyStates.hpp" />
|
||||
<ClInclude Include="..\TerminalDispatch.hpp" />
|
||||
<ClInclude Include="..\ITerminalApi.hpp" />
|
||||
<ClInclude Include="..\pch.h" />
|
||||
|
||||
@@ -48,12 +48,12 @@ namespace TerminalCoreUnitTests
|
||||
// Verify that Alt+a generates a lowercase a on the input
|
||||
expectedinput = L"\x1b"
|
||||
"a";
|
||||
VERIFY_IS_TRUE(term.SendKeyEvent(L'A', LEFT_ALT_PRESSED));
|
||||
VERIFY_IS_TRUE(term.SendKeyEvent(L'A', ControlKeyStates::LeftAltPressed));
|
||||
|
||||
// Verify that Alt+shift+a generates a uppercase a on the input
|
||||
expectedinput = L"\x1b"
|
||||
"A";
|
||||
VERIFY_IS_TRUE(term.SendKeyEvent(L'A', LEFT_ALT_PRESSED | SHIFT_PRESSED));
|
||||
VERIFY_IS_TRUE(term.SendKeyEvent(L'A', ControlKeyStates::LeftAltPressed | ControlKeyStates::ShiftPressed));
|
||||
}
|
||||
|
||||
void InputTest::AltSpace()
|
||||
@@ -61,6 +61,6 @@ namespace TerminalCoreUnitTests
|
||||
// Make sure we don't handle Alt+Space. The system will use this to
|
||||
// bring up the system menu for restore, min/maximimize, size, move,
|
||||
// close
|
||||
VERIFY_IS_FALSE(term.SendKeyEvent(L' ', LEFT_ALT_PRESSED));
|
||||
VERIFY_IS_FALSE(term.SendKeyEvent(L' ', ControlKeyStates::LeftAltPressed));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,25 +61,27 @@ AppHost::~AppHost()
|
||||
void AppHost::Initialize()
|
||||
{
|
||||
_window->Initialize();
|
||||
const auto handle = _window->GetHandle();
|
||||
_app.Create(reinterpret_cast<uint64_t>(handle));
|
||||
|
||||
if (_useNonClientArea)
|
||||
{
|
||||
// Register our callbar for when the app's non-client content changes.
|
||||
// This has to be done _before_ App::Create, as the app might set the
|
||||
// content in Create.
|
||||
_app.SetTitleBarContent({ this, &AppHost::_UpdateTitleBarContent });
|
||||
}
|
||||
_app.RequestedThemeChanged({ this, &AppHost::_UpdateTheme });
|
||||
|
||||
_app.Create();
|
||||
|
||||
_app.TitleChanged({ this, &AppHost::AppTitleChanged });
|
||||
_app.LastTabClosed({ this, &AppHost::LastTabClosed });
|
||||
|
||||
AppTitleChanged(_app.GetTitle());
|
||||
|
||||
_window->OnAppInitialized(_app);
|
||||
}
|
||||
|
||||
void AppHost::IncomingConnectionByHandle(HANDLE handle)
|
||||
{
|
||||
_app.IncomingConnection(reinterpret_cast<uint64_t>(handle));
|
||||
}
|
||||
|
||||
void AppHost::IncomingConnectionByLaunch(std::wstring_view cmdline, std::wstring_view workingDir)
|
||||
{
|
||||
_app.IncomingConnection(winrt::hstring(cmdline), winrt::hstring(workingDir));
|
||||
// Set up the content of the application. If the app has a custom titlebar,
|
||||
// set that content as well.
|
||||
_window->SetContent(_app.GetRoot());
|
||||
_window->OnAppInitialized();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -193,3 +195,32 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, const RECT proposedRect)
|
||||
// the originally proposed window size.
|
||||
LOG_LAST_ERROR_IF(!succeeded);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the app wants to set its titlebar content. We'll take the
|
||||
// UIElement and set the Content property of our Titlebar that element.
|
||||
// Arguments:
|
||||
// - sender: unused
|
||||
// - arg: the UIElement to use as the new Titlebar content.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void AppHost::_UpdateTitleBarContent(const winrt::TerminalApp::App&, const winrt::Windows::UI::Xaml::UIElement& arg)
|
||||
{
|
||||
if (_useNonClientArea)
|
||||
{
|
||||
(static_cast<NonClientIslandWindow*>(_window.get()))->SetTitlebarContent(arg);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the app wants to change its theme. We'll forward this to the
|
||||
// IslandWindow, so it can update the root UI element of the entire XAML tree.
|
||||
// Arguments:
|
||||
// - sender: unused
|
||||
// - arg: the ElementTheme to use as the new theme for the UI
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void AppHost::_UpdateTheme(const winrt::TerminalApp::App&, const winrt::Windows::UI::Xaml::ElementTheme& arg)
|
||||
{
|
||||
_window->UpdateTheme(arg);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ public:
|
||||
AppHost() noexcept;
|
||||
virtual ~AppHost();
|
||||
|
||||
void IncomingConnectionByHandle(HANDLE handle);
|
||||
void IncomingConnectionByLaunch(std::wstring_view cmdline, std::wstring_view workingDir);
|
||||
void AppTitleChanged(winrt::hstring newTitle);
|
||||
void LastTabClosed();
|
||||
void Initialize();
|
||||
@@ -27,4 +25,8 @@ private:
|
||||
winrt::TerminalApp::App _app;
|
||||
|
||||
void _HandleCreateWindow(const HWND hwnd, const RECT proposedRect);
|
||||
void _UpdateTitleBarContent(const winrt::TerminalApp::App& sender,
|
||||
const winrt::Windows::UI::Xaml::UIElement& arg);
|
||||
void _UpdateTheme(const winrt::TerminalApp::App&,
|
||||
const winrt::Windows::UI::Xaml::ElementTheme& arg);
|
||||
};
|
||||
|
||||
@@ -79,7 +79,7 @@ void IslandWindow::Close()
|
||||
|
||||
// Method Description:
|
||||
// - Set a callback to be called when we process a WM_CREATE message. This gives
|
||||
// the AppHost a chance to resize the window to the proper size.
|
||||
// the AppHost a chance to resize the window to the propoer size.
|
||||
// Arguments:
|
||||
// - pfn: a function to be called during the handling of WM_CREATE. It takes two
|
||||
// parameters:
|
||||
@@ -196,22 +196,41 @@ void IslandWindow::OnResize(const UINT width, const UINT height)
|
||||
// - Called when the window is minimized to the taskbar.
|
||||
void IslandWindow::OnMinimize()
|
||||
{
|
||||
// TODO MSFT#21315817 Stop rendering island content when the app is minimized.
|
||||
// TODO GH#1989 Stop rendering island content when the app is minimized.
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the window is restored from having been minimized.
|
||||
void IslandWindow::OnRestore()
|
||||
{
|
||||
// TODO MSFT#21315817 Stop rendering island content when the app is minimized.
|
||||
// TODO GH#1989 Stop rendering island content when the app is minimized.
|
||||
}
|
||||
|
||||
void IslandWindow::OnAppInitialized(winrt::TerminalApp::App app)
|
||||
void IslandWindow::SetContent(winrt::Windows::UI::Xaml::UIElement content)
|
||||
{
|
||||
_rootGrid.Children().Clear();
|
||||
_rootGrid.Children().Append(app.GetRoot());
|
||||
_rootGrid.Children().Append(content);
|
||||
}
|
||||
|
||||
void IslandWindow::OnAppInitialized()
|
||||
{
|
||||
// Do a quick resize to force the island to paint
|
||||
const auto size = GetPhysicalSize();
|
||||
OnSize(size.cx, size.cy);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the app wants to change its theme. We'll update the root UI
|
||||
// element of the entire XAML tree, so that all UI elements get the theme
|
||||
// applied.
|
||||
// Arguments:
|
||||
// - arg: the ElementTheme to use as the new theme for the UI
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void IslandWindow::UpdateTheme(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme)
|
||||
{
|
||||
_rootGrid.RequestedTheme(requestedTheme);
|
||||
// Invalidate the window rect, so that we'll repaint any elements we're
|
||||
// drawing ourselves to match the new theme
|
||||
::InvalidateRect(_window.get(), nullptr, false);
|
||||
}
|
||||
|
||||
@@ -20,12 +20,15 @@ public:
|
||||
void OnResize(const UINT width, const UINT height) override;
|
||||
void OnMinimize() override;
|
||||
void OnRestore() override;
|
||||
virtual void OnAppInitialized(winrt::TerminalApp::App app);
|
||||
virtual void OnAppInitialized();
|
||||
virtual void SetContent(winrt::Windows::UI::Xaml::UIElement content);
|
||||
|
||||
void Initialize();
|
||||
virtual void Initialize();
|
||||
|
||||
void SetCreateCallback(std::function<void(const HWND, const RECT)> pfn) noexcept;
|
||||
|
||||
void UpdateTheme(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
|
||||
|
||||
protected:
|
||||
void ForceResize()
|
||||
{
|
||||
|
||||
@@ -42,17 +42,82 @@ NonClientIslandWindow::~NonClientIslandWindow()
|
||||
// - <unused>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void NonClientIslandWindow::OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable /*sender*/, winrt::Windows::UI::Xaml::SizeChangedEventArgs /*eventArgs*/)
|
||||
void NonClientIslandWindow::OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable /*sender*/,
|
||||
winrt::Windows::UI::Xaml::SizeChangedEventArgs /*eventArgs*/)
|
||||
{
|
||||
_UpdateDragRegion();
|
||||
}
|
||||
|
||||
void NonClientIslandWindow::OnAppInitialized(winrt::TerminalApp::App app)
|
||||
void NonClientIslandWindow::OnAppInitialized()
|
||||
{
|
||||
_dragBar = app.GetDragBar();
|
||||
IslandWindow::OnAppInitialized();
|
||||
}
|
||||
|
||||
void NonClientIslandWindow::Initialize()
|
||||
{
|
||||
IslandWindow::Initialize();
|
||||
|
||||
// Set up our grid of content. We'll use _rootGrid as our root element.
|
||||
// There will be two children of this grid - the TitlebarControl, and the
|
||||
// "client content"
|
||||
_rootGrid.Children().Clear();
|
||||
Controls::RowDefinition titlebarRow{};
|
||||
Controls::RowDefinition contentRow{};
|
||||
titlebarRow.Height(GridLengthHelper::Auto());
|
||||
|
||||
_rootGrid.RowDefinitions().Append(titlebarRow);
|
||||
_rootGrid.RowDefinitions().Append(contentRow);
|
||||
|
||||
// Create our titlebar control
|
||||
_titlebar = winrt::TerminalApp::TitlebarControl{ reinterpret_cast<uint64_t>(GetHandle()) };
|
||||
_dragBar = _titlebar.DragBar();
|
||||
|
||||
_rootGrid.SizeChanged({ this, &NonClientIslandWindow::OnDragBarSizeChanged });
|
||||
|
||||
IslandWindow::OnAppInitialized(app);
|
||||
_rootGrid.Children().Append(_titlebar);
|
||||
|
||||
Controls::Grid::SetRow(_titlebar, 0);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Set the content of the "client area" of our window to the given content.
|
||||
// Arguments:
|
||||
// - content: the new UI element to use as the client content
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void NonClientIslandWindow::SetContent(winrt::Windows::UI::Xaml::UIElement content)
|
||||
{
|
||||
_clientContent = content;
|
||||
|
||||
_rootGrid.Children().Append(content);
|
||||
|
||||
// SetRow only works on FrameworkElement's, so cast it to a FWE before
|
||||
// calling. We know that our content is a Grid, so we don't need to worry
|
||||
// about this.
|
||||
const auto fwe = content.try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
|
||||
if (fwe)
|
||||
{
|
||||
Controls::Grid::SetRow(fwe, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Set the content of the "titlebar area" of our window to the given content.
|
||||
// Arguments:
|
||||
// - content: the new UI element to use as the titlebar content
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void NonClientIslandWindow::SetTitlebarContent(winrt::Windows::UI::Xaml::UIElement content)
|
||||
{
|
||||
_titlebar.Content(content);
|
||||
|
||||
// When the size of the titlebar content changes, we want to make sure to
|
||||
// update the size of the drag region as well.
|
||||
const auto fwe = content.try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
|
||||
if (fwe)
|
||||
{
|
||||
fwe.SizeChanged({ this, &NonClientIslandWindow::OnDragBarSizeChanged });
|
||||
}
|
||||
}
|
||||
|
||||
RECT NonClientIslandWindow::GetDragAreaRect() const noexcept
|
||||
@@ -61,7 +126,12 @@ RECT NonClientIslandWindow::GetDragAreaRect() const noexcept
|
||||
{
|
||||
const auto scale = GetCurrentDpiScale();
|
||||
const auto transform = _dragBar.TransformToVisual(_rootGrid);
|
||||
const auto logicalDragBarRect = winrt::Windows::Foundation::Rect{ 0.0f, 0.0f, static_cast<float>(_dragBar.ActualWidth()), static_cast<float>(_dragBar.ActualHeight()) };
|
||||
const auto logicalDragBarRect = winrt::Windows::Foundation::Rect{
|
||||
0.0f,
|
||||
0.0f,
|
||||
static_cast<float>(_dragBar.ActualWidth()),
|
||||
static_cast<float>(_dragBar.ActualHeight())
|
||||
};
|
||||
const auto clientDragBarRect = transform.TransformBounds(logicalDragBarRect);
|
||||
RECT dragBarRect = {
|
||||
static_cast<LONG>(clientDragBarRect.X * scale),
|
||||
@@ -118,8 +188,14 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height)
|
||||
_rootGrid.Arrange(finalRect);
|
||||
}
|
||||
|
||||
// I'm not sure that HWND_BOTTOM is any different than HWND_TOP for us.
|
||||
winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_BOTTOM, xPos, yPos, windowsWidth, windowsHeight, SWP_SHOWWINDOW));
|
||||
// I'm not sure that HWND_BOTTOM does anything differnet than HWND_TOP for us.
|
||||
winrt::check_bool(SetWindowPos(_interopWindowHandle,
|
||||
HWND_BOTTOM,
|
||||
xPos,
|
||||
yPos,
|
||||
windowsWidth,
|
||||
windowsHeight,
|
||||
SWP_SHOWWINDOW));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -143,6 +219,7 @@ void NonClientIslandWindow::_UpdateDragRegion()
|
||||
const auto width = windowRect.right - windowRect.left;
|
||||
const auto height = windowRect.bottom - windowRect.top;
|
||||
|
||||
const auto scale = GetCurrentDpiScale();
|
||||
const auto dpi = ::GetDpiForWindow(_window.get());
|
||||
|
||||
const auto dragY = ::GetSystemMetricsForDpi(SM_CYDRAG, dpi);
|
||||
@@ -318,11 +395,14 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
|
||||
// First get the monitor pointer from either the active window or the default location (0,0,0,0)
|
||||
HMONITOR hMonitor = nullptr;
|
||||
|
||||
// NOTE: We must use the nearest monitor because sometimes the system moves the window around into strange spots while performing snap and Win+D operations.
|
||||
// Those operations won't work correctly if we use MONITOR_DEFAULTTOPRIMARY.
|
||||
// NOTE: We must use the nearest monitor because sometimes the system moves
|
||||
// the window around into strange spots while performing snap and Win+D
|
||||
// operations. Those operations won't work correctly if we use
|
||||
// MONITOR_DEFAULTTOPRIMARY.
|
||||
if (!EqualRect(&rc, &rcZero))
|
||||
{
|
||||
// For invalid window handles or when we were passed a non-zero suggestion rectangle, get the monitor from the rect.
|
||||
// For invalid window handles or when we were passed a non-zero
|
||||
// suggestion rectangle, get the monitor from the rect.
|
||||
hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST);
|
||||
}
|
||||
else
|
||||
@@ -331,8 +411,9 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
|
||||
hMonitor = MonitorFromWindow(_window.get(), MONITOR_DEFAULTTONEAREST);
|
||||
}
|
||||
|
||||
// If for whatever reason there is no monitor, we're going to give back whatever we got since we can't figure anything out.
|
||||
// We won't adjust the DPI either. That's OK. DPI doesn't make much sense with no display.
|
||||
// If for whatever reason there is no monitor, we're going to give back
|
||||
// whatever we got since we can't figure anything out. We won't adjust the
|
||||
// DPI either. That's OK. DPI doesn't make much sense with no display.
|
||||
if (nullptr == hMonitor)
|
||||
{
|
||||
return rc;
|
||||
@@ -344,9 +425,11 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
|
||||
|
||||
GetMonitorInfoW(hMonitor, &MonitorInfo);
|
||||
|
||||
// We have to make a correction to the work area. If we actually consume the entire work area (by maximizing the window)
|
||||
// The window manager will render the borders off-screen.
|
||||
// We need to pad the work rectangle with the border dimensions to represent the actual max outer edges of the window rect.
|
||||
// We have to make a correction to the work area. If we actually consume the
|
||||
// entire work area (by maximizing the window). The window manager will
|
||||
// render the borders off-screen. We need to pad the work rectangle with the
|
||||
// border dimensions to represent the actual max outer edges of the window
|
||||
// rect.
|
||||
WINDOWINFO wi = { 0 };
|
||||
wi.cbSize = sizeof(WINDOWINFO);
|
||||
GetWindowInfo(_window.get(), &wi);
|
||||
@@ -464,8 +547,8 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
|
||||
const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY;
|
||||
|
||||
// Create brush for borders, titlebar color.
|
||||
const auto backgroundBrush = _dragBar.Background();
|
||||
const auto backgroundSolidBrush = backgroundBrush.as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
|
||||
const auto backgroundBrush = _titlebar.Background();
|
||||
const auto backgroundSolidBrush = backgroundBrush.as<Media::SolidColorBrush>();
|
||||
const auto backgroundColor = backgroundSolidBrush.Color();
|
||||
const auto color = RGB(backgroundColor.R, backgroundColor.G, backgroundColor.B);
|
||||
_backgroundBrush = wil::unique_hbrush(CreateSolidBrush(color));
|
||||
@@ -475,12 +558,16 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
|
||||
const auto cx = windowRect.right - windowRect.left;
|
||||
const auto cy = windowRect.bottom - windowRect.top;
|
||||
|
||||
// Fill in the _entire_ titlebar area.
|
||||
RECT dragBarRect = {};
|
||||
dragBarRect.left = xPos;
|
||||
dragBarRect.right = xPos + cx;
|
||||
dragBarRect.top = yPos;
|
||||
dragBarRect.bottom = yPos + cy;
|
||||
// Fill in ONLY the titlebar area. If we paint the _entirety_ of the
|
||||
// window rect here, the single pixel of the bottom border (set in
|
||||
// _UpdateFrameMargins) will be drawn, and blend with whatever the
|
||||
// border color is.
|
||||
RECT dragBarRect = GetDragAreaRect();
|
||||
const auto dragHeight = RECT_HEIGHT(&dragBarRect);
|
||||
dragBarRect.left = 0;
|
||||
dragBarRect.right = cx;
|
||||
dragBarRect.top = 0;
|
||||
dragBarRect.bottom = dragHeight + yPos;
|
||||
::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get());
|
||||
|
||||
// Draw the top window border
|
||||
|
||||
@@ -36,9 +36,16 @@ public:
|
||||
|
||||
MARGINS GetFrameMargins() const noexcept;
|
||||
|
||||
void OnAppInitialized(winrt::TerminalApp::App app) override;
|
||||
void Initialize() override;
|
||||
|
||||
void OnAppInitialized() override;
|
||||
void SetContent(winrt::Windows::UI::Xaml::UIElement content) override;
|
||||
void SetTitlebarContent(winrt::Windows::UI::Xaml::UIElement content);
|
||||
|
||||
private:
|
||||
winrt::TerminalApp::TitlebarControl _titlebar{ nullptr };
|
||||
winrt::Windows::UI::Xaml::UIElement _clientContent{ nullptr };
|
||||
|
||||
wil::unique_hbrush _backgroundBrush;
|
||||
wil::unique_hrgn _dragBarRegion;
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
|
||||
<PropertyGroup>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -72,46 +74,17 @@
|
||||
</ItemGroup>
|
||||
<!-- Dependencies -->
|
||||
<ItemGroup>
|
||||
<!-- Manually include the .pri files from the app project as content files. -->
|
||||
<NativeReferenceFile Include="$(OpenConsoleDir)$(Platform)\$(Configuration)\TerminalAppLib\*.pri">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</NativeReferenceFile>
|
||||
<!-- Manually include the xbf files from the app project as content files -->
|
||||
<NativeReferenceFile Include="$(OpenConsoleDir)$(Platform)\$(Configuration)\TerminalAppLib\*.xbf">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</NativeReferenceFile>
|
||||
<!--
|
||||
the packaging project wont recurse through our dependencies, you have to
|
||||
make sure that if you add a cppwinrt dependency to any of these projects,
|
||||
you also update all the consumers
|
||||
-->
|
||||
<!-- Even though we do have proper recursive dependencies, we want to keep some of these here
|
||||
so that the AppX Manifest contains their activatable classes. -->
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalSettings\TerminalSettings.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalControl\TerminalControl.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalConnection\TerminalConnection.vcxproj" />
|
||||
<!-- Don't add a ProjectReference to TerminalApp here. If you do, the
|
||||
packaging project will find the TerminalApp.pri from both the TerminalAppLib
|
||||
and TerminalApp project, and we only want this lib project's pri file. We'll
|
||||
manually add a reference to the TerminalApp winmd and dll below, because we
|
||||
still need those. -->
|
||||
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalApp\TerminalApp.vcxproj" />
|
||||
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- A small helper for paths to the compiled cppwinrt projects -->
|
||||
<_BinRoot Condition="'$(Platform)' != 'Win32'">$(OpenConsoleDir)$(Platform)\$(Configuration)\</_BinRoot>
|
||||
<_BinRoot Condition="'$(Platform)' == 'Win32'">$(OpenConsoleDir)$(Configuration)\</_BinRoot>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Manually reference TerminalApp, since we can't use a ProjectReference. -->
|
||||
<Reference Include="TerminalApp">
|
||||
<HintPath>$(_BinRoot)\TerminalApp\TerminalApp.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
<ReferenceCopyLocalPaths Include="$(_BinRoot)\TerminalApp\TerminalApp.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
This ItemGroup and the Globals PropertyGroup below it are required in order
|
||||
to enable F5 debugging for the unpackaged application
|
||||
@@ -127,6 +100,7 @@
|
||||
<!-- DON'T REDIRECT OUR OUTPUT -->
|
||||
<NoOutputRedirection>true</NoOutputRedirection>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
@@ -138,9 +112,38 @@
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets'))" />
|
||||
</Target>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.post.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190521.3\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190521.3\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets')" />
|
||||
</Project>
|
||||
|
||||
<!-- Override GetPackagingOutputs to roll up all our dependencies.
|
||||
This ensures that when the WAP packaging project asks what files go into
|
||||
the package, we tell it.
|
||||
This is a heavily stripped version of the one in Microsoft.*.AppxPackage.targets.
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<_ContinueOnError Condition="'$(BuildingProject)' == 'true'">true</_ContinueOnError>
|
||||
<_ContinueOnError Condition="'$(BuildingProject)' != 'true'">false</_ContinueOnError>
|
||||
</PropertyGroup>
|
||||
<Target Name="GetPackagingOutputs" Returns="@(PackagingOutputs)">
|
||||
<MSBuild
|
||||
Projects="@(ProjectReferenceWithConfiguration)"
|
||||
Targets="GetPackagingOutputs"
|
||||
BuildInParallel="$(BuildInParallel)"
|
||||
Properties="%(ProjectReferenceWithConfiguration.SetConfiguration); %(ProjectReferenceWithConfiguration.SetPlatform)"
|
||||
Condition="'@(ProjectReferenceWithConfiguration)' != ''
|
||||
and '%(ProjectReferenceWithConfiguration.BuildReference)' == 'true'
|
||||
and '%(ProjectReferenceWithConfiguration.ReferenceOutputAssembly)' == 'true'"
|
||||
ContinueOnError="$(_ContinueOnError)">
|
||||
<Output TaskParameter="TargetOutputs" ItemName="_PackagingOutputsFromOtherProjects"/>
|
||||
</MSBuild>
|
||||
|
||||
<ItemGroup>
|
||||
<PackagingOutputs Include="@(_PackagingOutputsFromOtherProjects)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="WindowsTerminal.manifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="AppHost.cpp" />
|
||||
<ClCompile Include="IslandWindow.cpp" />
|
||||
<ClCompile Include="NonClientIslandWindow.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="AppHost.h" />
|
||||
<ClInclude Include="BaseWindow.h" />
|
||||
<ClInclude Include="IslandWindow.h" />
|
||||
<ClInclude Include="NonClientIslandWindow.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="WindowsTerminal.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "AppHost.h"
|
||||
#include "..\..\types\Manager.h"
|
||||
#include "resource.h"
|
||||
|
||||
using namespace winrt;
|
||||
@@ -108,16 +107,6 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||
// provides an implementation of Windows.UI.Xaml.Application.
|
||||
AppHost host;
|
||||
|
||||
// Create a manager object for IPC.
|
||||
Manager manager;
|
||||
|
||||
// Create and register on connection callbacks from the manager into the application host.
|
||||
std::function<void(HANDLE)> onHandleConnection = std::bind(&AppHost::IncomingConnectionByHandle, &host, std::placeholders::_1);
|
||||
std::function<void(std::wstring_view, std::wstring_view)> onLaunchConnection = std::bind(&AppHost::IncomingConnectionByLaunch, &host, std::placeholders::_1, std::placeholders::_2);
|
||||
|
||||
Manager::s_RegisterOnConnection(onHandleConnection);
|
||||
Manager::s_RegisterOnConnection(onLaunchConnection);
|
||||
|
||||
// !!! LOAD BEARING !!!
|
||||
// This is _magic_. Do the initial loading of our settings *BEFORE* we
|
||||
// initialize our COM apartment type. This is because the Windows.Storage
|
||||
@@ -143,8 +132,5 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||
TranslateMessage(&message);
|
||||
DispatchMessage(&message);
|
||||
}
|
||||
|
||||
manager.NotifyExit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ const std::wstring_view ConsoleArguments::HEIGHT_ARG = L"--height";
|
||||
const std::wstring_view ConsoleArguments::INHERIT_CURSOR_ARG = L"--inheritcursor";
|
||||
const std::wstring_view ConsoleArguments::FEATURE_ARG = L"--feature";
|
||||
const std::wstring_view ConsoleArguments::FEATURE_PTY_ARG = L"pty";
|
||||
const std::wstring_view ConsoleArguments::FORCE_MANAGER_ARG = L"--manager";
|
||||
|
||||
std::wstring EscapeArgument(std::wstring_view ac)
|
||||
{
|
||||
@@ -103,9 +102,7 @@ ConsoleArguments::ConsoleArguments(const std::wstring& commandline,
|
||||
_vtOutHandle(hStdOut),
|
||||
_recievedEarlySizeChange{ false },
|
||||
_originalWidth{ -1 },
|
||||
_originalHeight{ -1 },
|
||||
_forceManager{ false },
|
||||
_workingDirectory{ wil::GetCurrentDirectoryW().get() }
|
||||
_originalHeight{ -1 }
|
||||
{
|
||||
_clientCommandline = L"";
|
||||
_vtMode = L"";
|
||||
@@ -288,7 +285,7 @@ void ConsoleArguments::s_ConsumeArg(_Inout_ std::vector<std::wstring>& args, _In
|
||||
// - S_OK if we could successfully parse the given text and store it in the handle value location.
|
||||
// - E_INVALIDARG if we couldn't parse the text as a valid hex-encoded handle number OR
|
||||
// if the handle value was already filled.
|
||||
[[nodiscard]] HRESULT ConsoleArguments::s_ParseHandleArg(const std::wstring& handleAsText, _Inout_ HANDLE& handleAsVal)
|
||||
[[nodiscard]] HRESULT ConsoleArguments::s_ParseHandleArg(const std::wstring& handleAsText, _Inout_ DWORD& handleAsVal)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
@@ -299,15 +296,13 @@ void ConsoleArguments::s_ConsumeArg(_Inout_ std::vector<std::wstring>& args, _In
|
||||
}
|
||||
else if (0 == handleAsVal)
|
||||
{
|
||||
const auto handleAsUlong = wcstoul(handleAsText.c_str(), nullptr /*endptr*/, 16 /*base*/);
|
||||
handleAsVal = wcstoul(handleAsText.c_str(), nullptr /*endptr*/, 16 /*base*/);
|
||||
|
||||
// If the handle didn't parse into a reasonable handle ID, invalid.
|
||||
if (handleAsUlong == 0)
|
||||
if (handleAsVal == 0)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
handleAsVal = UlongToHandle(handleAsUlong);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -472,12 +467,6 @@ void ConsoleArguments::s_ConsumeArg(_Inout_ std::vector<std::wstring>& args, _In
|
||||
{
|
||||
hr = s_HandleFeatureValue(args, i);
|
||||
}
|
||||
else if (arg == FORCE_MANAGER_ARG)
|
||||
{
|
||||
_forceManager = true;
|
||||
s_ConsumeArg(args, i);
|
||||
hr = S_OK;
|
||||
}
|
||||
else if (arg == HEADLESS_ARG)
|
||||
{
|
||||
_headless = true;
|
||||
@@ -563,72 +552,62 @@ bool ConsoleArguments::InConptyMode() const noexcept
|
||||
return IsValidHandle(_vtInHandle) || IsValidHandle(_vtOutHandle) || HasSignalHandle();
|
||||
}
|
||||
|
||||
bool ConsoleArguments::IsHeadless() const noexcept
|
||||
bool ConsoleArguments::IsHeadless() const
|
||||
{
|
||||
return _headless;
|
||||
}
|
||||
|
||||
bool ConsoleArguments::ShouldCreateServerHandle() const noexcept
|
||||
bool ConsoleArguments::ShouldCreateServerHandle() const
|
||||
{
|
||||
return _createServerHandle;
|
||||
}
|
||||
|
||||
bool ConsoleArguments::ShouldSendToManager() const noexcept
|
||||
HANDLE ConsoleArguments::GetServerHandle() const
|
||||
{
|
||||
return _forceManager;
|
||||
return ULongToHandle(_serverHandle);
|
||||
}
|
||||
|
||||
HANDLE ConsoleArguments::GetServerHandle() const noexcept
|
||||
HANDLE ConsoleArguments::GetSignalHandle() const
|
||||
{
|
||||
return _serverHandle;
|
||||
return ULongToHandle(_signalHandle);
|
||||
}
|
||||
|
||||
void ConsoleArguments::SetServerHandle(const HANDLE server) noexcept
|
||||
{
|
||||
_serverHandle = server;
|
||||
}
|
||||
|
||||
HANDLE ConsoleArguments::GetSignalHandle() const noexcept
|
||||
{
|
||||
return _signalHandle;
|
||||
}
|
||||
|
||||
HANDLE ConsoleArguments::GetVtInHandle() const noexcept
|
||||
HANDLE ConsoleArguments::GetVtInHandle() const
|
||||
{
|
||||
return _vtInHandle;
|
||||
}
|
||||
|
||||
HANDLE ConsoleArguments::GetVtOutHandle() const noexcept
|
||||
HANDLE ConsoleArguments::GetVtOutHandle() const
|
||||
{
|
||||
return _vtOutHandle;
|
||||
}
|
||||
|
||||
std::wstring_view ConsoleArguments::GetClientCommandline() const noexcept
|
||||
std::wstring ConsoleArguments::GetClientCommandline() const
|
||||
{
|
||||
return _clientCommandline;
|
||||
}
|
||||
|
||||
std::wstring ConsoleArguments::GetVtMode() const noexcept
|
||||
std::wstring ConsoleArguments::GetVtMode() const
|
||||
{
|
||||
return _vtMode;
|
||||
}
|
||||
|
||||
bool ConsoleArguments::GetForceV1() const noexcept
|
||||
bool ConsoleArguments::GetForceV1() const
|
||||
{
|
||||
return _forceV1;
|
||||
}
|
||||
|
||||
short ConsoleArguments::GetWidth() const noexcept
|
||||
short ConsoleArguments::GetWidth() const
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
short ConsoleArguments::GetHeight() const noexcept
|
||||
short ConsoleArguments::GetHeight() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
bool ConsoleArguments::GetInheritCursor() const noexcept
|
||||
bool ConsoleArguments::GetInheritCursor() const
|
||||
{
|
||||
return _inheritCursor;
|
||||
}
|
||||
|
||||
@@ -33,26 +33,23 @@ public:
|
||||
|
||||
bool HasVtHandles() const;
|
||||
bool InConptyMode() const noexcept;
|
||||
bool IsHeadless() const noexcept;
|
||||
bool ShouldCreateServerHandle() const noexcept;
|
||||
bool ShouldSendToManager() const noexcept;
|
||||
bool IsHeadless() const;
|
||||
bool ShouldCreateServerHandle() const;
|
||||
|
||||
HANDLE GetServerHandle() const noexcept;
|
||||
void SetServerHandle(const HANDLE server) noexcept;
|
||||
|
||||
HANDLE GetVtInHandle() const noexcept;
|
||||
HANDLE GetVtOutHandle() const noexcept;
|
||||
HANDLE GetServerHandle() const;
|
||||
HANDLE GetVtInHandle() const;
|
||||
HANDLE GetVtOutHandle() const;
|
||||
|
||||
bool HasSignalHandle() const;
|
||||
HANDLE GetSignalHandle() const noexcept;
|
||||
HANDLE GetSignalHandle() const;
|
||||
|
||||
std::wstring_view GetClientCommandline() const noexcept;
|
||||
std::wstring GetVtMode() const noexcept;
|
||||
bool GetForceV1() const noexcept;
|
||||
std::wstring GetClientCommandline() const;
|
||||
std::wstring GetVtMode() const;
|
||||
bool GetForceV1() const;
|
||||
|
||||
short GetWidth() const noexcept;
|
||||
short GetHeight() const noexcept;
|
||||
bool GetInheritCursor() const noexcept;
|
||||
short GetWidth() const;
|
||||
short GetHeight() const;
|
||||
bool GetInheritCursor() const;
|
||||
|
||||
void SetExpectedSize(COORD dimensions) noexcept;
|
||||
|
||||
@@ -69,7 +66,6 @@ public:
|
||||
static const std::wstring_view INHERIT_CURSOR_ARG;
|
||||
static const std::wstring_view FEATURE_ARG;
|
||||
static const std::wstring_view FEATURE_PTY_ARG;
|
||||
static const std::wstring_view FORCE_MANAGER_ARG;
|
||||
|
||||
private:
|
||||
#ifdef UNIT_TESTING
|
||||
@@ -111,8 +107,6 @@ private:
|
||||
|
||||
std::wstring _clientCommandline;
|
||||
|
||||
std::wstring _workingDirectory;
|
||||
|
||||
HANDLE _vtInHandle;
|
||||
|
||||
HANDLE _vtOutHandle;
|
||||
@@ -125,10 +119,9 @@ private:
|
||||
short _width;
|
||||
short _height;
|
||||
|
||||
bool _forceManager;
|
||||
bool _createServerHandle;
|
||||
HANDLE _serverHandle;
|
||||
HANDLE _signalHandle;
|
||||
DWORD _serverHandle;
|
||||
DWORD _signalHandle;
|
||||
bool _inheritCursor;
|
||||
|
||||
bool _recievedEarlySizeChange;
|
||||
@@ -151,7 +144,7 @@ private:
|
||||
_Inout_ size_t& index);
|
||||
|
||||
[[nodiscard]] static HRESULT s_ParseHandleArg(const std::wstring& handleAsText,
|
||||
_Inout_ HANDLE& handle);
|
||||
_Inout_ DWORD& handleAsVal);
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class ConsoleArgumentsTests;
|
||||
|
||||
@@ -77,7 +77,28 @@ VtInputThread::VtInputThread(_In_ wil::unique_hfile hPipe,
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
_pInputStateMachine->ProcessString(pwsSequence.get(), cchSequence);
|
||||
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
if (gci.GetVtIo()->IsInPassthroughMode())
|
||||
{
|
||||
try
|
||||
{
|
||||
std::deque<std::unique_ptr<IInputEvent>> inputEvents;
|
||||
for (size_t i = 0; i < cchSequence; i++)
|
||||
{
|
||||
inputEvents.push_back(std::make_unique<KeyEvent>(true, 1ui16, 0ui16, 0ui16, pwsSequence[i], 0));
|
||||
}
|
||||
gci.GetActiveInputBuffer()->Write(inputEvents);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_HR(wil::ResultFromCaughtException());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_pInputStateMachine->ProcessString(pwsSequence.get(), cchSequence);
|
||||
}
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
|
||||
@@ -70,14 +70,14 @@ VtIo::VtIo() :
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtIo::Initialize(const ConsoleArguments args)
|
||||
[[nodiscard]] HRESULT VtIo::Initialize(const ConsoleArguments* const pArgs)
|
||||
{
|
||||
_lookingForCursorPosition = args.GetInheritCursor();
|
||||
_lookingForCursorPosition = pArgs->GetInheritCursor();
|
||||
|
||||
// If we were already given VT handles, set up the VT IO engine to use those.
|
||||
if (args.InConptyMode())
|
||||
if (pArgs->InConptyMode())
|
||||
{
|
||||
return _Initialize(args.GetVtInHandle(), args.GetVtOutHandle(), args.GetVtMode(), args.GetSignalHandle());
|
||||
return _Initialize(pArgs->GetVtInHandle(), pArgs->GetVtOutHandle(), pArgs->GetVtMode(), pArgs->GetSignalHandle());
|
||||
}
|
||||
// Didn't need to initialize if we didn't have VT stuff. It's still OK, but report we did nothing.
|
||||
else
|
||||
@@ -397,3 +397,18 @@ void VtIo::_ShutdownIfNeeded()
|
||||
ServiceLocator::RundownAndExit(ERROR_BROKEN_PIPE);
|
||||
}
|
||||
}
|
||||
|
||||
void VtIo::SetPassthroughMode(const bool enable)
|
||||
{
|
||||
_pVtRenderEngine->SetPassthroughMode(enable);
|
||||
}
|
||||
bool VtIo::IsInPassthroughMode()
|
||||
{
|
||||
return _pVtRenderEngine->IsInPassthroughMode();
|
||||
}
|
||||
void VtIo::PassthroughString(std::wstring_view view)
|
||||
{
|
||||
std::wstring wstr{ view };
|
||||
// LOG_IF_FAILED(_pVtRenderEngine->WriteTerminalW(wstr));
|
||||
_pVtRenderEngine->PassthroughString(wstr);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
VtIo();
|
||||
virtual ~VtIo() override = default;
|
||||
|
||||
[[nodiscard]] HRESULT Initialize(const ConsoleArguments args);
|
||||
[[nodiscard]] HRESULT Initialize(const ConsoleArguments* const pArgs);
|
||||
|
||||
[[nodiscard]] HRESULT CreateAndStartSignalThread() noexcept;
|
||||
[[nodiscard]] HRESULT CreateIoHandlers() noexcept;
|
||||
@@ -36,6 +36,10 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
void CloseInput() override;
|
||||
void CloseOutput() override;
|
||||
|
||||
void SetPassthroughMode(const bool enable);
|
||||
void PassthroughString(std::wstring_view view);
|
||||
bool IsInPassthroughMode();
|
||||
|
||||
private:
|
||||
// After CreateIoHandlers is called, these will be invalid.
|
||||
wil::unique_hfile _hInput;
|
||||
|
||||
@@ -941,6 +941,17 @@ using Microsoft::Console::VirtualTerminal::StateMachine;
|
||||
const DWORD dwFlags,
|
||||
_Inout_opt_ PSHORT const psScrollY)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
if (gci.IsInVtIoMode() && gci.GetVtIo()->IsInPassthroughMode())
|
||||
// if (WI_IsFlagSet(screenInfo.OutputMode, ENABLE_PASSTHROUGH_MODE))
|
||||
{
|
||||
const size_t BufferSize = *pcb;
|
||||
const size_t cch = BufferSize / sizeof(WCHAR);
|
||||
gci.GetVtIo()->PassthroughString({ pwchRealUnicode, cch });
|
||||
// *pcb += BufferSize;
|
||||
// return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!WI_IsFlagSet(screenInfo.OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING) ||
|
||||
!WI_IsFlagSet(screenInfo.OutputMode, ENABLE_PROCESSED_OUTPUT))
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "srvinit.h"
|
||||
#include "..\server\Entrypoints.h"
|
||||
#include "..\interactivity\inc\ServiceLocator.hpp"
|
||||
#include "..\types\Manager.h"
|
||||
|
||||
// Define TraceLogging provider
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
@@ -196,7 +195,7 @@ int CALLBACK wWinMain(
|
||||
{
|
||||
if (args.ShouldCreateServerHandle())
|
||||
{
|
||||
hr = Entrypoints::StartConsoleForCmdLine(args);
|
||||
hr = Entrypoints::StartConsoleForCmdLine(args.GetClientCommandline().c_str(), &args);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -204,7 +203,7 @@ int CALLBACK wWinMain(
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = Entrypoints::StartConsoleForServerHandle(args);
|
||||
hr = Entrypoints::StartConsoleForServerHandle(args.GetServerHandle(), &args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define VALID_TEXT_ATTRIBUTES (FG_ATTRS | BG_ATTRS | META_ATTRS)
|
||||
|
||||
#define INPUT_MODES (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT)
|
||||
#define OUTPUT_MODES (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN | ENABLE_LVB_GRID_WORLDWIDE)
|
||||
#define OUTPUT_MODES (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN | ENABLE_LVB_GRID_WORLDWIDE | ENABLE_PASSTHROUGH_MODE)
|
||||
#define PRIVATE_MODES (ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_AUTO_POSITION | ENABLE_EXTENDED_FLAGS)
|
||||
|
||||
using namespace Microsoft::Console::Types;
|
||||
@@ -394,7 +394,14 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
|
||||
|
||||
SCREEN_INFORMATION& screenInfo = context.GetActiveBuffer();
|
||||
const DWORD dwOldMode = screenInfo.OutputMode;
|
||||
const DWORD dwNewMode = mode;
|
||||
DWORD preprocessNewMode = mode;
|
||||
|
||||
if (!gci.IsInVtIoMode() &&
|
||||
(WI_IsFlagSet(preprocessNewMode, ENABLE_PASSTHROUGH_MODE)))
|
||||
{
|
||||
WI_ClearFlag(preprocessNewMode, ENABLE_PASSTHROUGH_MODE);
|
||||
}
|
||||
const DWORD dwNewMode = preprocessNewMode;
|
||||
|
||||
screenInfo.OutputMode = dwNewMode;
|
||||
|
||||
@@ -413,6 +420,31 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
|
||||
screenInfo.SetDefaultVtTabStops();
|
||||
}
|
||||
|
||||
if (gci.IsInVtIoMode())
|
||||
{
|
||||
// if we're moving from passthrough on->off
|
||||
if (WI_IsFlagClear(dwNewMode, ENABLE_PASSTHROUGH_MODE) &&
|
||||
WI_IsFlagSet(dwOldMode, ENABLE_PASSTHROUGH_MODE))
|
||||
{
|
||||
gci.GetVtIo()->SetPassthroughMode(false);
|
||||
// Trigger a redaw all, to sync us back up.
|
||||
ServiceLocator::LocateGlobals().pRender->TriggerRedrawAll();
|
||||
}
|
||||
// if we're moving from passthrough off->on
|
||||
else if (WI_IsFlagSet(dwNewMode, ENABLE_PASSTHROUGH_MODE) &&
|
||||
WI_IsFlagClear(dwOldMode, ENABLE_PASSTHROUGH_MODE))
|
||||
{
|
||||
// DebugBreak();
|
||||
// Trigger a frame NOW, to flush any state since the last frame
|
||||
RECT dummy{ 0 };
|
||||
// ServiceLocator::LocateGlobals().pRender->TriggerSystemRedraw(&dummy);
|
||||
// ServiceLocator::LocateGlobals().pRender->WaitForPaintCompletion(1000);
|
||||
LOG_IF_FAILED(ServiceLocator::LocateGlobals().pRender->PaintFrame());
|
||||
gci.GetVtIo()->SetPassthroughMode(true);
|
||||
ServiceLocator::LocateGlobals().pRender->WaitForPaintCompletion(1000);
|
||||
}
|
||||
}
|
||||
|
||||
gci.SetVirtTermLevel(WI_IsFlagSet(dwNewMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING) ? 1 : 0);
|
||||
gci.SetAutomaticReturnOnNewline(WI_IsFlagSet(screenInfo.OutputMode, DISABLE_NEWLINE_AUTO_RETURN) ? false : true);
|
||||
gci.SetGridRenderingAllowedWorldwide(WI_IsFlagSet(screenInfo.OutputMode, ENABLE_LVB_GRID_WORLDWIDE));
|
||||
|
||||
@@ -71,6 +71,9 @@ Revision History:
|
||||
#define CONSOLE_SUSPENDED (CONSOLE_OUTPUT_SUSPENDED)
|
||||
// clang-format on
|
||||
|
||||
// ENABLE_LVB_GRID_WORLDWIDE is 0x0010
|
||||
#define ENABLE_PASSTHROUGH_MODE 0x0020
|
||||
|
||||
class COOKED_READ_DATA;
|
||||
class CommandHistory;
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "renderFontDefaults.hpp"
|
||||
|
||||
#include "ApiRoutines.h"
|
||||
#include "ConsoleArguments.hpp"
|
||||
|
||||
#include "../types/inc/GlyphWidth.hpp"
|
||||
|
||||
@@ -32,15 +31,15 @@ using namespace Microsoft::Console::Render;
|
||||
const UINT CONSOLE_EVENT_FAILURE_ID = 21790;
|
||||
const UINT CONSOLE_LPC_PORT_FAILURE_ID = 21791;
|
||||
|
||||
[[nodiscard]] HRESULT ConsoleServerInitialization(const ConsoleArguments& args)
|
||||
[[nodiscard]] HRESULT ConsoleServerInitialization(_In_ HANDLE Server, const ConsoleArguments* const args)
|
||||
{
|
||||
Globals& Globals = ServiceLocator::LocateGlobals();
|
||||
|
||||
try
|
||||
{
|
||||
Globals.pDeviceComm = new DeviceComm(args.GetServerHandle());
|
||||
Globals.pDeviceComm = new DeviceComm(Server);
|
||||
|
||||
Globals.launchArgs = args;
|
||||
Globals.launchArgs = *args;
|
||||
|
||||
Globals.uiOEMCP = GetOEMCP();
|
||||
Globals.uiWindowsCP = GetACP();
|
||||
@@ -246,10 +245,10 @@ void ConsoleCheckDebug()
|
||||
#endif
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT ConsoleCreateIoThreadLegacy(const ConsoleArguments& args)
|
||||
[[nodiscard]] HRESULT ConsoleCreateIoThreadLegacy(_In_ HANDLE Server, const ConsoleArguments* const args)
|
||||
{
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
RETURN_IF_FAILED(ConsoleServerInitialization(args));
|
||||
RETURN_IF_FAILED(ConsoleServerInitialization(Server, args));
|
||||
RETURN_IF_FAILED(g.hConsoleInputInitEvent.create(wil::EventOptions::None));
|
||||
|
||||
// Set up and tell the driver about the input available event.
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <future>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
@@ -201,7 +201,6 @@ bool SignalResizeWindow(const HANDLE hSignal,
|
||||
// - startingDirectory: The directory to start the process in
|
||||
// - w: The initial width of the pty, in characters
|
||||
// - h: The initial height of the pty, in characters
|
||||
// - hServer: An optional handle to a server connection handle already established for this PTY.
|
||||
// - hInput: A handle to the pipe for writing input to the pty.
|
||||
// - hOutput: A handle to the pipe for reading the output of the pty.
|
||||
// - hSignal: A handle to the pipe for writing signal messages to the pty.
|
||||
@@ -217,7 +216,6 @@ bool SignalResizeWindow(const HANDLE hSignal,
|
||||
std::optional<std::wstring> startingDirectory,
|
||||
const unsigned short w,
|
||||
const unsigned short h,
|
||||
std::optional<HANDLE> const hServer,
|
||||
HANDLE* const hInput,
|
||||
HANDLE* const hOutput,
|
||||
HANDLE* const hSignal,
|
||||
@@ -256,11 +254,6 @@ bool SignalResizeWindow(const HANDLE hSignal,
|
||||
SetHandleInformation(outPipeConhostSide, HANDLE_FLAG_INHERIT, 1);
|
||||
SetHandleInformation(signalPipeConhostSide, HANDLE_FLAG_INHERIT, 1);
|
||||
|
||||
if (hServer.has_value())
|
||||
{
|
||||
SetHandleInformation(hServer.value(), HANDLE_FLAG_INHERIT, 1);
|
||||
}
|
||||
|
||||
std::wstring conhostCmdline = L"conhost.exe";
|
||||
conhostCmdline += L" --headless";
|
||||
std::wstringstream ss;
|
||||
@@ -271,19 +264,9 @@ bool SignalResizeWindow(const HANDLE hSignal,
|
||||
}
|
||||
|
||||
ss << L" --signal 0x" << std::hex << HandleToUlong(signalPipeConhostSide);
|
||||
|
||||
if (hServer.has_value())
|
||||
{
|
||||
ss << L" --server 0x" << std::hex << HandleToUlong(hServer.value());
|
||||
}
|
||||
|
||||
conhostCmdline += ss.str();
|
||||
|
||||
if (!hServer.has_value())
|
||||
{
|
||||
conhostCmdline += L" -- ";
|
||||
conhostCmdline += cmdline;
|
||||
}
|
||||
conhostCmdline += L" -- ";
|
||||
conhostCmdline += cmdline;
|
||||
|
||||
STARTUPINFO si = { 0 };
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
|
||||
@@ -27,6 +27,7 @@ Author(s):
|
||||
|
||||
// UNICODE_NULL is a Windows macro definition
|
||||
const wchar_t UNICODE_BACKSPACE = 0x8;
|
||||
const wchar_t UNICODE_ESC = 0x1b;
|
||||
const wchar_t UNICODE_DEL = 0x7f;
|
||||
// NOTE: This isn't actually a backspace. It's a graphical block. But
|
||||
// I believe it's emitted by one of our ANSI/OEM --> Unicode conversions.
|
||||
|
||||
@@ -507,6 +507,11 @@ void Renderer::WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs)
|
||||
_pThread->WaitForPaintCompletionAndDisable(dwTimeoutMs);
|
||||
}
|
||||
|
||||
void Renderer::WaitForPaintCompletion(const DWORD dwTimeoutMs)
|
||||
{
|
||||
_pThread->WaitForPaintCompletion(dwTimeoutMs);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Paint helper to fill in the background color of the invalid area within the frame.
|
||||
// Arguments:
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
void EnablePainting() override;
|
||||
void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) override;
|
||||
void WaitForPaintCompletion(const DWORD dwTimeoutMs) override;
|
||||
|
||||
void AddRenderEngine(_In_ IRenderEngine* const pEngine) override;
|
||||
|
||||
|
||||
@@ -242,3 +242,8 @@ void RenderThread::WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs)
|
||||
ResetEvent(_hPaintEnabledEvent);
|
||||
WaitForSingleObject(_hPaintCompletedEvent, dwTimeoutMs);
|
||||
}
|
||||
|
||||
void RenderThread::WaitForPaintCompletion(const DWORD dwTimeoutMs)
|
||||
{
|
||||
WaitForSingleObject(_hPaintCompletedEvent, dwTimeoutMs);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
void EnablePainting() override;
|
||||
void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) override;
|
||||
void WaitForPaintCompletion(const DWORD dwTimeoutMs) override;
|
||||
|
||||
private:
|
||||
static DWORD WINAPI s_ThreadProc(_In_ LPVOID lpParameter);
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Microsoft::Console::Render
|
||||
virtual void NotifyPaint() = 0;
|
||||
virtual void EnablePainting() = 0;
|
||||
virtual void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) = 0;
|
||||
virtual void WaitForPaintCompletion(const DWORD dwTimeoutMs) = 0;
|
||||
};
|
||||
|
||||
inline Microsoft::Console::Render::IRenderThread::~IRenderThread(){};
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
virtual void EnablePainting() = 0;
|
||||
virtual void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) = 0;
|
||||
virtual void WaitForPaintCompletion(const DWORD dwTimeoutMs) = 0;
|
||||
|
||||
virtual void AddRenderEngine(_In_ IRenderEngine* const pEngine) = 0;
|
||||
};
|
||||
|
||||
@@ -40,7 +40,11 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
|
||||
// the pipe.
|
||||
[[nodiscard]] HRESULT XtermEngine::StartPaint() noexcept
|
||||
{
|
||||
RETURN_IF_FAILED(VtEngine::StartPaint());
|
||||
const auto hr = VtEngine::StartPaint();
|
||||
if (hr == S_FALSE)
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
_trace.TraceLastText(_lastText);
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ using namespace Microsoft::Console::Types;
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
if (_passthroughMode)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
// If there's nothing to do, quick return
|
||||
bool somethingToDo = _fInvalidRectUsed ||
|
||||
|
||||
@@ -417,3 +417,19 @@ HRESULT VtEngine::RequestCursor() noexcept
|
||||
RETURN_IF_FAILED(_Flush());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void VtEngine::SetPassthroughMode(const bool enable)
|
||||
{
|
||||
_passthroughMode = enable;
|
||||
}
|
||||
|
||||
void VtEngine::PassthroughString(const std::wstring& wstr)
|
||||
{
|
||||
LOG_IF_FAILED(WriteTerminalW(wstr));
|
||||
LOG_IF_FAILED(_Flush());
|
||||
}
|
||||
|
||||
bool VtEngine::IsInPassthroughMode()
|
||||
{
|
||||
return _passthroughMode;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,10 @@ namespace Microsoft::Console::Render
|
||||
|
||||
void SetTerminalOwner(Microsoft::Console::ITerminalOwner* const terminalOwner);
|
||||
|
||||
void SetPassthroughMode(const bool enable);
|
||||
void PassthroughString(const std::wstring& wstr);
|
||||
bool IsInPassthroughMode();
|
||||
|
||||
protected:
|
||||
wil::unique_hfile _hFile;
|
||||
std::string _buffer;
|
||||
@@ -133,6 +137,8 @@ namespace Microsoft::Console::Render
|
||||
|
||||
Microsoft::Console::VirtualTerminal::RenderTracing _trace;
|
||||
|
||||
bool _passthroughMode{ false };
|
||||
|
||||
[[nodiscard]] HRESULT _Write(std::string_view const str) noexcept;
|
||||
[[nodiscard]] HRESULT _WriteFormattedString(const std::string* const pFormat, ...) noexcept;
|
||||
[[nodiscard]] HRESULT _Flush() noexcept;
|
||||
|
||||
@@ -9,21 +9,10 @@
|
||||
|
||||
#include "winbasep.h"
|
||||
|
||||
#include "..\types\Manager.h"
|
||||
#include "..\host\ConsoleArguments.hpp"
|
||||
|
||||
[[nodiscard]] HRESULT Entrypoints::StartConsoleForServerHandle(const ConsoleArguments& args)
|
||||
[[nodiscard]] HRESULT Entrypoints::StartConsoleForServerHandle(const HANDLE ServerHandle,
|
||||
const ConsoleArguments* const args)
|
||||
{
|
||||
if (args.ShouldSendToManager())
|
||||
{
|
||||
if (Manager::s_TrySendToManager(args.GetServerHandle()))
|
||||
{
|
||||
SleepEx(INFINITE, FALSE);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ConsoleCreateIoThreadLegacy(args);
|
||||
return ConsoleCreateIoThreadLegacy(ServerHandle, args);
|
||||
}
|
||||
|
||||
// this function has unreachable code due to its unusual lifetime. We
|
||||
@@ -31,17 +20,9 @@
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4702)
|
||||
|
||||
[[nodiscard]] HRESULT Entrypoints::StartConsoleForCmdLine(ConsoleArguments& args)
|
||||
[[nodiscard]] HRESULT Entrypoints::StartConsoleForCmdLine(_In_ PCWSTR pwszCmdLine,
|
||||
const ConsoleArguments* const args)
|
||||
{
|
||||
if (args.ShouldSendToManager())
|
||||
{
|
||||
if (Manager::s_TrySendToManager(args.GetClientCommandline(), L"C:\\windows\\system32"))
|
||||
{
|
||||
SleepEx(INFINITE, FALSE);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a scope because we're going to exit thread if everything goes well.
|
||||
// This scope will ensure all C++ objects and smart pointers get a chance to destruct before ExitThread is called.
|
||||
{
|
||||
@@ -58,8 +39,7 @@
|
||||
L"\\Reference",
|
||||
FALSE));
|
||||
|
||||
args.SetServerHandle(ServerHandle.get());
|
||||
RETURN_IF_NTSTATUS_FAILED(Entrypoints::StartConsoleForServerHandle(args));
|
||||
RETURN_IF_NTSTATUS_FAILED(Entrypoints::StartConsoleForServerHandle(ServerHandle.get(), args));
|
||||
|
||||
// If we get to here, we have transferred ownership of the server handle to the console, so release it.
|
||||
// Keep a copy of the value so we can open the client handles even though we're no longer the owner.
|
||||
@@ -163,8 +143,6 @@
|
||||
NULL));
|
||||
|
||||
// We have to copy the command line string we're given because CreateProcessW has to be called with mutable data.
|
||||
PCWSTR pwszCmdLine = args.GetClientCommandline().data();
|
||||
|
||||
if (wcslen(pwszCmdLine) == 0)
|
||||
{
|
||||
// If they didn't give us one, just launch cmd.exe.
|
||||
|
||||
@@ -20,6 +20,6 @@ class ConsoleArguments;
|
||||
|
||||
namespace Entrypoints
|
||||
{
|
||||
[[nodiscard]] HRESULT StartConsoleForServerHandle(const ConsoleArguments& args);
|
||||
[[nodiscard]] HRESULT StartConsoleForCmdLine(ConsoleArguments& args);
|
||||
[[nodiscard]] HRESULT StartConsoleForServerHandle(const HANDLE ServerHandle, const ConsoleArguments* const args);
|
||||
[[nodiscard]] HRESULT StartConsoleForCmdLine(_In_ PCWSTR pwszCmdLine, const ConsoleArguments* const args);
|
||||
};
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
|
||||
class ConsoleArguments;
|
||||
|
||||
[[nodiscard]] HRESULT ConsoleCreateIoThreadLegacy(const ConsoleArguments& args);
|
||||
[[nodiscard]] HRESULT ConsoleCreateIoThreadLegacy(_In_ HANDLE Server, const ConsoleArguments* const args);
|
||||
|
||||
@@ -2,9 +2,178 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include <windows.h>
|
||||
#include <wil\Common.h>
|
||||
#include <wil\result.h>
|
||||
#include <wil\resource.h>
|
||||
#include <wil\wistd_functional.h>
|
||||
#include <wil\wistd_memory.h>
|
||||
#include <stdlib.h> /* srand, rand */
|
||||
#include <time.h> /* time */
|
||||
#include <conio.h>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <assert.h>
|
||||
|
||||
#define ENABLE_PASSTHROUGH_MODE 0x0020
|
||||
|
||||
std::string csi(std::string seq)
|
||||
{
|
||||
std::string fullSeq = "\x1b[";
|
||||
fullSeq += seq;
|
||||
return fullSeq;
|
||||
}
|
||||
|
||||
std::string osc(std::string seq)
|
||||
{
|
||||
std::string fullSeq = "\x1b]";
|
||||
fullSeq += seq;
|
||||
fullSeq += "\x7";
|
||||
return fullSeq;
|
||||
}
|
||||
|
||||
void testOutput()
|
||||
{
|
||||
wprintf(L"Attempting to start passthrough mode...\n");
|
||||
auto hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
DWORD dwMode = 0;
|
||||
THROW_LAST_ERROR_IF(!GetConsoleMode(hOut, &dwMode));
|
||||
|
||||
wprintf(L"Original Mode: 0x%x\n", dwMode);
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
dwMode |= DISABLE_NEWLINE_AUTO_RETURN;
|
||||
dwMode |= ENABLE_PASSTHROUGH_MODE;
|
||||
|
||||
wprintf(L"Requested Mode: 0x%x\n", dwMode);
|
||||
THROW_LAST_ERROR_IF(!SetConsoleMode(hOut, dwMode));
|
||||
|
||||
DWORD roundtripMode = 0;
|
||||
THROW_LAST_ERROR_IF(!GetConsoleMode(hOut, &roundtripMode));
|
||||
wprintf(L"Rountripped Mode: 0x%x\n", dwMode);
|
||||
|
||||
if (roundtripMode != dwMode)
|
||||
{
|
||||
wprintf(L"Mode did not rountrip\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
wprintf(L"Mode rountripped successfully\n");
|
||||
}
|
||||
|
||||
wprintf(L"Press a key to continue\n");
|
||||
_getch();
|
||||
|
||||
wprintf(L"We're going to write some VT straight to the terminal\n");
|
||||
|
||||
printf(csi("31m").c_str());
|
||||
printf(osc("0;Title:foo").c_str());
|
||||
wprintf(L"Press a key to continue\n");
|
||||
_getch();
|
||||
|
||||
printf(csi("0m").c_str());
|
||||
wprintf(L"Time for something more complicated...\n");
|
||||
Sleep(500);
|
||||
printf(csi("2;1H").c_str());
|
||||
printf(csi("44m").c_str());
|
||||
printf(csi("K").c_str());
|
||||
Sleep(500);
|
||||
|
||||
printf(csi("9;1H").c_str());
|
||||
printf(csi("46m").c_str());
|
||||
printf(csi("K").c_str());
|
||||
Sleep(500);
|
||||
|
||||
printf(csi("3;8r").c_str());
|
||||
printf(csi("3;1H").c_str());
|
||||
printf(csi("0m").c_str());
|
||||
Sleep(500);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
wprintf(L"Print in the margins %d\n", i);
|
||||
Sleep(500);
|
||||
}
|
||||
|
||||
printf(csi("r").c_str());
|
||||
wprintf(L"Press a key to continue\n");
|
||||
_getch();
|
||||
}
|
||||
|
||||
void launchChild(int argc, WCHAR* argv[])
|
||||
{
|
||||
auto hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
auto hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
DWORD dwMode = 0;
|
||||
THROW_LAST_ERROR_IF(!GetConsoleMode(hOut, &dwMode));
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
dwMode |= DISABLE_NEWLINE_AUTO_RETURN;
|
||||
dwMode |= ENABLE_PASSTHROUGH_MODE;
|
||||
THROW_LAST_ERROR_IF(!SetConsoleMode(hOut, dwMode));
|
||||
|
||||
DWORD dwInMode = 0;
|
||||
GetConsoleMode(hIn, &dwInMode);
|
||||
dwInMode = ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||
SetConsoleMode(hIn, dwInMode);
|
||||
|
||||
std::wstring commandline = L"";
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
commandline += (argv[i]);
|
||||
commandline += (L" ");
|
||||
}
|
||||
|
||||
std::unique_ptr<wchar_t[]> mutableCommandline = std::make_unique<wchar_t[]>(commandline.length() + 1);
|
||||
THROW_IF_NULL_ALLOC(mutableCommandline);
|
||||
|
||||
HRESULT hr = StringCchCopy(mutableCommandline.get(), commandline.length() + 1, commandline.c_str());
|
||||
THROW_IF_FAILED(hr);
|
||||
|
||||
STARTUPINFO si = { 0 };
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
PROCESS_INFORMATION _piClient;
|
||||
|
||||
bool fSuccess = !!CreateProcessW(
|
||||
nullptr,
|
||||
mutableCommandline.get(),
|
||||
nullptr, // lpProcessAttributes
|
||||
nullptr, // lpThreadAttributes
|
||||
true, // bInheritHandles
|
||||
false, // dwCreationFlags
|
||||
nullptr, // lpEnvironment
|
||||
nullptr, // lpCurrentDirectory
|
||||
&si, // lpStartupInfo
|
||||
&_piClient // lpProcessInformation
|
||||
);
|
||||
THROW_LAST_ERROR_IF(!fSuccess);
|
||||
|
||||
// Sleep(10000);
|
||||
WaitForSingleObject(_piClient.hProcess, INFINITE);
|
||||
}
|
||||
|
||||
// This wmain exists for help in writing scratch programs while debugging.
|
||||
int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/)
|
||||
int __cdecl wmain(int argc, WCHAR* argv[])
|
||||
{
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
wprintf(argv[i]);
|
||||
wprintf(L" ");
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
std::wstring arg1 = argv[1];
|
||||
if (arg1 == L"--test")
|
||||
{
|
||||
testOutput();
|
||||
}
|
||||
else if (arg1 == L"--")
|
||||
{
|
||||
launchChild(argc - 2, &argv[2]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,357 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "Manager.h"
|
||||
|
||||
static constexpr std::wstring_view MUTEX_NAME = L"Local\\WindowsTerminalManager";
|
||||
static constexpr std::wstring_view PIPE_NAME = L"\\\\.\\pipe\\WindowsTerminalManagerPipe";
|
||||
static constexpr DWORD PIPE_BUFFER_SIZE = 4096;
|
||||
|
||||
Manager::Manager() :
|
||||
_mutex(),
|
||||
_pipe(),
|
||||
_exit(),
|
||||
_theServer(false)
|
||||
{
|
||||
// Create exit event.
|
||||
_exit.create();
|
||||
|
||||
// Try to open the mutex.
|
||||
if (!_mutex.try_open(MUTEX_NAME.data()))
|
||||
{
|
||||
// If we can't open it, create one because no one else did.
|
||||
_mutex.create(MUTEX_NAME.data());
|
||||
_theServer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it could just be opened, we're not the server.
|
||||
_theServer = false;
|
||||
}
|
||||
|
||||
// If we're the server, establish communication listener and thread
|
||||
if (_theServer)
|
||||
{
|
||||
_becomeServer();
|
||||
}
|
||||
// If we're not the server, find out who it is so we can get notified when they leave and become the server.
|
||||
else
|
||||
{
|
||||
ManagerMessageQuery query;
|
||||
query.size = sizeof(query);
|
||||
query.type = ManagerMessageTypes::GetManagerPid;
|
||||
|
||||
const auto reply = _ask(query);
|
||||
|
||||
_waitToBecomeServer = std::async(std::launch::async, [reply, this] {
|
||||
|
||||
wil::unique_handle managerProcess(OpenProcess(SYNCHRONIZE, FALSE, reply.reply.getPid.id));
|
||||
THROW_LAST_ERROR_IF_NULL(managerProcess.get());
|
||||
|
||||
WaitForSingleObject(managerProcess.get(), INFINITE);
|
||||
_becomeServer();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Manager::NotifyExit()
|
||||
{
|
||||
_exit.SetEvent();
|
||||
}
|
||||
|
||||
bool Manager::s_TrySendToManager(const HANDLE server)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get PID from remote process.
|
||||
ManagerMessageQuery query;
|
||||
query.size = sizeof(query);
|
||||
query.type = ManagerMessageTypes::GetManagerPid;
|
||||
|
||||
auto reply = _ask(query);
|
||||
const auto processId = reply.reply.getPid.id;
|
||||
|
||||
// Open for handle duping.
|
||||
wil::unique_handle otherProcess(OpenProcess(PROCESS_DUP_HANDLE, FALSE, processId));
|
||||
THROW_LAST_ERROR_IF_NULL(otherProcess.get());
|
||||
|
||||
// Send handle into that process.
|
||||
HANDLE targetHandle;
|
||||
THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(GetCurrentProcess(), server,
|
||||
otherProcess.get(), &targetHandle,
|
||||
0,
|
||||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS));
|
||||
|
||||
// Tell remote process about new handle ID
|
||||
query.size = sizeof(query);
|
||||
query.type = ManagerMessageTypes::SendConnection;
|
||||
query.query.sendConn.handle = targetHandle;
|
||||
|
||||
reply = _ask(query);
|
||||
|
||||
return reply.reply.sendConn.ok;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Manager::s_TrySendToManager(const std::wstring_view cmdline,
|
||||
const std::wstring_view workingDir)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Figure out how much data we actually need to send with the variable length strings
|
||||
size_t size = sizeof(ManagerMessageQuery) + 1;
|
||||
size += 2*(cmdline.size() + 1);
|
||||
size += 2*(workingDir.size() + 1);
|
||||
|
||||
// Make a big buffer to hold it all contiguously
|
||||
const auto buffer = std::make_unique<byte[]>(size);
|
||||
|
||||
// Make pointers to fill up each piece of data
|
||||
const auto query = reinterpret_cast<ManagerMessageQuery*>(buffer.get());
|
||||
const auto cmdPayload = reinterpret_cast<PWCHAR>(buffer.get() + sizeof(ManagerMessageQuery) + 1);
|
||||
const auto workingPayload = reinterpret_cast<PWCHAR>(buffer.get() + sizeof(ManagerMessageQuery) + 1 + (cmdline.size() + 1) * 2);
|
||||
|
||||
// Tell the remote process the command line and working directory
|
||||
query->size = gsl::narrow<DWORD>(size);
|
||||
query->type = ManagerMessageTypes::SendCmdAndWorking;
|
||||
query->query.sendCmdAndWorking.cmd = gsl::narrow<DWORD>(cmdline.size());
|
||||
query->query.sendCmdAndWorking.working = gsl::narrow<DWORD>(workingDir.size());
|
||||
|
||||
THROW_IF_FAILED(StringCchCopyW(cmdPayload, cmdline.size() + 1, cmdline.data()));
|
||||
THROW_IF_FAILED(StringCchCopyW(workingPayload, workingDir.size() + 1, workingDir.data()));
|
||||
|
||||
const auto reply = _ask(*query);
|
||||
|
||||
return reply.reply.sendConn.ok;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::_becomeServer()
|
||||
{
|
||||
// lock?
|
||||
|
||||
// test if pipe exists?
|
||||
|
||||
_theServer = true;
|
||||
|
||||
// enter loop to make server connections
|
||||
_serverWork = std::async(std::launch::async, [this] {
|
||||
_serverLoop();
|
||||
});
|
||||
}
|
||||
|
||||
void Manager::_serverLoop()
|
||||
{
|
||||
wil::unique_event newClient;
|
||||
newClient.create(wil::EventOptions::ManualReset);
|
||||
|
||||
bool keepGoing = true;
|
||||
while (keepGoing)
|
||||
{
|
||||
OVERLAPPED overlap = { 0 };
|
||||
overlap.hEvent = newClient.get();
|
||||
|
||||
wil::unique_handle pipe(CreateNamedPipeW(PIPE_NAME.data(),
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_ACCEPT_REMOTE_CLIENTS,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
PIPE_BUFFER_SIZE,
|
||||
PIPE_BUFFER_SIZE,
|
||||
0,
|
||||
nullptr)); // replace with actual security descriptor?
|
||||
|
||||
THROW_LAST_ERROR_IF(pipe.get() == INVALID_HANDLE_VALUE);
|
||||
|
||||
if (!ConnectNamedPipe(pipe.get(), &overlap))
|
||||
{
|
||||
// IO pending and Pipe Connected are OK error codes. Go into the wait.
|
||||
const auto gle = GetLastError();
|
||||
if (gle != ERROR_IO_PENDING && gle != ERROR_PIPE_CONNECTED)
|
||||
{
|
||||
THROW_LAST_ERROR();
|
||||
}
|
||||
}
|
||||
|
||||
std::array<HANDLE, 2> waitOn;
|
||||
waitOn.at(0) = _exit.get();
|
||||
waitOn.at(1) = newClient.get();
|
||||
const auto ret = WaitForMultipleObjects(gsl::narrow<DWORD>(waitOn.size()), waitOn.data(), FALSE, INFINITE);
|
||||
|
||||
if (ret == WAIT_OBJECT_0)
|
||||
{
|
||||
keepGoing = false;
|
||||
continue;
|
||||
}
|
||||
else if (ret == WAIT_OBJECT_0 + 1)
|
||||
{
|
||||
const auto loosePipeHandle = pipe.release();
|
||||
auto future = std::async(std::launch::async, [this, loosePipeHandle] {
|
||||
_perClientLoop(wil::unique_handle(loosePipeHandle));
|
||||
});
|
||||
_perClientWork.push_back(std::move(future));
|
||||
}
|
||||
else if (ret == WAIT_FAILED)
|
||||
{
|
||||
THROW_LAST_ERROR();
|
||||
}
|
||||
else
|
||||
{
|
||||
THROW_WIN32(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::_perClientLoop(wil::unique_handle pipe)
|
||||
{
|
||||
/*bool keepGoing = true;
|
||||
while (keepGoing)*/
|
||||
{
|
||||
ManagerMessageQuery query;
|
||||
DWORD bytesRead = 0;
|
||||
SetLastError(S_OK);
|
||||
const auto result = ReadFile(pipe.get(),
|
||||
&query,
|
||||
sizeof(query),
|
||||
&bytesRead,
|
||||
nullptr);
|
||||
|
||||
// False is OK if it's ERROR_MORE_DATA.
|
||||
const auto gle = GetLastError();
|
||||
THROW_LAST_ERROR_IF(!result && gle != ERROR_MORE_DATA);
|
||||
|
||||
std::unique_ptr<byte[]> buffer;
|
||||
if (gle == ERROR_MORE_DATA)
|
||||
{
|
||||
const auto remainingBytes = query.size - gsl::narrow<DWORD>(sizeof(query));
|
||||
buffer = std::make_unique<byte[]>(remainingBytes);
|
||||
|
||||
bytesRead = 0;
|
||||
THROW_IF_WIN32_BOOL_FALSE(ReadFile(pipe.get(),
|
||||
buffer.get(),
|
||||
remainingBytes,
|
||||
&bytesRead,
|
||||
nullptr));
|
||||
}
|
||||
|
||||
ManagerMessageReply reply;
|
||||
switch (query.type)
|
||||
{
|
||||
case ManagerMessageTypes::GetManagerPid:
|
||||
reply = _getPid(query);
|
||||
break;
|
||||
case ManagerMessageTypes::SendConnection:
|
||||
reply = _sendConnection(query);
|
||||
break;
|
||||
case ManagerMessageTypes::SendCmdAndWorking:
|
||||
reply = _sendCmdAndWorking(query, buffer);
|
||||
break;
|
||||
default:
|
||||
THROW_HR(E_NOTIMPL);
|
||||
}
|
||||
|
||||
DWORD bytesWritten = 0;
|
||||
THROW_IF_WIN32_BOOL_FALSE(WriteFile(pipe.get(),
|
||||
&reply,
|
||||
sizeof(reply),
|
||||
&bytesWritten,
|
||||
nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
Manager::ManagerMessageReply Manager::_ask(Manager::ManagerMessageQuery& query)
|
||||
{
|
||||
ManagerMessageReply reply;
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
THROW_IF_WIN32_BOOL_FALSE(CallNamedPipeW(PIPE_NAME.data(),
|
||||
&query,
|
||||
query.size,
|
||||
&reply,
|
||||
sizeof(reply),
|
||||
&bytesRead,
|
||||
NMPWAIT_WAIT_FOREVER));
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
Manager::ManagerMessageReply Manager::_getPid(ManagerMessageQuery /*query*/)
|
||||
{
|
||||
ManagerMessageReply reply;
|
||||
|
||||
reply.type = ManagerMessageTypes::GetManagerPid;
|
||||
reply.reply.getPid.id = GetCurrentProcessId();
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static std::vector<std::function<void(HANDLE)>> s_onHandleConnection;
|
||||
|
||||
void Manager::s_RegisterOnConnection(std::function<void(HANDLE)> func)
|
||||
{
|
||||
s_onHandleConnection.push_back(func);
|
||||
}
|
||||
|
||||
Manager::ManagerMessageReply Manager::_sendConnection(ManagerMessageQuery query)
|
||||
{
|
||||
const auto serverHandle = query.query.sendConn.handle;
|
||||
|
||||
// create new conhost connection...
|
||||
for (const auto& func : s_onHandleConnection)
|
||||
{
|
||||
func(serverHandle);
|
||||
}
|
||||
|
||||
ManagerMessageReply reply;
|
||||
|
||||
reply.type = ManagerMessageTypes::SendConnection;
|
||||
reply.reply.sendConn.ok = true;
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
static std::vector<std::function<void(std::wstring_view, std::wstring_view)>> s_onLaunchConnection;
|
||||
|
||||
void Manager::s_RegisterOnConnection(std::function<void(std::wstring_view, std::wstring_view)> func)
|
||||
{
|
||||
s_onLaunchConnection.push_back(func);
|
||||
}
|
||||
|
||||
Manager::ManagerMessageReply Manager::_sendCmdAndWorking(ManagerMessageQuery query, std::unique_ptr<BYTE[]>& buffer)
|
||||
{
|
||||
const auto cmd = query.query.sendCmdAndWorking.cmd;
|
||||
const auto work = query.query.sendCmdAndWorking.working;
|
||||
|
||||
std::wstring_view cmdline(reinterpret_cast<wchar_t*>(buffer.get() + 1), cmd);
|
||||
std::wstring_view workingDir(reinterpret_cast<wchar_t*>(buffer.get() + 1 + (cmd + 1) * 2), work);
|
||||
|
||||
// create new conhost connection...
|
||||
for (const auto& func : s_onLaunchConnection)
|
||||
{
|
||||
func(cmdline, workingDir);
|
||||
}
|
||||
|
||||
ManagerMessageReply reply;
|
||||
|
||||
reply.type = ManagerMessageTypes::SendCmdAndWorking;
|
||||
reply.reply.sendCmdAndWorking.ok = true;
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
class Manager final
|
||||
{
|
||||
public:
|
||||
Manager();
|
||||
virtual ~Manager();
|
||||
|
||||
void NotifyExit();
|
||||
|
||||
static void s_RegisterOnConnection(std::function<void(HANDLE)> func);
|
||||
static void s_RegisterOnConnection(std::function<void(std::wstring_view, std::wstring_view)> func);
|
||||
static bool s_TrySendToManager(const HANDLE server);
|
||||
static bool s_TrySendToManager(const std::wstring_view cmdline,
|
||||
const std::wstring_view workingDir);
|
||||
|
||||
Manager(const Manager&) = delete;
|
||||
Manager(Manager&&) = delete;
|
||||
Manager& operator=(const Manager&) = delete;
|
||||
Manager& operator=(Manager&&) = delete;
|
||||
private:
|
||||
wil::unique_mutex _mutex;
|
||||
wil::unique_event _exit;
|
||||
wil::unique_handle _pipe;
|
||||
bool _theServer;
|
||||
std::future<void> _waitToBecomeServer;
|
||||
std::future<void> _serverWork;
|
||||
std::vector<std::future<void>> _perClientWork;
|
||||
|
||||
enum class ManagerMessageTypes
|
||||
{
|
||||
GetManagerPid,
|
||||
SendConnection,
|
||||
SendCmdAndWorking
|
||||
};
|
||||
|
||||
struct ManagerMessageQuery
|
||||
{
|
||||
DWORD size;
|
||||
ManagerMessageTypes type;
|
||||
union
|
||||
{
|
||||
struct SendConnection
|
||||
{
|
||||
HANDLE handle;
|
||||
} sendConn;
|
||||
struct SendCmdAndWorking
|
||||
{
|
||||
DWORD cmd;
|
||||
DWORD working;
|
||||
} sendCmdAndWorking;
|
||||
} query;
|
||||
};
|
||||
|
||||
struct ManagerMessageReply
|
||||
{
|
||||
ManagerMessageTypes type;
|
||||
union
|
||||
{
|
||||
struct GetManagerPid
|
||||
{
|
||||
DWORD id;
|
||||
} getPid;
|
||||
struct SendConnection
|
||||
{
|
||||
bool ok;
|
||||
} sendConn;
|
||||
struct SendCmdAndWorking
|
||||
{
|
||||
bool ok;
|
||||
} sendCmdAndWorking;
|
||||
} reply;
|
||||
};
|
||||
|
||||
static ManagerMessageReply _ask(ManagerMessageQuery& query);
|
||||
static ManagerMessageReply _getPid(ManagerMessageQuery query);
|
||||
static ManagerMessageReply _sendConnection(ManagerMessageQuery query);
|
||||
static ManagerMessageReply _sendCmdAndWorking(ManagerMessageQuery query, std::unique_ptr<byte[]>& buffer);
|
||||
|
||||
void _becomeServer();
|
||||
void _serverLoop();
|
||||
void _perClientLoop(wil::unique_handle pipe);
|
||||
};
|
||||
98
src/types/UTF8OutPipeReader.cpp
Normal file
98
src/types/UTF8OutPipeReader.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "inc/Utf8OutPipeReader.hpp"
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
UTF8OutPipeReader::UTF8OutPipeReader(HANDLE outPipe) :
|
||||
_outPipe{ outPipe }
|
||||
{
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// Populates a string_view with *complete* UTF-8 codepoints read from the pipe.
|
||||
// If it receives an incomplete codepoint, it will cache it until it can be completed.
|
||||
// Note: This method trusts that the other end will, in fact, send complete codepoints.
|
||||
// Arguments:
|
||||
// - strView: on return, populated with successfully-read codepoints.
|
||||
// Return Value:
|
||||
// An HRESULT indicating whether the read was successful. For the purposes of this
|
||||
// method, a closed pipe is considered a successful (but false!) read. All other errors
|
||||
// are translated into an appropriate status code.
|
||||
// S_OK for a successful read
|
||||
// S_FALSE for a read on a closed pipe
|
||||
// E_* (anything) for a failed read
|
||||
[[nodiscard]] HRESULT UTF8OutPipeReader::Read(_Out_ std::string_view& strView)
|
||||
{
|
||||
DWORD dwRead{};
|
||||
bool fSuccess{};
|
||||
|
||||
// in case of early escaping
|
||||
*_buffer = 0;
|
||||
strView = std::string_view{ reinterpret_cast<char*>(_buffer), 0 };
|
||||
|
||||
// copy UTF-8 code units that were remaining from the previously read chunk (if any)
|
||||
if (_dwPartialsLen != 0)
|
||||
{
|
||||
std::move(_utf8Partials, _utf8Partials + _dwPartialsLen, _buffer);
|
||||
}
|
||||
|
||||
// try to read data
|
||||
fSuccess = !!ReadFile(_outPipe, &_buffer[_dwPartialsLen], std::extent<decltype(_buffer)>::value - _dwPartialsLen, &dwRead, nullptr);
|
||||
|
||||
dwRead += _dwPartialsLen;
|
||||
_dwPartialsLen = 0;
|
||||
|
||||
if (!fSuccess) // reading failed (we must check this first, because dwRead will also be 0.)
|
||||
{
|
||||
auto lastError = GetLastError();
|
||||
if (lastError == ERROR_BROKEN_PIPE)
|
||||
{
|
||||
// This is a successful, but detectable, exit.
|
||||
// There is a chance that we put some partials into the buffer. Since
|
||||
// the pipe has closed, they're just invalid now. They're not worth
|
||||
// reporting.
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
return HRESULT_FROM_WIN32(lastError);
|
||||
}
|
||||
|
||||
if (dwRead == 0) // quit if no data has been read and no cached data was left over
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const BYTE* const endPtr{ _buffer + dwRead };
|
||||
const BYTE* backIter{ endPtr - 1 };
|
||||
// If the last byte in the buffer was a byte belonging to a UTF-8 multi-byte character
|
||||
if ((*backIter & _Utf8BitMasks::MaskAsciiByte) > _Utf8BitMasks::IsAsciiByte)
|
||||
{
|
||||
// Check only up to 3 last bytes, if no Lead Byte was found then the byte before must be the Lead Byte and no partials are in the buffer
|
||||
for (DWORD dwSequenceLen{ 1UL }, stop{ dwRead < 4UL ? dwRead : 4UL }; dwSequenceLen < stop; ++dwSequenceLen, --backIter)
|
||||
{
|
||||
// If Lead Byte found
|
||||
if ((*backIter & _Utf8BitMasks::MaskContinuationByte) > _Utf8BitMasks::IsContinuationByte)
|
||||
{
|
||||
// If the Lead Byte indicates that the last bytes in the buffer is a partial UTF-8 code point then cache them:
|
||||
// Use the bitmask at index `dwSequenceLen`. Compare the result with the operand having the same index. If they
|
||||
// are not equal then the sequence has to be cached because it is a partial code point. Otherwise the
|
||||
// sequence is a complete UTF-8 code point and the whole buffer is ready for the conversion to hstring.
|
||||
if ((*backIter & _cmpMasks[dwSequenceLen]) != _cmpOperands[dwSequenceLen])
|
||||
{
|
||||
std::move(backIter, endPtr, _utf8Partials);
|
||||
dwRead -= dwSequenceLen;
|
||||
_dwPartialsLen = dwSequenceLen;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// give back a view of the part of the buffer that contains complete code points only
|
||||
strView = std::string_view{ reinterpret_cast<char*>(_buffer), dwRead };
|
||||
return S_OK;
|
||||
}
|
||||
68
src/types/inc/UTF8OutPipeReader.hpp
Normal file
68
src/types/inc/UTF8OutPipeReader.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- UTF8OutPipeReader.hpp
|
||||
|
||||
Abstract:
|
||||
- This reads a UTF-8 stream and gives back a buffer that contains complete code points only
|
||||
- Partial UTF-8 code points at the end of the buffer read are cached and prepended to the next chunk read
|
||||
|
||||
Author(s):
|
||||
- Steffen Illhardt (german-one) 12-July-2019
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <wil\common.h>
|
||||
#include <wil\resource.h>
|
||||
#include <string_view>
|
||||
|
||||
class UTF8OutPipeReader final
|
||||
{
|
||||
public:
|
||||
UTF8OutPipeReader(HANDLE outPipe);
|
||||
[[nodiscard]] HRESULT Read(_Out_ std::string_view& strView);
|
||||
|
||||
private:
|
||||
enum _Utf8BitMasks : BYTE
|
||||
{
|
||||
IsAsciiByte = 0b0'0000000, // Any byte representing an ASCII character has the MSB set to 0
|
||||
MaskAsciiByte = 0b1'0000000, // Bit mask to be used in a bitwise AND operation to find out whether or not a byte match the IsAsciiByte pattern
|
||||
IsContinuationByte = 0b10'000000, // Continuation bytes of any UTF-8 non-ASCII character have the MSB set to 1 and the adjacent bit set to 0
|
||||
MaskContinuationByte = 0b11'000000, // Bit mask to be used in a bitwise AND operation to find out whether or not a byte match the IsContinuationByte pattern
|
||||
IsLeadByteTwoByteSequence = 0b110'00000, // A lead byte that indicates a UTF-8 non-ASCII character consisting of two bytes has the two highest bits set to 1 and the adjacent bit set to 0
|
||||
MaskLeadByteTwoByteSequence = 0b111'00000, // Bit mask to be used in a bitwise AND operation to find out whether or not a lead byte match the IsLeadByteTwoByteSequence pattern
|
||||
IsLeadByteThreeByteSequence = 0b1110'0000, // A lead byte that indicates a UTF-8 non-ASCII character consisting of three bytes has the three highest bits set to 1 and the adjacent bit set to 0
|
||||
MaskLeadByteThreeByteSequence = 0b1111'0000, // Bit mask to be used in a bitwise AND operation to find out whether or not a lead byte match the IsLeadByteThreeByteSequence pattern
|
||||
IsLeadByteFourByteSequence = 0b11110'000, // A lead byte that indicates a UTF-8 non-ASCII character consisting of four bytes has the four highest bits set to 1 and the adjacent bit set to 0
|
||||
MaskLeadByteFourByteSequence = 0b11111'000 // Bit mask to be used in a bitwise AND operation to find out whether or not a lead byte match the IsLeadByteFourByteSequence pattern
|
||||
};
|
||||
|
||||
// array of bitmasks
|
||||
constexpr const static BYTE _cmpMasks[]{
|
||||
0, // unused
|
||||
_Utf8BitMasks::MaskContinuationByte,
|
||||
_Utf8BitMasks::MaskLeadByteTwoByteSequence,
|
||||
_Utf8BitMasks::MaskLeadByteThreeByteSequence,
|
||||
};
|
||||
|
||||
// array of values for the comparisons
|
||||
constexpr const static BYTE _cmpOperands[]{
|
||||
0, // unused
|
||||
_Utf8BitMasks::IsAsciiByte, // intentionally conflicts with MaskContinuationByte
|
||||
_Utf8BitMasks::IsLeadByteTwoByteSequence,
|
||||
_Utf8BitMasks::IsLeadByteThreeByteSequence,
|
||||
};
|
||||
|
||||
HANDLE _outPipe; // non-owning reference to a pipe.
|
||||
BYTE _buffer[4096]{ 0 }; // buffer for the chunk read
|
||||
BYTE _utf8Partials[4]{ 0 }; // buffer for code units of a partial UTF-8 code point that have to be cached
|
||||
DWORD _dwPartialsLen{}; // number of cached UTF-8 code units
|
||||
};
|
||||
@@ -5,7 +5,6 @@
|
||||
<ClCompile Include="..\CodepointWidthDetector.cpp" />
|
||||
<ClCompile Include="..\convert.cpp" />
|
||||
<ClCompile Include="..\GlyphWidth.cpp" />
|
||||
<ClCompile Include="..\Manager.cpp" />
|
||||
<ClCompile Include="..\MouseEvent.cpp" />
|
||||
<ClCompile Include="..\FocusEvent.cpp" />
|
||||
<ClCompile Include="..\IInputEvent.cpp" />
|
||||
@@ -13,6 +12,7 @@
|
||||
<ClCompile Include="..\MenuEvent.cpp" />
|
||||
<ClCompile Include="..\ModifierKeyState.cpp" />
|
||||
<ClCompile Include="..\Utf16Parser.cpp" />
|
||||
<ClCompile Include="..\UTF8OutPipeReader.cpp" />
|
||||
<ClCompile Include="..\Viewport.cpp" />
|
||||
<ClCompile Include="..\WindowBufferSizeEvent.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
@@ -25,9 +25,9 @@
|
||||
<ClInclude Include="..\inc\convert.hpp" />
|
||||
<ClInclude Include="..\inc\GlyphWidth.hpp" />
|
||||
<ClInclude Include="..\inc\IInputEvent.hpp" />
|
||||
<ClInclude Include="..\inc\UTF8OutPipeReader.hpp" />
|
||||
<ClInclude Include="..\inc\Viewport.hpp" />
|
||||
<ClInclude Include="..\inc\Utf16Parser.hpp" />
|
||||
<ClInclude Include="..\Manager.h" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
<ClInclude Include="..\utils.hpp" />
|
||||
</ItemGroup>
|
||||
@@ -41,4 +41,4 @@
|
||||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||
<Import Project="$(SolutionDir)src\common.build.lib.props" />
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<ClCompile Include="..\utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Manager.cpp">
|
||||
<ClCompile Include="..\UTF8OutPipeReader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
@@ -86,7 +86,7 @@
|
||||
<ClInclude Include="..\utils.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Manager.h">
|
||||
<ClInclude Include="..\inc\UTF8OutPipeReader.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -33,7 +33,6 @@ SOURCES= \
|
||||
..\FocusEvent.cpp \
|
||||
..\GlyphWidth.cpp \
|
||||
..\KeyEvent.cpp \
|
||||
..\Manager.cpp \
|
||||
..\MenuEvent.cpp \
|
||||
..\ModifierKeyState.cpp \
|
||||
..\MouseEvent.cpp \
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(SolutionDir)src\common.build.pre.props" />
|
||||
<ItemGroup>
|
||||
<ClCompile Include="UTF8OutPipeReaderTests.cpp" />
|
||||
<ClCompile Include="UtilsTests.cpp" />
|
||||
<ClCompile Include="UuidTests.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
|
||||
155
src/types/ut_types/UTF8OutPipeReaderTests.cpp
Normal file
155
src/types/ut_types/UTF8OutPipeReaderTests.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "WexTestClass.h"
|
||||
#include "..\..\inc\consoletaeftemplates.hpp"
|
||||
|
||||
#include "..\inc\UTF8OutPipeReader.hpp"
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
||||
using namespace WEX::Common;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
|
||||
class UTF8OutPipeReaderTests
|
||||
{
|
||||
TEST_CLASS(UTF8OutPipeReaderTests);
|
||||
|
||||
TEST_METHOD(TestUtf8MergePartials)
|
||||
{
|
||||
// The test uses the character 'GOTHIC LETTER HWAIR' (U+10348) as an example
|
||||
// Its UTF-8 representation consists of four bytes:
|
||||
// 1 2 3 4
|
||||
// 0xF0 0x90 0x8D 0x88
|
||||
//
|
||||
// For the test a std::string is filled with 4104 '.' characters to make sure it exceeds the
|
||||
// buffer size of 4096 bytes in UTF8OutPipeReader.
|
||||
//
|
||||
// This figure shows how the string is getting changed for the 7 sub-tests. The digits 1 to 4
|
||||
// represent the four bytes of the 'Hwair' letter. The vertical bar represents the buffer boundary.
|
||||
// Test 1: [more points] . . S 1 2 3 4 T|U V W X Y Z . .
|
||||
// Test 2: [more points] . . S T 1 2 3 4|U V W X Y Z . .
|
||||
// Test 3: [more points] . . S T U 1 2 3|4 V W X Y Z . .
|
||||
// Test 4: [more points] . . S T U V 1 2|3 4 W X Y Z . .
|
||||
// Test 5: [more points] . . S T U V W 1|2 3 4 X Y Z . .
|
||||
// Test 6: [more points] . . S T U V W X|1 2 3 4 Y Z . .
|
||||
// Test 7: [more points] . . S T U V W X|Y 1 2 3 4 Z . .
|
||||
//
|
||||
// Tests 1, 6, and 7 prove proper ASCII handling.
|
||||
// Test 2 leaves all four bytes of 'Hwair' in the first chunk.
|
||||
// Test 3, 4, and 5 move the partials from the end of the first chunk to the begin of the
|
||||
// second chunk.
|
||||
//
|
||||
// At the beginning of a test the whole string is converted into a winrt::hstring for reference.
|
||||
// During the test a second hstring is concatenated out of the chunks that we get from
|
||||
// UTF8OutPipeReader::Read. Each chunk is separately converted to hstring in order to make
|
||||
// sure it would be corrupted if we get UTF-8 partials.
|
||||
// The test is positive if both hstrings are equal.
|
||||
|
||||
const size_t bufferSize{ 4096 }; // NOTE: This has to match the buffer size in UTF8OutPipeReader!
|
||||
std::string utf8TestString(bufferSize + 8, '.'); // create a test string with the required size
|
||||
|
||||
// Test 1:
|
||||
// ||
|
||||
utf8TestString.replace(bufferSize - 6, 12, "S\xF0\x90\x8D\x88TUVWXYZ");
|
||||
VERIFY_SUCCEEDED(RunTest(utf8TestString));
|
||||
|
||||
// Test 2:
|
||||
// | |
|
||||
utf8TestString.replace(bufferSize - 6, 12, "ST\xF0\x90\x8D\x88UVWXYZ");
|
||||
VERIFY_SUCCEEDED(RunTest(utf8TestString));
|
||||
|
||||
// Test 3:
|
||||
// | |
|
||||
utf8TestString.replace(bufferSize - 6, 12, "STU\xF0\x90\x8D\x88VWXYZ");
|
||||
VERIFY_SUCCEEDED(RunTest(utf8TestString));
|
||||
|
||||
// Test 4:
|
||||
// | |
|
||||
utf8TestString.replace(bufferSize - 6, 12, "STUV\xF0\x90\x8D\x88WXYZ");
|
||||
VERIFY_SUCCEEDED(RunTest(utf8TestString));
|
||||
|
||||
// Test 5:
|
||||
// | |
|
||||
utf8TestString.replace(bufferSize - 6, 12, "STUVW\xF0\x90\x8D\x88XYZ");
|
||||
VERIFY_SUCCEEDED(RunTest(utf8TestString));
|
||||
|
||||
// Test 6:
|
||||
// | |
|
||||
utf8TestString.replace(bufferSize - 6, 12, "STUVWX\xF0\x90\x8D\x88YZ");
|
||||
VERIFY_SUCCEEDED(RunTest(utf8TestString));
|
||||
|
||||
// Test 7:
|
||||
// ||
|
||||
utf8TestString.replace(bufferSize - 6, 12, "STUVWXY\xF0\x90\x8D\x88Z");
|
||||
VERIFY_SUCCEEDED(RunTest(utf8TestString));
|
||||
}
|
||||
|
||||
struct ThreadData
|
||||
{
|
||||
wil::unique_hfile& inPipe;
|
||||
std::string& utf8TestString;
|
||||
};
|
||||
|
||||
// Thread function which writes the UTF-8 data to the pipe.
|
||||
static DWORD WINAPI WritePipeThread(LPVOID threadArg)
|
||||
{
|
||||
ThreadData* pThreadData{ reinterpret_cast<ThreadData*>(threadArg) };
|
||||
DWORD length{};
|
||||
|
||||
WriteFile(pThreadData->inPipe.get(), pThreadData->utf8TestString.c_str(), static_cast<DWORD>(pThreadData->utf8TestString.size()), &length, nullptr);
|
||||
pThreadData->inPipe.reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Performs the sub-tests.
|
||||
HRESULT RunTest(std::string& utf8TestString)
|
||||
{
|
||||
std::string_view strView{}; // contains the chunk that we get from UTF8OutPipeReader::Read
|
||||
const winrt::hstring utf16Expected{ winrt::to_hstring(utf8TestString) }; // contains the whole string converted to UTF-16
|
||||
winrt::hstring utf16Actual{}; // will be concatenated from the converted chunks
|
||||
|
||||
wil::unique_hfile outPipe{};
|
||||
wil::unique_hfile inPipe{};
|
||||
|
||||
SECURITY_ATTRIBUTES sa{ sizeof(SECURITY_ATTRIBUTES) };
|
||||
CreatePipe(&outPipe, &inPipe, &sa, 0); // create the pipe handles
|
||||
|
||||
UTF8OutPipeReader reader{ outPipe.get() };
|
||||
|
||||
ThreadData data{ inPipe, utf8TestString };
|
||||
|
||||
wil::unique_handle threadHandle{ CreateThread(nullptr, 0, WritePipeThread, &data, 0, nullptr) }; // create a thread that writes to the pipe
|
||||
RETURN_HR_IF_NULL(E_FAIL, threadHandle.get());
|
||||
|
||||
// process the chunks that we get from UTF8OutPipeReader::Read
|
||||
while (true)
|
||||
{
|
||||
// get a chunk of UTF-8 data
|
||||
THROW_IF_FAILED(reader.Read(strView));
|
||||
|
||||
if (strView.empty())
|
||||
{
|
||||
// this is okay, no data left in the pipe
|
||||
break;
|
||||
}
|
||||
|
||||
// convert the chunk to hstring and append it to the resulting hstring
|
||||
utf16Actual = utf16Actual + winrt::to_hstring(strView);
|
||||
}
|
||||
|
||||
WaitForSingleObject(threadHandle.get(), 2000);
|
||||
|
||||
// the test passed if both hstrings are equal
|
||||
if (utf16Actual == utf16Expected)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
};
|
||||
@@ -187,7 +187,7 @@ function Invoke-OpenConsoleTests()
|
||||
}
|
||||
$OpenConsolePath = "$env:OpenConsoleroot\bin\$OpenConsolePlatform\$Configuration\OpenConsole.exe"
|
||||
$RunTePath = "$env:OpenConsoleRoot\tools\runte.cmd"
|
||||
$TaefExePath = "$env:OpenConsoleRoot\packages\Taef.Redist.Wlk.10.30.180808002\build\binaries\$Platform\te.exe"
|
||||
$TaefExePath = "$env:OpenConsoleRoot\packages\Taef.Redist.Wlk.10.38.190610001-uapadmin\build\Binaries\$Platform\te.exe"
|
||||
$BinDir = "$env:OpenConsoleRoot\bin\$OpenConsolePlatform\$Configuration"
|
||||
[xml]$TestConfig = Get-Content "$env:OpenConsoleRoot\tools\tests.xml"
|
||||
|
||||
|
||||
5
tools/bzcon.cmd
Normal file
5
tools/bzcon.cmd
Normal file
@@ -0,0 +1,5 @@
|
||||
@echo off
|
||||
|
||||
"%msbuild%" Openconsole.sln /t:Conhost\Host_EXE /m /p:Configuration=Debug /p:Platform=%ARCH%
|
||||
|
||||
:eof
|
||||
@@ -104,7 +104,7 @@ shift
|
||||
goto :ARGS_LOOP
|
||||
|
||||
:POST_ARGS_LOOP
|
||||
set TAEF=%OPENCON%\packages\Taef.Redist.Wlk.10.30.180808002\build\binaries\%ARCH%\TE.exe
|
||||
set TAEF=%OPENCON%\packages\Taef.Redist.Wlk.10.38.190610001-uapadmin\build\Binaries\%ARCH%\TE.exe
|
||||
rem Set this envvar so setup won't repeat itself
|
||||
set OpenConBuild=true
|
||||
|
||||
|
||||
24
tools/scratch.cmd
Normal file
24
tools/scratch.cmd
Normal file
@@ -0,0 +1,24 @@
|
||||
@echo off
|
||||
|
||||
rem openvt - launch the vtterm binary
|
||||
rem Runs the VtPipeTerm.exe binary generated by the build in the debug directory.
|
||||
rem Passes any args along.
|
||||
|
||||
setlocal
|
||||
set _last_build=%OPENCON%\bin\%ARCH%\%_LAST_BUILD_CONF%
|
||||
|
||||
if not exist %_last_build%\scratch.exe (
|
||||
echo Could not locate the scratch.exe in %_last_build%. Double check that it has been built and try again.
|
||||
goto :eof
|
||||
)
|
||||
|
||||
set _r=%random%
|
||||
set copy_dir=OpenConsole\%_r%
|
||||
rem Generate a unique name, so that we can debug multiple revisions of the binary at the same time if needed.
|
||||
|
||||
(xcopy /Y %_last_build%\OpenConsole.exe %TEMP%\%copy_dir%\conhost.exe*) > nul
|
||||
(xcopy /Y %_last_build%\console.dll %TEMP%\%copy_dir%\console.dll*) > nul
|
||||
(xcopy /Y %_last_build%\scratch.exe %TEMP%\%copy_dir%\scratch.exe*) > nul
|
||||
|
||||
echo Launching %TEMP%\%copy_dir%\scratch.exe...
|
||||
%TEMP%\%copy_dir%\scratch.exe %*
|
||||
Reference in New Issue
Block a user