mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-18 20:21:05 +00:00
Compare commits
108 Commits
dev/cazamo
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f978cd0b9 | ||
|
|
06c7a3abcb | ||
|
|
1122838862 | ||
|
|
e745d6281e | ||
|
|
52bf57e67c | ||
|
|
f3d70f2068 | ||
|
|
f86d02e66e | ||
|
|
39a5b270e8 | ||
|
|
8282d3a1c3 | ||
|
|
8318bf9a6a | ||
|
|
aec7392e6b | ||
|
|
dd744a5e8f | ||
|
|
e17e4f5c3d | ||
|
|
6e3be8f42a | ||
|
|
61292d8cf6 | ||
|
|
b25dc74a1d | ||
|
|
2366427a14 | ||
|
|
3fad41c0bb | ||
|
|
9ac7ce2082 | ||
|
|
5abb574973 | ||
|
|
e49d180e13 | ||
|
|
f4de1e47b3 | ||
|
|
c8007ce9e2 | ||
|
|
797abba352 | ||
|
|
cc0bc484ce | ||
|
|
0a76283911 | ||
|
|
1d090d6036 | ||
|
|
47b4ddcc1e | ||
|
|
d052617e87 | ||
|
|
c384ef657e | ||
|
|
ceb3c05c1b | ||
|
|
c18c240627 | ||
|
|
32e075956d | ||
|
|
62814f80a7 | ||
|
|
cbf5d6c5e4 | ||
|
|
5cc663c830 | ||
|
|
68c54bf65f | ||
|
|
cc215ce59a | ||
|
|
3dadd8e2be | ||
|
|
2bc4f64eac | ||
|
|
d44bb4e60e | ||
|
|
f6a821f026 | ||
|
|
a18bca8689 | ||
|
|
1821c00722 | ||
|
|
6c46b172a1 | ||
|
|
a02e8aef3c | ||
|
|
3831d47bc4 | ||
|
|
d87b49067a | ||
|
|
988dad37e5 | ||
|
|
5235d2d43b | ||
|
|
ccf87cd98c | ||
|
|
4c1815bd4b | ||
|
|
a5541ec285 | ||
|
|
2093dc4a4d | ||
|
|
4d8ccbfe54 | ||
|
|
2f6530ccf2 | ||
|
|
47e6a1a7d0 | ||
|
|
36879c1e4d | ||
|
|
0cd97a920c | ||
|
|
7a83ee2710 | ||
|
|
e37fd5e546 | ||
|
|
59166faa27 | ||
|
|
19f8b9c3ca | ||
|
|
17e68a09a8 | ||
|
|
0980a0d50f | ||
|
|
1d33429673 | ||
|
|
ef8ba20bee | ||
|
|
a0e5085b49 | ||
|
|
d57fb84557 | ||
|
|
be2b77653f | ||
|
|
c18e0f5008 | ||
|
|
a89746a869 | ||
|
|
f339705ce7 | ||
|
|
f152573058 | ||
|
|
91b454ac95 | ||
|
|
6409ab91fa | ||
|
|
a0527a1dbe | ||
|
|
f03cacfa5b | ||
|
|
cdecfcd67f | ||
|
|
d6da6ba353 | ||
|
|
96f4a9daef | ||
|
|
1374396f10 | ||
|
|
192d6debba | ||
|
|
a50731119a | ||
|
|
305e3df8fa | ||
|
|
83c6bce73d | ||
|
|
59239e3b07 | ||
|
|
79a18f0825 | ||
|
|
d3b9a780d3 | ||
|
|
9b9b0738c8 | ||
|
|
f3e30d07fa | ||
|
|
ee3259847a | ||
|
|
ab5a8d701d | ||
|
|
6a37818c07 | ||
|
|
4fc283f8b6 | ||
|
|
51e1ae3e8a | ||
|
|
8c057a04a8 | ||
|
|
8c00dd7d55 | ||
|
|
848e353b9c | ||
|
|
e3b7a44b13 | ||
|
|
0d9a357373 | ||
|
|
85c485e94f | ||
|
|
1b79cc87c3 | ||
|
|
b7fc0f2d44 | ||
|
|
2770228e09 | ||
|
|
4f0b57ec8e | ||
|
|
c8f00df170 | ||
|
|
c90de69250 |
@@ -397,6 +397,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_Control", "src\ca
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsTerminal.UIA.Tests", "src\cascadia\WindowsTerminal_UIATests\WindowsTerminal.UIA.Tests.csproj", "{F19DACD5-0C6E-40DC-B6E4-767A3200542C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api-ms-win-core-synch-l1-2-0", "src\api-ms-win-core-synch-l1-2-0\api-ms-win-core-synch-l1-2-0.vcxproj", "{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
AuditMode|Any CPU = AuditMode|Any CPU
|
||||
@@ -3292,6 +3294,50 @@ Global
|
||||
{F19DACD5-0C6E-40DC-B6E4-767A3200542C}.Release|x64.Build.0 = Release|x64
|
||||
{F19DACD5-0C6E-40DC-B6E4-767A3200542C}.Release|x86.ActiveCfg = Release|Win32
|
||||
{F19DACD5-0C6E-40DC-B6E4-767A3200542C}.Release|x86.Build.0 = Release|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|x64.ActiveCfg = AuditMode|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|x64.Build.0 = AuditMode|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|x86.ActiveCfg = AuditMode|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.AuditMode|x86.Build.0 = AuditMode|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|DotNet_x86Test.Build.0 = Debug|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|x64.Build.0 = Debug|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Debug|x86.Build.0 = Debug|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|x64.Build.0 = Fuzzing|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Fuzzing|x86.Build.0 = Fuzzing|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|DotNet_x86Test.Build.0 = Release|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x64.ActiveCfg = Release|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x64.Build.0 = Release|x64
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.ActiveCfg = Release|Win32
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -3390,6 +3436,7 @@ Global
|
||||
{05D9052F-D78F-478F-968A-2DE38A6DB996} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
|
||||
{C323DAEE-B307-4C7B-ACE5-7293CBEFCB5B} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
|
||||
{F19DACD5-0C6E-40DC-B6E4-767A3200542C} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
|
||||
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}
|
||||
|
||||
@@ -3,16 +3,16 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31205.134
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Package", "ScratchIslandApp\Package\Package.wapproj", "{CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}"
|
||||
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Package", "scratch\ScratchIslandApp\Package\Package.wapproj", "{CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleAppLib", "ScratchIslandApp\SampleApp\SampleAppLib.vcxproj", "{A4394404-37F7-41C1-802B-49788D3720E3}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleAppLib", "scratch\ScratchIslandApp\SampleApp\SampleAppLib.vcxproj", "{A4394404-37F7-41C1-802B-49788D3720E3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleApp", "ScratchIslandApp\SampleApp\dll\SampleApp.vcxproj", "{26C51792-41A3-4FE0-AB5E-8B69D557BF91}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleApp", "scratch\ScratchIslandApp\SampleApp\dll\SampleApp.vcxproj", "{26C51792-41A3-4FE0-AB5E-8B69D557BF91}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A4394404-37F7-41C1-802B-49788D3720E3} = {A4394404-37F7-41C1-802B-49788D3720E3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowExe", "ScratchIslandApp\WindowExe\WindowExe.vcxproj", "{B4427499-9FDE-4208-B456-5BC580637633}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowExe", "scratch\ScratchIslandApp\WindowExe\WindowExe.vcxproj", "{B4427499-9FDE-4208-B456-5BC580637633}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{26C51792-41A3-4FE0-AB5E-8B69D557BF91} = {26C51792-41A3-4FE0-AB5E-8B69D557BF91}
|
||||
EndProjectSection
|
||||
@@ -29,9 +29,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common Props", "Common Prop
|
||||
src\wap-common.build.pre.props = src\wap-common.build.pre.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\src\dep\fmt\fmt.vcxproj", "{6BAE5851-50D5-4934-8D5E-30361A8A40F3}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "src\dep\fmt\fmt.vcxproj", "{6BAE5851-50D5-4934-8D5E-30361A8A40F3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types", "..\src\types\lib\types.vcxproj", "{18D09A24-8240-42D6-8CB6-236EEE820263}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types", "src\types\lib\types.vcxproj", "{18D09A24-8240-42D6-8CB6-236EEE820263}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}"
|
||||
EndProject
|
||||
@@ -21,7 +21,7 @@ Write-Host "Checking test results..."
|
||||
$queryUri = GetQueryTestRunsUri -CollectionUri $CollectionUri -TeamProject $TeamProject -BuildUri $BuildUri -IncludeRunDetails
|
||||
Write-Host "queryUri = $queryUri"
|
||||
|
||||
$testRuns = Invoke-RestMethod -Uri $queryUri -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
$testRuns = Invoke-RestMethodWithRetries $queryUri -Headers $azureDevOpsRestApiHeaders
|
||||
[System.Collections.Generic.List[string]]$failingTests = @()
|
||||
[System.Collections.Generic.List[string]]$unreliableTests = @()
|
||||
[System.Collections.Generic.List[string]]$unexpectedResultTest = @()
|
||||
@@ -50,7 +50,7 @@ foreach ($testRun in ($testRuns.value | Sort-Object -Property "completedDate" -D
|
||||
$totalTestsExecutedCount += $testRun.totalTests
|
||||
|
||||
$testRunResultsUri = "$($testRun.url)/results?api-version=5.0"
|
||||
$testResults = Invoke-RestMethod -Uri "$($testRun.url)/results?api-version=5.0" -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
$testResults = Invoke-RestMethodWithRetries "$($testRun.url)/results?api-version=5.0" -Headers $azureDevOpsRestApiHeaders
|
||||
|
||||
foreach ($testResult in $testResults.value)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ $payloadDir = "HelixPayload\$Configuration\$Platform"
|
||||
|
||||
$repoDirectory = Join-Path (Split-Path -Parent $script:MyInvocation.MyCommand.Path) "..\..\"
|
||||
$nugetPackagesDir = Join-Path (Split-Path -Parent $script:MyInvocation.MyCommand.Path) "packages"
|
||||
|
||||
|
||||
# Create the payload directory. Remove it if it already exists.
|
||||
If(test-path $payloadDir)
|
||||
{
|
||||
@@ -19,8 +19,8 @@ New-Item -ItemType Directory -Force -Path $payloadDir
|
||||
|
||||
# Copy files from nuget packages
|
||||
Copy-Item "$nugetPackagesDir\microsoft.windows.apps.test.1.0.181203002\lib\netcoreapp2.1\*.dll" $payloadDir
|
||||
Copy-Item "$nugetPackagesDir\Microsoft.Taef.10.58.210305002\build\Binaries\$Platform\*" $payloadDir
|
||||
Copy-Item "$nugetPackagesDir\Microsoft.Taef.10.58.210305002\build\Binaries\$Platform\NetFx4.5\*" $payloadDir
|
||||
Copy-Item "$nugetPackagesDir\Microsoft.Taef.10.60.210621002\build\Binaries\$Platform\*" $payloadDir
|
||||
Copy-Item "$nugetPackagesDir\Microsoft.Taef.10.60.210621002\build\Binaries\$Platform\NetFx4.5\*" $payloadDir
|
||||
New-Item -ItemType Directory -Force -Path "$payloadDir\.NETCoreApp2.1\"
|
||||
Copy-Item "$nugetPackagesDir\runtime.win-$Platform.microsoft.netcore.app.2.1.0\runtimes\win-$Platform\lib\netcoreapp2.1\*" "$payloadDir\.NETCoreApp2.1\"
|
||||
Copy-Item "$nugetPackagesDir\runtime.win-$Platform.microsoft.netcore.app.2.1.0\runtimes\win-$Platform\native\*" "$payloadDir\.NETCoreApp2.1\"
|
||||
@@ -59,7 +59,7 @@ Copy-Item "build\Helix\EnsureMachineState.ps1" "$payloadDir"
|
||||
Copy-Item "$repoDirectory\Artifacts\$ArtifactName\appx\CascadiaPackage_0.0.1.0_$Platform.msix" $payloadDir\CascadiaPackage.zip
|
||||
|
||||
# Rename it to extension of ZIP because Expand-Archive is real sassy on the build machines
|
||||
# and refuses to unzip it because of its file extension while on a desktop, it just
|
||||
# and refuses to unzip it because of its file extension while on a desktop, it just
|
||||
# does the job without complaining.
|
||||
|
||||
# Extract the APPX package
|
||||
|
||||
@@ -20,13 +20,31 @@ function Generate-File-Links
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "<ul>"
|
||||
foreach($file in $files)
|
||||
{
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "<li><a href=$($file.Link)>$($file.Name)</a></li>"
|
||||
$url = Append-HelixAccessTokenToUrl $file.Link "{Your-Helix-Access-Token-Here}"
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "<li>$($url)</li>"
|
||||
}
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "</ul>"
|
||||
Out-File -FilePath $helixLinkFile -Append -InputObject "</div>"
|
||||
}
|
||||
}
|
||||
|
||||
function Append-HelixAccessTokenToUrl
|
||||
{
|
||||
Param ([string]$url, [string]$token)
|
||||
if($token)
|
||||
{
|
||||
if($url.Contains("?"))
|
||||
{
|
||||
$url = "$($url)&access_token=$($token)"
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = "$($url)?access_token=$($token)"
|
||||
}
|
||||
}
|
||||
return $url
|
||||
}
|
||||
|
||||
#Create output directory
|
||||
New-Item $OutputFolder -ItemType Directory
|
||||
|
||||
@@ -63,7 +81,8 @@ foreach ($testRun in $testRuns.value)
|
||||
if (-not $workItems.Contains($workItem))
|
||||
{
|
||||
$workItems.Add($workItem)
|
||||
$filesQueryUri = "https://helix.dot.net/api/2019-06-17/jobs/$helixJobId/workitems/$helixWorkItemName/files$accessTokenParam"
|
||||
$filesQueryUri = "https://helix.dot.net/api/2019-06-17/jobs/$helixJobId/workitems/$helixWorkItemName/files"
|
||||
$filesQueryUri = Append-HelixAccessTokenToUrl $filesQueryUri $helixAccessToken
|
||||
$files = Invoke-RestMethodWithRetries $filesQueryUri
|
||||
|
||||
$screenShots = $files | where { $_.Name.EndsWith(".jpg") }
|
||||
@@ -102,6 +121,7 @@ foreach ($testRun in $testRuns.value)
|
||||
|
||||
Write-Host "Downloading $link to $destination"
|
||||
|
||||
$link = Append-HelixAccessTokenToUrl $link $HelixAccessToken
|
||||
Download-FileWithRetries $link $destination
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ Write-Host "queryUri = $queryUri"
|
||||
# To account for unreliable tests, we'll iterate through all of the tests associated with this build, check to see any tests that were unreliable
|
||||
# (denoted by being marked as "skipped"), and if so, we'll instead mark those tests with a warning and enumerate all of the attempted runs
|
||||
# with their pass/fail states as well as any relevant error messages for failed attempts.
|
||||
$testRuns = Invoke-RestMethod -Uri $queryUri -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
$testRuns = Invoke-RestMethodWithRetries $queryUri -Headers $azureDevOpsRestApiHeaders
|
||||
|
||||
$timesSeenByRunName = @{}
|
||||
|
||||
@@ -32,10 +32,10 @@ foreach ($testRun in $testRuns.value)
|
||||
$testRunResultsUri = "$($testRun.url)/results?api-version=5.0"
|
||||
|
||||
Write-Host "Marking test run `"$($testRun.name)`" as in progress so we can change its results to account for unreliable tests."
|
||||
Invoke-RestMethod -Uri "$($testRun.url)?api-version=5.0" -Method Patch -Body (ConvertTo-Json @{ "state" = "InProgress" }) -Headers $azureDevOpsRestApiHeaders -ContentType "application/json" | Out-Null
|
||||
Invoke-RestMethod "$($testRun.url)?api-version=5.0" -Method Patch -Body (ConvertTo-Json @{ "state" = "InProgress" }) -Headers $azureDevOpsRestApiHeaders -ContentType "application/json" | Out-Null
|
||||
|
||||
Write-Host "Retrieving test results..."
|
||||
$testResults = Invoke-RestMethod -Uri $testRunResultsUri -Method Get -Headers $azureDevOpsRestApiHeaders
|
||||
$testResults = Invoke-RestMethodWithRetries $testRunResultsUri -Headers $azureDevOpsRestApiHeaders
|
||||
|
||||
foreach ($testResult in $testResults.value)
|
||||
{
|
||||
@@ -54,7 +54,8 @@ foreach ($testRun in $testRuns.value)
|
||||
Write-Host " Test $($testResult.testCaseTitle) was detected as unreliable. Updating..."
|
||||
|
||||
# The errorMessage field contains a link to the JSON-encoded rerun result data.
|
||||
$rerunResults = ConvertFrom-Json (New-Object System.Net.WebClient).DownloadString($testResult.errorMessage)
|
||||
$resultsJson = Download-StringWithRetries "Error results" $testResult.errorMessage
|
||||
$rerunResults = ConvertFrom-Json $resultsJson
|
||||
[System.Collections.Generic.List[System.Collections.Hashtable]]$rerunDataList = @()
|
||||
$attemptCount = 0
|
||||
$passCount = 0
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="MUXCustomBuildTasks" version="1.0.48" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.Windows.Terminal.TestContent" version="1.0.1" />
|
||||
<package id="Microsoft.Taef" version="10.58.210305002" targetFramework="native" />
|
||||
<package id="Microsoft.Taef" version="10.60.210621002" targetFramework="native" />
|
||||
<package id="microsoft.windows.apps.test" version="1.0.181203002" targetFramework="native" />
|
||||
<package id="runtime.win-x86.microsoft.netcore.app" version="2.1.0" targetFramework="native" />
|
||||
<package id="runtime.win-x64.microsoft.netcore.app" version="2.1.0" targetFramework="native" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MUXCustomBuildTasks" version="1.0.48" targetFramework="native" />
|
||||
<package id="Microsoft.Taef" version="10.58.210305002" targetFramework="native" />
|
||||
<package id="Microsoft.Taef" version="10.60.210621002" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -1,48 +1,487 @@
|
||||
# This build should never run as CI or against a pull request.
|
||||
trigger: none
|
||||
pr: none
|
||||
|
||||
pool:
|
||||
name: WinDevPool-L
|
||||
demands: ImageOverride -equals WinDevVS16-latest
|
||||
|
||||
parameters:
|
||||
- name: branding
|
||||
displayName: "Branding (Build Type)"
|
||||
type: string
|
||||
default: Release
|
||||
values:
|
||||
- Release
|
||||
- Preview
|
||||
- name: buildTerminal
|
||||
displayName: "Build Windows Terminal MSIX"
|
||||
type: boolean
|
||||
default: true
|
||||
- name: buildTerminalVPack
|
||||
displayName: "Build Windows Terminal VPack"
|
||||
type: boolean
|
||||
default: false
|
||||
- name: buildWPF
|
||||
displayName: "Build Terminal WPF Control"
|
||||
type: boolean
|
||||
default: false
|
||||
- name: pgoBuildMode
|
||||
displayName: "PGO Build Mode"
|
||||
type: string
|
||||
default: Optimize
|
||||
values:
|
||||
- Optimize
|
||||
- Instrument
|
||||
- None
|
||||
|
||||
- name: buildConfigurations
|
||||
type: object
|
||||
default:
|
||||
- Release
|
||||
- name: buildPlatforms
|
||||
type: object
|
||||
default:
|
||||
- x64
|
||||
- x86
|
||||
- arm64
|
||||
|
||||
variables:
|
||||
baseYearForVersioning: 2019 # Used by build-console-int
|
||||
versionMajor: 0
|
||||
versionMinor: 1
|
||||
TerminalInternalPackageVersion: "0.0.7"
|
||||
|
||||
# When we move off PackageES for Versioning, we'll need to switch
|
||||
# name to this format. For now, though, we need to use DayOfYear.Rev
|
||||
# to unique our builds, as mandated by PackageES's Setup task.
|
||||
# name: '$(versionMajor).$(versionMinor).$(DayOfYear)$(Rev:r).0'
|
||||
#
|
||||
# Build name/version number above must end with .0 to make the
|
||||
# store publication machinery happy.
|
||||
name: 'Terminal_$(date:yyMM).$(date:dd)$(rev:rrr)'
|
||||
|
||||
# Build Arguments:
|
||||
# WindowsTerminalOfficialBuild=[true,false]
|
||||
# true - this is running on our build agent
|
||||
# false - running locally
|
||||
# WindowsTerminalBranding=[Dev,Preview,Release]
|
||||
# <none> - Development build resources (default)
|
||||
# Preview - Preview build resources
|
||||
# Release - regular build resources
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
resources:
|
||||
repositories:
|
||||
- repository: self
|
||||
type: git
|
||||
ref: main
|
||||
jobs:
|
||||
- template: ./templates/build-console-audit-job.yml
|
||||
parameters:
|
||||
platform: x64
|
||||
- job: Build
|
||||
strategy:
|
||||
matrix:
|
||||
${{ each config in parameters.buildConfigurations }}:
|
||||
${{ each platform in parameters.buildPlatforms }}:
|
||||
${{ config }}_${{ platform }}:
|
||||
BuildConfiguration: ${{ config }}
|
||||
BuildPlatform: ${{ platform }}
|
||||
displayName: Build
|
||||
cancelTimeoutInMinutes: 1
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: True
|
||||
- task: PkgESSetupBuild@12
|
||||
displayName: Package ES - Setup Build
|
||||
inputs:
|
||||
disableOutputRedirect: true
|
||||
- task: PowerShell@2
|
||||
displayName: Rationalize Build Platform
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: >-
|
||||
$Arch = "$(BuildPlatform)"
|
||||
|
||||
- template: ./templates/build-console-int.yml
|
||||
parameters:
|
||||
platform: x64
|
||||
additionalBuildArguments: /p:WindowsTerminalOfficialBuild=true;WindowsTerminalBranding=Preview
|
||||
If ($Arch -Eq "x86") { $Arch = "Win32" }
|
||||
|
||||
- template: ./templates/build-console-int.yml
|
||||
parameters:
|
||||
platform: x86
|
||||
additionalBuildArguments: /p:WindowsTerminalOfficialBuild=true;WindowsTerminalBranding=Preview
|
||||
Write-Host "##vso[task.setvariable variable=RationalizedBuildPlatform]${Arch}"
|
||||
- task: NuGetToolInstaller@1
|
||||
displayName: Use NuGet 5.10
|
||||
inputs:
|
||||
versionSpec: 5.10
|
||||
- task: NuGetCommand@2
|
||||
displayName: NuGet custom
|
||||
inputs:
|
||||
command: custom
|
||||
selectOrConfig: config
|
||||
nugetConfigPath: NuGet.Config
|
||||
arguments: restore OpenConsole.sln -SolutionDirectory $(Build.SourcesDirectory)
|
||||
- task: UniversalPackages@0
|
||||
displayName: Download terminal-internal Universal Package
|
||||
inputs:
|
||||
feedListDownload: 2b3f8893-a6e8-411f-b197-a9e05576da48
|
||||
packageListDownload: e82d490c-af86-4733-9dc4-07b772033204
|
||||
versionListDownload: $(TerminalInternalPackageVersion)
|
||||
- task: TouchdownBuildTask@1
|
||||
displayName: Download Localization Files
|
||||
inputs:
|
||||
teamId: 7105
|
||||
authId: $(TouchdownAppId)
|
||||
authKey: $(TouchdownAppKey)
|
||||
resourceFilePath: >-
|
||||
src\cascadia\TerminalApp\Resources\en-US\Resources.resw
|
||||
|
||||
- template: ./templates/build-console-int.yml
|
||||
parameters:
|
||||
platform: arm64
|
||||
additionalBuildArguments: /p:WindowsTerminalOfficialBuild=true;WindowsTerminalBranding=Preview
|
||||
src\cascadia\TerminalControl\Resources\en-US\Resources.resw
|
||||
|
||||
- template: ./templates/check-formatting.yml
|
||||
src\cascadia\TerminalConnection\Resources\en-US\Resources.resw
|
||||
|
||||
- template: ./templates/release-sign-and-bundle.yml
|
||||
src\cascadia\TerminalSettingsModel\Resources\en-US\Resources.resw
|
||||
|
||||
src\cascadia\TerminalSettingsEditor\Resources\en-US\Resources.resw
|
||||
|
||||
src\cascadia\WindowsTerminalUniversal\Resources\en-US\Resources.resw
|
||||
|
||||
src\cascadia\CascadiaPackage\Resources\en-US\Resources.resw
|
||||
appendRelativeDir: true
|
||||
localizationTarget: false
|
||||
pseudoSetting: Included
|
||||
- task: PowerShell@2
|
||||
displayName: Move Loc files one level up
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: >-
|
||||
$Files = Get-ChildItem . -R -Filter 'Resources.resw' | ? FullName -Like '*en-US\*\Resources.resw'
|
||||
|
||||
$Files | % { Move-Item -Verbose $_.Directory $_.Directory.Parent.Parent -EA:Ignore }
|
||||
pwsh: true
|
||||
- task: PowerShell@2
|
||||
displayName: Generate NOTICE.html from NOTICE.md
|
||||
inputs:
|
||||
filePath: .\build\scripts\Generate-ThirdPartyNotices.ps1
|
||||
arguments: -MarkdownNoticePath .\NOTICE.md -OutputPath .\src\cascadia\CascadiaPackage\NOTICE.html
|
||||
pwsh: true
|
||||
- ${{ if eq(parameters.pgoBuildMode, 'Optimize') }}:
|
||||
- task: PowerShell@2
|
||||
displayName: Restore PGO Database
|
||||
inputs:
|
||||
filePath: tools/PGODatabase/restore-pgodb.ps1
|
||||
workingDirectory: $(Build.SourcesDirectory)\tools\PGODatabase
|
||||
- ${{ if eq(parameters.buildTerminal, true) }}:
|
||||
- task: VSBuild@1
|
||||
displayName: Build solution **\OpenConsole.sln
|
||||
inputs:
|
||||
solution: '**\OpenConsole.sln'
|
||||
vsVersion: 16.0
|
||||
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /t:Terminal\CascadiaPackage;Terminal\WindowsTerminalUniversal /p:WindowsTerminalReleaseBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: true
|
||||
maximumCpuCount: true
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Artifact: binlog'
|
||||
condition: failed()
|
||||
continueOnError: True
|
||||
inputs:
|
||||
PathtoPublish: $(Build.SourcesDirectory)\msbuild.binlog
|
||||
ArtifactName: binlog-$(BuildPlatform)
|
||||
- ${{ if eq(parameters.pgoBuildMode, 'Optimize') }}:
|
||||
- task: PowerShell@2
|
||||
displayName: Validate binaries are optimized
|
||||
condition: and(succeeded(), eq(variables['BuildPlatform'], 'x64'))
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: >-
|
||||
$Binaries = 'OpenConsole.exe', 'WindowsTerminal.exe', 'TerminalApp.dll', 'TerminalConnection.dll', 'Microsoft.Terminal.Control.dll', 'Microsoft.Terminal.Remoting.dll', 'Microsoft.Terminal.Settings.Editor.dll', 'Microsoft.Terminal.Settings.Model.dll'
|
||||
|
||||
foreach ($BinFile in $Binaries) {
|
||||
|
||||
& "$(Build.SourcesDirectory)\tools\PGODatabase\verify-pgo.ps1" "$(Build.SourcesDirectory)/src/cascadia/CascadiaPackage/bin/$(BuildPlatform)/$(BuildConfiguration)/$BinFile"
|
||||
|
||||
}
|
||||
- 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
|
||||
pwsh: true
|
||||
- ${{ if eq(parameters.buildWPF, true) }}:
|
||||
- task: VSBuild@1
|
||||
displayName: Build solution **\OpenConsole.sln for PublicTerminalCore
|
||||
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
|
||||
inputs:
|
||||
solution: '**\OpenConsole.sln'
|
||||
vsVersion: 16.0
|
||||
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /p:WindowsTerminalReleaseBuild=true /t:Terminal\wpf\PublicTerminalCore
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
- task: PowerShell@2
|
||||
displayName: Source Index PDBs
|
||||
inputs:
|
||||
filePath: build\scripts\Index-Pdbs.ps1
|
||||
arguments: -SearchDir '$(Build.SourcesDirectory)' -SourceRoot '$(Build.SourcesDirectory)' -recursive -Verbose -CommitId $(Build.SourceVersion)
|
||||
errorActionPreference: silentlyContinue
|
||||
- task: ComponentGovernanceComponentDetection@0
|
||||
displayName: Component Detection
|
||||
- task: PowerShell@2
|
||||
displayName: Run Unit Tests
|
||||
condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'x86')))
|
||||
enabled: False
|
||||
inputs:
|
||||
filePath: build\scripts\Run-Tests.ps1
|
||||
arguments: -MatchPattern '*unit.test*.dll' -Platform '$(RationalizedBuildPlatform)' -Configuration '$(BuildConfiguration)'
|
||||
- task: PowerShell@2
|
||||
displayName: Run Feature Tests
|
||||
condition: and(succeeded(), eq(variables['BuildPlatform'], 'x64'))
|
||||
enabled: False
|
||||
inputs:
|
||||
filePath: build\scripts\Run-Tests.ps1
|
||||
arguments: -MatchPattern '*feature.test*.dll' -Platform '$(RationalizedBuildPlatform)' -Configuration '$(BuildConfiguration)'
|
||||
- ${{ if eq(parameters.buildTerminal, true) }}:
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy *.appx/*.msix to Artifacts
|
||||
inputs:
|
||||
Contents: >-
|
||||
**/*.appx
|
||||
|
||||
**/*.msix
|
||||
|
||||
**/*.appxsym
|
||||
|
||||
!**/Microsoft.VCLibs*.appx
|
||||
TargetFolder: $(Build.ArtifactStagingDirectory)/appx
|
||||
OverWrite: true
|
||||
flattenFolders: true
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: Publish Artifact (appx)
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)/appx
|
||||
ArtifactName: appx-$(BuildPlatform)-$(BuildConfiguration)
|
||||
- ${{ if eq(parameters.buildWPF, true) }}:
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy PublicTerminalCore.dll to Artifacts
|
||||
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
|
||||
inputs:
|
||||
Contents: >-
|
||||
**/PublicTerminalCore.dll
|
||||
|
||||
**/api-ms-win-core-synch-l1-2-0.dll
|
||||
TargetFolder: $(Build.ArtifactStagingDirectory)/wpf
|
||||
OverWrite: true
|
||||
flattenFolders: true
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: Publish Artifact (PublicTerminalCore)
|
||||
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)/wpf
|
||||
ArtifactName: wpf-dll-$(BuildPlatform)-$(BuildConfiguration)
|
||||
- task: PublishSymbols@2
|
||||
displayName: Publish symbols path
|
||||
continueOnError: True
|
||||
inputs:
|
||||
SearchPattern: '**/*.pdb'
|
||||
IndexSources: false
|
||||
SymbolServerType: TeamServices
|
||||
|
||||
- ${{ if eq(parameters.buildTerminal, true) }}:
|
||||
- job: BundleAndSign
|
||||
displayName: Create and sign AppX/MSIX bundles
|
||||
dependsOn: Build
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: True
|
||||
- task: PkgESSetupBuild@12
|
||||
displayName: Package ES - Setup Build
|
||||
inputs:
|
||||
disableOutputRedirect: true
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download Artifacts (*.appx, *.msix)
|
||||
inputs:
|
||||
downloadType: specific
|
||||
itemPattern: >-
|
||||
**/*.msix
|
||||
|
||||
**/*.appx
|
||||
extractTars: false
|
||||
- task: PowerShell@2
|
||||
displayName: Create WindowsTerminal*.msixbundle
|
||||
inputs:
|
||||
filePath: build\scripts\Create-AppxBundle.ps1
|
||||
arguments: -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion 0.0.0.0 -OutputPath "$(System.ArtifactsDirectory)\Microsoft.WindowsTerminal_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
- task: PowerShell@2
|
||||
displayName: Create WindowsTerminalUniversal*.msixbundle
|
||||
inputs:
|
||||
filePath: build\scripts\Create-AppxBundle.ps1
|
||||
arguments: -InputPath "$(System.ArtifactsDirectory)" -ProjectName WindowsTerminalUniversal -BundleVersion $(XES_APPXMANIFESTVERSION) -OutputPath "$(System.ArtifactsDirectory)\Microsoft.WindowsTerminalUniversal_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
- task: EsrpCodeSigning@1
|
||||
displayName: Submit *.msixbundle to ESRP for code signing
|
||||
inputs:
|
||||
ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
|
||||
FolderPath: $(System.ArtifactsDirectory)
|
||||
Pattern: Microsoft.WindowsTerminal*.msixbundle
|
||||
UseMinimatch: true
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: >-
|
||||
[
|
||||
{
|
||||
"KeyCode": "Dynamic",
|
||||
"CertTemplateName": "WINMSAPP1ST",
|
||||
"CertSubjectName": "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
|
||||
"OperationCode": "SigntoolSign",
|
||||
"Parameters": {
|
||||
"OpusName": "Microsoft",
|
||||
"OpusInfo": "http://www.microsoft.com",
|
||||
"FileDigest": "/fd \"SHA256\"",
|
||||
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
|
||||
},
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"KeyCode": "Dynamic",
|
||||
"CertTemplateName": "WINMSAPP1ST",
|
||||
"CertSubjectName": "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
|
||||
"OperationCode": "SigntoolVerify",
|
||||
"Parameters": {},
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Artifact: appxbundle-signed'
|
||||
inputs:
|
||||
PathtoPublish: $(System.ArtifactsDirectory)
|
||||
ArtifactName: appxbundle-signed
|
||||
|
||||
- ${{ if eq(parameters.buildWPF, true) }}:
|
||||
- job: PackageAndSignWPF
|
||||
strategy:
|
||||
matrix:
|
||||
${{ each config in parameters.buildConfigurations }}:
|
||||
${{ config }}:
|
||||
BuildConfiguration: ${{ config }}
|
||||
displayName: Create NuGet Package (WPF Terminal Control)
|
||||
dependsOn: Build
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: True
|
||||
- task: PkgESSetupBuild@12
|
||||
displayName: Package ES - Setup Build
|
||||
inputs:
|
||||
disableOutputRedirect: true
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download x86 PublicTerminalCore
|
||||
inputs:
|
||||
artifactName: wpf-dll-x86-$(BuildConfiguration)
|
||||
itemPattern: '**/*.dll'
|
||||
downloadPath: bin\Win32\$(BuildConfiguration)\
|
||||
extractTars: false
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download x64 PublicTerminalCore
|
||||
inputs:
|
||||
artifactName: wpf-dll-x64-$(BuildConfiguration)
|
||||
itemPattern: '**/*.dll'
|
||||
downloadPath: bin\x64\$(BuildConfiguration)\
|
||||
extractTars: false
|
||||
- task: PowerShell@2
|
||||
displayName: Move downloaded artifacts up a level
|
||||
inputs:
|
||||
targetType: inline
|
||||
# Find all artifact files and move them up a directory. Ugh.
|
||||
script: >-
|
||||
Get-ChildItem bin -Recurse -Directory -Filter wpf-dll-* | % {
|
||||
$_ | Get-ChildItem -Recurse -File | % {
|
||||
Move-Item -Verbose $_.FullName $_.Directory.Parent.FullName
|
||||
}
|
||||
}
|
||||
- task: NuGetToolInstaller@1
|
||||
displayName: Use NuGet 5.10.0
|
||||
inputs:
|
||||
versionSpec: 5.10.0
|
||||
- task: NuGetCommand@2
|
||||
displayName: NuGet restore copy
|
||||
inputs:
|
||||
selectOrConfig: config
|
||||
nugetConfigPath: NuGet.Config
|
||||
- task: VSBuild@1
|
||||
displayName: Build solution **\OpenConsole.sln for WPF Control
|
||||
inputs:
|
||||
solution: '**\OpenConsole.sln'
|
||||
vsVersion: 16.0
|
||||
msbuildArgs: /p:WindowsTerminalReleaseBuild=$(UseReleaseBranding);Version=$(XES_PACKAGEVERSIONNUMBER) /t:Pack
|
||||
platform: Any CPU
|
||||
configuration: $(BuildConfiguration)
|
||||
maximumCpuCount: true
|
||||
- task: PublishSymbols@2
|
||||
displayName: Publish symbols path
|
||||
continueOnError: True
|
||||
inputs:
|
||||
SearchPattern: '**/*.pdb'
|
||||
IndexSources: false
|
||||
SymbolServerType: TeamServices
|
||||
SymbolsArtifactName: Symbols_WPF_$(BuildConfiguration)
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy *.nupkg to Artifacts
|
||||
inputs:
|
||||
Contents: '**/*Wpf*.nupkg'
|
||||
TargetFolder: $(Build.ArtifactStagingDirectory)/nupkg
|
||||
OverWrite: true
|
||||
flattenFolders: true
|
||||
- task: EsrpCodeSigning@1
|
||||
displayName: Submit *.nupkg to ESRP for code signing
|
||||
inputs:
|
||||
ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
|
||||
FolderPath: $(Build.ArtifactStagingDirectory)/nupkg
|
||||
Pattern: '*.nupkg'
|
||||
UseMinimatch: true
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: >-
|
||||
[
|
||||
{
|
||||
"KeyCode": "CP-401405",
|
||||
"OperationCode": "NuGetSign",
|
||||
"Parameters": {},
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"KeyCode": "CP-401405",
|
||||
"OperationCode": "NuGetVerify",
|
||||
"Parameters": {},
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: Publish Artifact (nupkg)
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)\nupkg
|
||||
ArtifactName: wpf-nupkg-$(BuildConfiguration)
|
||||
|
||||
- ${{ if eq(parameters.buildTerminalVPack, true) }}:
|
||||
- job: VPack
|
||||
displayName: Create Windows vPack
|
||||
dependsOn: BundleAndSign
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
- task: PkgESSetupBuild@12
|
||||
displayName: Package ES - Setup Build
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download Build Artifacts
|
||||
inputs:
|
||||
artifactName: appxbundle-signed
|
||||
extractTars: false
|
||||
- task: PowerShell@2
|
||||
displayName: Rename and stage packages for vpack
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: >-
|
||||
# Rename to known/fixed name for Windows build system
|
||||
|
||||
Get-ChildItem Microsoft.WindowsTerminal_*.msixbundle | Rename-Item -NewName { 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle' }
|
||||
|
||||
|
||||
# Create vpack directory and place item inside
|
||||
|
||||
mkdir WindowsTerminal.app
|
||||
|
||||
mv Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle .\WindowsTerminal.app\
|
||||
workingDirectory: $(System.ArtifactsDirectory)\appxbundle-signed
|
||||
- task: PkgESVPack@12
|
||||
displayName: 'Package ES - VPack'
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
inputs:
|
||||
sourceDirectory: $(System.ArtifactsDirectory)\appxbundle-signed\WindowsTerminal.app
|
||||
description: Windows Terminal pre-install application
|
||||
pushPkgName: WindowsTerminal.app
|
||||
owner: condev
|
||||
...
|
||||
|
||||
@@ -8,9 +8,12 @@ jobs:
|
||||
variables:
|
||||
BuildConfiguration: AuditMode
|
||||
BuildPlatform: ${{ parameters.platform }}
|
||||
pool: "windevbuildagents"
|
||||
# The public pool is also an option!
|
||||
# pool: { vmImage: windows-2019 }
|
||||
pool:
|
||||
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
|
||||
name: WinDevPoolOSS-L
|
||||
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
|
||||
name: WinDevPool-L
|
||||
demands: ImageOverride -equals WinDevVS16-latest
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
|
||||
@@ -11,9 +11,12 @@ jobs:
|
||||
variables:
|
||||
BuildConfiguration: ${{ parameters.configuration }}
|
||||
BuildPlatform: ${{ parameters.platform }}
|
||||
pool: "windevbuildagents"
|
||||
# The public pool is also an option!
|
||||
# pool: { vmImage: windows-2019 }
|
||||
pool:
|
||||
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
|
||||
name: WinDevPoolOSS-L
|
||||
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
|
||||
name: WinDevPool-L
|
||||
demands: ImageOverride -equals WinDevVS16-latest
|
||||
|
||||
steps:
|
||||
- template: build-console-steps.yml
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
parameters:
|
||||
configuration: 'Release'
|
||||
platform: ''
|
||||
additionalBuildArguments: ''
|
||||
|
||||
jobs:
|
||||
- job: Build${{ parameters.platform }}${{ parameters.configuration }}
|
||||
displayName: Build ${{ parameters.platform }} ${{ parameters.configuration }}
|
||||
variables:
|
||||
BuildConfiguration: ${{ parameters.configuration }}
|
||||
BuildPlatform: ${{ parameters.platform }}
|
||||
PGOBuildMode: 'Optimize'
|
||||
|
||||
pool:
|
||||
name: Package ES Lab E
|
||||
demands:
|
||||
- msbuild
|
||||
- visualstudio
|
||||
- vstest
|
||||
|
||||
steps:
|
||||
- task: PkgESSetupBuild@10
|
||||
displayName: 'Package ES - Setup Build'
|
||||
inputs:
|
||||
useDfs: false
|
||||
productName: WindowsTerminal
|
||||
disableOutputRedirect: true
|
||||
|
||||
- template: build-console-steps.yml
|
||||
parameters:
|
||||
additionalBuildArguments: "/p:XesUseOneStoreVersioning=true;XesBaseYearForStoreVersion=$(baseYearForVersioning) ${{ parameters.additionalBuildArguments }}"
|
||||
@@ -3,7 +3,7 @@ parameters:
|
||||
platform: ''
|
||||
additionalBuildArguments: ''
|
||||
minimumExpectedTestsExecutedCount: 1 # Sanity check for minimum expected tests to be reported
|
||||
rerunPassesRequiredToAvoidFailure: 0
|
||||
rerunPassesRequiredToAvoidFailure: 5
|
||||
|
||||
jobs:
|
||||
- job: Build${{ parameters.platform }}${{ parameters.configuration }}
|
||||
@@ -12,9 +12,12 @@ jobs:
|
||||
BuildConfiguration: ${{ parameters.configuration }}
|
||||
BuildPlatform: ${{ parameters.platform }}
|
||||
PGOBuildMode: 'Instrument'
|
||||
pool: "windevbuildagents"
|
||||
# The public pool is also an option!
|
||||
# pool: { vmImage: windows-2019 }
|
||||
pool:
|
||||
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
|
||||
name: WinDevPoolOSS-L
|
||||
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
|
||||
name: WinDevPool-L
|
||||
demands: ImageOverride -equals WinDevVS16-latest
|
||||
|
||||
steps:
|
||||
- template: build-console-steps.yml
|
||||
|
||||
@@ -12,4 +12,4 @@ steps:
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\Helix\GenerateTestProjFile.ps1
|
||||
arguments: -TestFile '${{ parameters.testFilePath }}' -OutputProjFile '$(Build.ArtifactStagingDirectory)\$(BuildConfiguration)\$(BuildPlatform)\${{ parameters.outputProjFileName }}' -JobTestSuiteName '${{ parameters.testSuite }}' -TaefPath '$(Build.SourcesDirectory)\build\Helix\packages\Microsoft.Taef.10.58.210305002\build\Binaries\x86' -TaefQuery '${{ parameters.taefQuery }}'
|
||||
arguments: -TestFile '${{ parameters.testFilePath }}' -OutputProjFile '$(Build.ArtifactStagingDirectory)\$(BuildConfiguration)\$(BuildPlatform)\${{ parameters.outputProjFileName }}' -JobTestSuiteName '${{ parameters.testSuite }}' -TaefPath '$(Build.SourcesDirectory)\build\Helix\packages\Microsoft.Taef.10.60.210621002\build\Binaries\x86' -TaefQuery '${{ parameters.taefQuery }}'
|
||||
@@ -22,6 +22,7 @@ jobs:
|
||||
condition: succeededOrFailed()
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
HelixAccessToken: $(HelixApiAccessToken)
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\Helix\UpdateUnreliableTests.ps1
|
||||
@@ -32,6 +33,7 @@ jobs:
|
||||
condition: succeededOrFailed()
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
HelixAccessToken: $(HelixApiAccessToken)
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\Helix\OutputTestResults.ps1
|
||||
|
||||
@@ -15,6 +15,7 @@ parameters:
|
||||
# if 'useBuildOutputFromBuildId' is set, we will default to using a build from this pipeline:
|
||||
useBuildOutputFromPipeline: $(System.DefinitionId)
|
||||
openHelixTargetQueues: 'windows.10.amd64.client19h1.open.xaml'
|
||||
closedHelixTargetQueues: 'windows.10.amd64.client19h1.xaml'
|
||||
|
||||
jobs:
|
||||
- job: ${{ parameters.name }}
|
||||
@@ -29,11 +30,11 @@ jobs:
|
||||
buildConfiguration: ${{ parameters.configuration }}
|
||||
buildPlatform: ${{ parameters.platform }}
|
||||
openHelixTargetQueues: ${{ parameters.openHelixTargetQueues }}
|
||||
closedHelixTargetQueues: ${{ parameters.closedHelixTargetQueues }}
|
||||
artifactsDir: $(Build.SourcesDirectory)\Artifacts
|
||||
taefPath: $(Build.SourcesDirectory)\build\Helix\packages\Microsoft.Taef.10.58.210305002\build\Binaries\$(buildPlatform)
|
||||
taefPath: $(Build.SourcesDirectory)\build\Helix\packages\Microsoft.Taef.10.60.210621002\build\Binaries\$(buildPlatform)
|
||||
helixCommonArgs: '/binaryLogger:$(Build.SourcesDirectory)/${{parameters.name}}.$(buildPlatform).$(buildConfiguration).binlog /p:HelixBuild=$(Build.BuildId).$(buildPlatform).$(buildConfiguration) /p:Platform=$(buildPlatform) /p:Configuration=$(buildConfiguration) /p:HelixType=${{parameters.helixType}} /p:TestSuite=${{parameters.testSuite}} /p:ProjFilesPath=$(Build.ArtifactStagingDirectory) /p:rerunPassesRequiredToAvoidFailure=${{parameters.rerunPassesRequiredToAvoidFailure}}'
|
||||
|
||||
|
||||
steps:
|
||||
- task: CmdLine@1
|
||||
displayName: 'Display build machine environment variables'
|
||||
@@ -140,6 +141,7 @@ jobs:
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Run tests in Helix (open queues)'
|
||||
condition: and(succeeded(),eq(variables['System.CollectionUri'],'https://dev.azure.com/ms/'))
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
inputs:
|
||||
@@ -148,3 +150,14 @@ jobs:
|
||||
custom: msbuild
|
||||
arguments: '$(helixCommonArgs) /p:IsExternal=true /p:Creator=Terminal /p:HelixTargetQueues=$(openHelixTargetQueues)'
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Run tests in Helix (closed queues)'
|
||||
condition: and(succeeded(),ne(variables['System.CollectionUri'],'https://dev.azure.com/ms/'))
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
HelixAccessToken: $(HelixApiAccessToken)
|
||||
inputs:
|
||||
command: custom
|
||||
projects: build\Helix\RunTestsInHelix.proj
|
||||
custom: msbuild
|
||||
arguments: '$(helixCommonArgs) /p:HelixTargetQueues=$(closedHelixTargetQueues)'
|
||||
|
||||
@@ -20,11 +20,15 @@ jobs:
|
||||
inputs:
|
||||
artifactName: ${{ parameters.pgoArtifact }}
|
||||
downloadPath: $(artifactsPath)
|
||||
|
||||
- task: NuGetToolInstaller@0
|
||||
displayName: 'Use NuGet 5.2.0'
|
||||
|
||||
- task: NuGetAuthenticate@0
|
||||
inputs:
|
||||
versionSpec: 5.2.0
|
||||
nuGetServiceConnections: 'Terminal Public Artifact Feed'
|
||||
|
||||
- task: NuGetToolInstaller@0
|
||||
displayName: 'Use NuGet 5.8.0'
|
||||
inputs:
|
||||
versionSpec: 5.8.0
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy pgd files to NuGet build directory'
|
||||
@@ -58,5 +62,11 @@ jobs:
|
||||
displayName: 'NuGet push'
|
||||
inputs:
|
||||
command: push
|
||||
publishVstsFeed: Terminal/TerminalDependencies
|
||||
packagesToPush: $(Build.ArtifactStagingDirectory)/*.nupkg
|
||||
nuGetFeedType: external
|
||||
packagesToPush: $(Build.ArtifactStagingDirectory)/*.nupkg
|
||||
# The actual URL and PAT for this feed is configured at
|
||||
# https://microsoft.visualstudio.com/Dart/_settings/adminservices
|
||||
# This is the name of that connection
|
||||
publishFeedCredentials: 'Terminal Public Artifact Feed'
|
||||
feedsToUse: config
|
||||
nugetConfigPath: '$(Build.SourcesDirectory)/NuGet.config'
|
||||
@@ -1,74 +0,0 @@
|
||||
parameters:
|
||||
configuration: 'Release'
|
||||
|
||||
jobs:
|
||||
- job: SignDeploy${{ parameters.configuration }}
|
||||
displayName: Sign and Deploy for ${{ parameters.configuration }}
|
||||
|
||||
dependsOn:
|
||||
- Buildx64AuditMode
|
||||
- Buildx64Release
|
||||
- Buildx86Release
|
||||
- Buildarm64Release
|
||||
- CodeFormatCheck
|
||||
condition: |
|
||||
and
|
||||
(
|
||||
in(dependencies.Buildx64AuditMode.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
|
||||
in(dependencies.Buildx64Release.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
|
||||
in(dependencies.Buildx86Release.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
|
||||
in(dependencies.Buildarm64Release.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
|
||||
in(dependencies.CodeFormatCheck.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')
|
||||
)
|
||||
|
||||
variables:
|
||||
BuildConfiguration: ${{ parameters.configuration }}
|
||||
AppxProjectName: CascadiaPackage
|
||||
AppxBundleName: Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle
|
||||
|
||||
pool:
|
||||
name: Package ES Lab E
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
|
||||
- task: PkgESSetupBuild@10
|
||||
displayName: 'Package ES - Setup Build'
|
||||
inputs:
|
||||
useDfs: false
|
||||
productName: WindowsTerminal
|
||||
disableOutputRedirect: true
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download AppX artifacts
|
||||
inputs:
|
||||
artifactName: 'appx-$(BuildConfiguration)'
|
||||
itemPattern: |
|
||||
**/*.appx
|
||||
**/*.msix
|
||||
downloadPath: '$(Build.ArtifactStagingDirectory)\appx'
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Create $(AppxBundleName)'
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: '.\build\scripts\Create-AppxBundle.ps1'
|
||||
arguments: |
|
||||
-InputPath "$(Build.ArtifactStagingDirectory)\appx" -ProjectName $(AppxProjectName) -BundleVersion 0.0.0.0 -OutputPath "$(Build.ArtifactStagingDirectory)\$(AppxBundleName)"
|
||||
|
||||
- task: PkgESCodeSign@10
|
||||
displayName: 'Package ES - SignConfig.WindowsTerminal.xml'
|
||||
inputs:
|
||||
signConfigXml: 'build\config\SignConfig.WindowsTerminal.xml'
|
||||
inPathRoot: '$(Build.ArtifactStagingDirectory)'
|
||||
outPathRoot: '$(Build.ArtifactStagingDirectory)\signed'
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Signed AppX'
|
||||
inputs:
|
||||
PathtoPublish: '$(Build.ArtifactStagingDirectory)\signed'
|
||||
ArtifactName: 'appxbundle-signed-$(BuildConfiguration)'
|
||||
@@ -19,6 +19,7 @@
|
||||
"/.github/",
|
||||
"/samples/",
|
||||
"/res/terminal/",
|
||||
"/res/fonts/",
|
||||
"/doc/specs/",
|
||||
"/doc/cascadia/",
|
||||
"/doc/user-docs/",
|
||||
|
||||
@@ -6,9 +6,9 @@ Adding a setting to Windows Terminal is fairly straightforward. This guide serve
|
||||
|
||||
The Terminal Settings Model (`Microsoft.Terminal.Settings.Model`) is responsible for (de)serializing and exposing settings.
|
||||
|
||||
### `GETSET_SETTING` macro
|
||||
### `INHERITABLE_SETTING` macro
|
||||
|
||||
The `GETSET_SETTING` macro can be used to implement inheritance for your new setting and store the setting in the settings model. It takes three parameters:
|
||||
The `INHERITABLE_SETTING` macro can be used to implement inheritance for your new setting and store the setting in the settings model. It takes three parameters:
|
||||
- `type`: the type that the setting will be stored as
|
||||
- `name`: the name of the variable for storage
|
||||
- `defaultValue`: the value to use if the user does not define the setting anywhere
|
||||
@@ -20,7 +20,7 @@ This tutorial will add `CloseOnExitMode CloseOnExit` as a profile setting.
|
||||
1. In `Profile.h`, declare/define the setting:
|
||||
|
||||
```c++
|
||||
GETSET_SETTING(CloseOnExitMode, CloseOnExit, CloseOnExitMode::Graceful)
|
||||
INHERITABLE_SETTING(CloseOnExitMode, CloseOnExit, CloseOnExitMode::Graceful)
|
||||
```
|
||||
|
||||
2. In `Profile.idl`, expose the setting via WinRT:
|
||||
@@ -141,7 +141,7 @@ struct OpenSettingsArgs : public OpenSettingsArgsT<OpenSettingsArgs>
|
||||
OpenSettingsArgs() = default;
|
||||
|
||||
// adds a getter/setter for your argument, and defines the json key
|
||||
GETSET_PROPERTY(SettingsTarget, Target, SettingsTarget::SettingsFile);
|
||||
WINRT_PROPERTY(SettingsTarget, Target, SettingsTarget::SettingsFile);
|
||||
static constexpr std::string_view TargetKey{ "target" };
|
||||
|
||||
public:
|
||||
@@ -213,9 +213,9 @@ Terminal-level settings are settings that affect a shell session. Generally, the
|
||||
- Declare the setting in `IControlSettings.idl` or `ICoreSettings.idl` (whichever is relevant to your setting). If your setting is an enum setting, declare the enum here instead of in the `TerminalSettingsModel` project.
|
||||
- In `TerminalSettings.h`, declare/define the setting...
|
||||
```c++
|
||||
// The GETSET_PROPERTY macro declares/defines a getter setter for the setting.
|
||||
// Like GETSET_SETTING, it takes in a type, name, and defaultValue.
|
||||
GETSET_PROPERTY(bool, UseAcrylic, false);
|
||||
// The WINRT_PROPERTY macro declares/defines a getter setter for the setting.
|
||||
// Like INHERITABLE_SETTING, it takes in a type, name, and defaultValue.
|
||||
WINRT_PROPERTY(bool, UseAcrylic, false);
|
||||
```
|
||||
- In `TerminalSettings.cpp`...
|
||||
- update `_ApplyProfileSettings` for profile settings
|
||||
|
||||
@@ -154,6 +154,17 @@
|
||||
"description": "Sets how the background image aligns to the boundaries of the window when unfocused. Possible values: \"center\", \"left\", \"top\", \"right\", \"bottom\", \"topLeft\", \"topRight\", \"bottomLeft\", \"bottomRight\"",
|
||||
"type": "string"
|
||||
},
|
||||
"intenseTextStyle": {
|
||||
"default": "bright",
|
||||
"description": "Controls how 'intense' text is rendered. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"enum": [
|
||||
"none",
|
||||
"bold",
|
||||
"bright",
|
||||
"all"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"experimental.retroTerminalEffect": {
|
||||
"description": "When set to true, enable retro terminal effects when unfocused. This is an experimental feature, and its continued existence is not guaranteed.",
|
||||
"type": "boolean"
|
||||
@@ -165,6 +176,49 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"FontConfig": {
|
||||
"properties": {
|
||||
"face": {
|
||||
"default": "Cascadia Mono",
|
||||
"description": "Name of the font face used in the profile.",
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"default": 12,
|
||||
"description": "Size of the font in points.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"weight": {
|
||||
"default": "normal",
|
||||
"description": "Sets the weight (lightness or heaviness of the strokes) for the given font. Possible values:\n -\"thin\"\n -\"extra-light\"\n -\"light\"\n -\"semi-light\"\n -\"normal\" (default)\n -\"medium\"\n -\"semi-bold\"\n -\"bold\"\n -\"extra-bold\"\n -\"black\"\n -\"extra-black\"\n or the corresponding numeric representation of OpenType font weight.",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": [
|
||||
"thin",
|
||||
"extra-light",
|
||||
"light",
|
||||
"semi-light",
|
||||
"normal",
|
||||
"medium",
|
||||
"semi-bold",
|
||||
"bold",
|
||||
"extra-bold",
|
||||
"black",
|
||||
"extra-black"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"maximum": 990,
|
||||
"minimum": 100,
|
||||
"type": "integer"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ProfileGuid": {
|
||||
"default": "{}",
|
||||
"pattern": "^\\{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\\}$",
|
||||
@@ -546,12 +600,14 @@
|
||||
"action": { "type": "string", "pattern": "openSettings" },
|
||||
"target": {
|
||||
"type": "string",
|
||||
"default": "settingsFile",
|
||||
"description": "The settings file to open.",
|
||||
"default": "settingsUI",
|
||||
"description": "Opens Settings UI or settings file.",
|
||||
"enum": [
|
||||
"settingsFile",
|
||||
"defaultsFile",
|
||||
"allFiles"
|
||||
"allFiles",
|
||||
"settingsUI"
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -646,6 +702,25 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"CloseTabAction": {
|
||||
"description": "Arguments for a closeTab action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "closeTab" },
|
||||
"index": {
|
||||
"oneOf": [
|
||||
{ "type": "integer" },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"default": null,
|
||||
"description": "Close the tab at this index. If no index is provided, use the focused tab's index."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ScrollUpAction": {
|
||||
"description": "Arguments for a scrollUp action",
|
||||
"allOf": [
|
||||
@@ -897,6 +972,7 @@
|
||||
{ "$ref": "#/definitions/WtAction" },
|
||||
{ "$ref": "#/definitions/CloseOtherTabsAction" },
|
||||
{ "$ref": "#/definitions/CloseTabsAfterAction" },
|
||||
{ "$ref": "#/definitions/CloseTabAction" },
|
||||
{ "$ref": "#/definitions/ScrollUpAction" },
|
||||
{ "$ref": "#/definitions/ScrollDownAction" },
|
||||
{ "$ref": "#/definitions/MoveTabAction" },
|
||||
@@ -1242,6 +1318,11 @@
|
||||
"description": "Sets the appearance of the terminal when it is unfocused.",
|
||||
"type": ["object", "null"]
|
||||
},
|
||||
"font": {
|
||||
"$ref": "#/definitions/FontConfig",
|
||||
"description": "Sets the font options of the terminal.",
|
||||
"type": ["object", "null"]
|
||||
},
|
||||
"backgroundImage": {
|
||||
"description": "Sets the file location of the image to draw over the window background.",
|
||||
"oneOf": [
|
||||
@@ -1358,18 +1439,20 @@
|
||||
},
|
||||
"fontFace": {
|
||||
"default": "Cascadia Mono",
|
||||
"description": "Name of the font face used in the profile.",
|
||||
"type": "string"
|
||||
"description": "[deprecated] Define 'face' within the 'font' object instead.",
|
||||
"type": "string",
|
||||
"deprecated": true
|
||||
},
|
||||
"fontSize": {
|
||||
"default": 12,
|
||||
"description": "Size of the font in points.",
|
||||
"description": "[deprecated] Define 'size' within the 'font' object instead.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
"type": "integer",
|
||||
"deprecated": true
|
||||
},
|
||||
"fontWeight": {
|
||||
"default": "normal",
|
||||
"description": "Sets the weight (lightness or heaviness of the strokes) for the given font. Possible values:\n -\"thin\"\n -\"extra-light\"\n -\"light\"\n -\"semi-light\"\n -\"normal\" (default)\n -\"medium\"\n -\"semi-bold\"\n -\"bold\"\n -\"extra-bold\"\n -\"black\"\n -\"extra-black\"\n or the corresponding numeric representation of OpenType font weight.",
|
||||
"description": "[deprecated] Define 'weight' within the 'font' object instead.",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": [
|
||||
@@ -1392,7 +1475,8 @@
|
||||
"minimum": 100,
|
||||
"type": "integer"
|
||||
}
|
||||
]
|
||||
],
|
||||
"deprecated": true
|
||||
},
|
||||
"foreground": {
|
||||
"$ref": "#/definitions/Color",
|
||||
|
||||
105
doc/specs/#1790 - Font features and axes-spec.md
Normal file
105
doc/specs/#1790 - Font features and axes-spec.md
Normal file
@@ -0,0 +1,105 @@
|
||||
---
|
||||
author: Pankaj Bhojwani, pabhojwa@microsoft.com
|
||||
created on: 2021-6-17
|
||||
last updated: 2021-6-23
|
||||
issue id: #1790
|
||||
---
|
||||
|
||||
# Font features and axes of variation
|
||||
|
||||
## Abstract
|
||||
|
||||
This spec outlines how we can allow users to specify font features and axes of variation for fonts in Windows Terminal. Font features include things like being able to specify whether ligatures should be used as well as the specific stylistic set used for a font. Axes of variation commonly include things like weight and slant but can also include fancier things like shadow distance, depending on the font.
|
||||
|
||||
## Inspiration
|
||||
|
||||
Reference: [#1790](https://github.com/microsoft/terminal/issues/1790)
|
||||
|
||||
Currently, if a font has ligatures, we offer no way for a user to disable them. Many users would like the option to do so, and would also like the ability to choose stylistic sets for fonts - for example, at the time of this writing, Cascadia Code offers 4 stylistic sets but we offer no way for users to specify any of them.
|
||||
|
||||
In a similar vein, many fonts allow for setting variations on the font along certain attributes, commonly referred to as 'axes of variation'. We can offer users more font customization options by allowing them to configure these font variations.
|
||||
|
||||
## Solution Design
|
||||
|
||||
### Font features
|
||||
|
||||
It is already possible to pass in a list of [font feature structs](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/ns-dwrite-dwrite_font_feature) to DWrite for it to handle. A font feature struct contains only 2 things:
|
||||
|
||||
1. A font feature tag
|
||||
2. A parameter value
|
||||
|
||||
A font feature tag is constructed using a 4-character feature tag and the parameter value defines how the feature is applied. For most features, the parameter value is simply treated as a binary value - a value of 0 means the feature is not applied and a non-zero value means the feature is applied. For example, a font feature struct like {'ss03', 1} enables stylistic set 3 for the font and a font feature struct like {'liga', 0} disables ligatures. (Technically, the feature tag is _constructed_ with the 4-character tag and is not the 4-character tag itself, but they are treated the same in the example here for brevity's sake).
|
||||
|
||||
Currently, we pass in to DWrite a null value for the list of features to apply to the font. This causes DWrite to automatically apply a ['standard' list](https://github.com/fdwr/TextLayoutSampler/blob/master/DrawableObject.ixx#L802) of font features to the font. Naturally, passing in our own list of font features to DWrite means DWrite will _only_ apply the features we defined, and no longer apply the standard list. Since the standard list contains 11 features, we need to consider how we can allow users to specify 1 additional feature or delete 1 of the standard features without needing to redefine all the others.
|
||||
|
||||
We will do this by allowing users to define a dictionary in their settings.json file, where the keys are the 4-character feature tags and the values are the parameter values. This dictionary will then get applied to our internal dictionary (which will contain the standard list of 11 features with their parameter values), meaning that any new key-value pairs will get added to our dictionary and any existing key-value pairs will get updated. Finally, this 'merged' dictionary will be what we use to construct the list of features to pass into DWrite.
|
||||
|
||||
### Axes of variation
|
||||
|
||||
Specifying axes of variation is done in an extremely similar manner to the way font features are specified - a 4-character tag is used to specify which font axis is being modified and a numerical value is provided to specify the value the axis should be set to. For example, {'slnt', 20} specifies that the 'slant' axis should be set to 20.
|
||||
|
||||
There is also a standard list of axes of variation, and each axis has its own default. We will approach this the same way we approached font features, by allowing users to specify additional features or omit features without needing to redefine the defaults.
|
||||
|
||||
## UI/UX Design
|
||||
|
||||
Users will be able to add a new setting to their font objects (added in [#10433](https://github.com/microsoft/terminal/pull/10433)). The resultant font object may look something like this
|
||||
|
||||
```json
|
||||
"font": {
|
||||
"face": "Cascadia Code",
|
||||
"size": 12,
|
||||
"features": {
|
||||
"ss03": 1,
|
||||
"liga": 0
|
||||
},
|
||||
"axes": {
|
||||
"slnt": 20.5
|
||||
}
|
||||
}
|
||||
```
|
||||
There is one point to note here about clashing. For example, if a user has the old "weight" setting defined _as well as_ a "wght" axis defined, we will only use the "wght" axis value. We prioritize that value for a few reasons:
|
||||
|
||||
1. It is the more recent addition to our settings model. Thus, it is likely that a user that has defined both values probably just forgot to remove the old value.
|
||||
2. It is the more precise value, it is a specific float value whereas the the old "weight" setting is an enum (that eventually gets mapped to a float value).
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Accessibility
|
||||
|
||||
Should not affect accessibility.
|
||||
|
||||
### Security
|
||||
|
||||
Should not affect security.
|
||||
|
||||
### Reliability
|
||||
|
||||
Aside from additional parsing required for the settings file (which inherently offers more locations for parsing to fail), we need to be careful about badly formed/non-existant feature tags or axes specified in the user-defined dictionaries. We must make sure to ignore such declarations (perhaps alongside emitting a warning to the user) and only apply those that are correctly formed and exist.
|
||||
|
||||
### Compatibility
|
||||
|
||||
Older versions of Windows may not have the DWrite updates that allow for defining font features and axes of variation. We must make sure to fallback to the current implementation in these cases.
|
||||
|
||||
### Performance, Power, and Efficiency
|
||||
|
||||
Currently when rendering a run of text, if we detect that the given run is simple we will use a shortcut to obtain the glyphs needed, skipping over an expensive `GetGlyphs` call to DWrite. However, when the default feature list is changed in any way (either by adding a new feature or removing one of the defaults), there is no way for us to detect beforehand how the font glyphs would change.
|
||||
|
||||
This means that as long as the user requests a change to the default font feature list, we will _always_ skip the shortcut and call the expensive `GetGlyphs` function for every run of text.
|
||||
|
||||
This will naturally cause a performance cost that we will have to bear for this feature. However, it is worth noting that there are a fair number of glyphs that will cause a run of text to be deemed "not simple" (and thus cause us to call `GetGlyphs` anyway), for example when using Cascadia Code, any run of text that has the letters 'i', 'j', 'l', 'n', 'w' or 'x' is not considered simple (because those glyphs have localized variants).
|
||||
|
||||
## Potential Issues
|
||||
|
||||
See performance issues above.
|
||||
|
||||
## Future considerations
|
||||
|
||||
DWrite additionally offers the ability to vary the font features across runs of text. However, for our initial implementation of this feature, we will only apply font features to the entire buffer. If/when we decide to allow specifying font features for particular runs of text, we can lean into our existing mechanisms of splitting up runs of text to implement that.
|
||||
|
||||
We will also need to consider how we want to represent this in the settings UI. This is slightly more complex than other settings since users should be allowed to manually input 4-character tags.
|
||||
|
||||
## Resources
|
||||
|
||||
[DWRITE_FONT_FEATURE structure](https://docs.microsoft.com/en-us/windows/win32/api/dwrite/ns-dwrite-dwrite_font_feature)
|
||||
|
||||
[DWRITE_FONT_AXIS_VALUE structure](https://docs.microsoft.com/en-us/windows/win32/api/dwrite_3/ns-dwrite_3-dwrite_font_axis_value)
|
||||
@@ -28,7 +28,7 @@ Below is the schedule for when milestones will be included in release builds of
|
||||
| 2021-01-31 | [1.6] in Windows Terminal Preview<br>[1.5] in Windows Terminal | [Windows Terminal Preview 1.6 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-6-release/) |
|
||||
| 2021-03-01 | [1.7] in Windows Terminal Preview<br>[1.6] in Windows Terminal | [Windows Terminal Preview 1.7 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-7-release/) |
|
||||
| 2021-04-14 | [1.8] in Windows Terminal Preview<br>[1.7] in Windows Terminal | [Windows Terminal Preview 1.8 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-8-release/) |
|
||||
| 2021-05-31 | [1.9] in Windows Terminal Preview<br>[1.8] in Windows Terminal | |
|
||||
| 2021-05-31 | [1.9] in Windows Terminal Preview<br>[1.8] in Windows Terminal | [Windows Terminal Preview 1.9 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-9-release/) |
|
||||
| 2021-07-31 | 1.10 in Windows Terminal Preview<br>[1.9] in Windows Terminal | |
|
||||
| 2021-08-30 | 1.11 in Windows Terminal Preview<br>1.10 in Windows Terminal | |
|
||||
| 2021-10-31 | 1.12 in Windows Terminal Preview<br>1.11 in Windows Terminal | |
|
||||
|
||||
BIN
res/Cascadia.ttf
BIN
res/Cascadia.ttf
Binary file not shown.
Binary file not shown.
@@ -6,16 +6,3 @@ The images in this directory do not fall under the same [license](https://raw.gi
|
||||
of the Windows Terminal code.
|
||||
|
||||
Please consult the [license](./LICENSE) in this directory for terms applicable to the image assets in this directory.
|
||||
|
||||
## Fonts
|
||||
|
||||
The fonts in this directory do not fall under the same [license](https://raw.githubusercontent.com/microsoft/terminal/main/LICENSE) as the rest
|
||||
of the Windows Terminal code.
|
||||
|
||||
Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadia-code/main/LICENSE) in the
|
||||
[microsoft/cascadia-code](https://github.com/microsoft/cascadia-code) repository for terms applicable to the fonts in this directory.
|
||||
|
||||
### Fonts Included
|
||||
|
||||
* Cascadia Code, Cascadia Mono (2102.25)
|
||||
* from microsoft/cascadia-code@911dc421f333e3b72b97381d16fee5b71eb48f04
|
||||
|
||||
BIN
res/fonts/CascadiaCode.ttf
Normal file
BIN
res/fonts/CascadiaCode.ttf
Normal file
Binary file not shown.
BIN
res/fonts/CascadiaCodeItalic.ttf
Normal file
BIN
res/fonts/CascadiaCodeItalic.ttf
Normal file
Binary file not shown.
BIN
res/fonts/CascadiaMono.ttf
Normal file
BIN
res/fonts/CascadiaMono.ttf
Normal file
Binary file not shown.
BIN
res/fonts/CascadiaMonoItalic.ttf
Normal file
BIN
res/fonts/CascadiaMonoItalic.ttf
Normal file
Binary file not shown.
12
res/fonts/README.md
Normal file
12
res/fonts/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Windows Terminal and Console Assets (Fonts)
|
||||
|
||||
The fonts in this directory do not fall under the same [license](https://raw.githubusercontent.com/microsoft/terminal/main/LICENSE) as the rest
|
||||
of the Windows Terminal code.
|
||||
|
||||
Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadia-code/main/LICENSE) in the
|
||||
[microsoft/cascadia-code](https://github.com/microsoft/cascadia-code) repository for terms applicable to the fonts in this directory.
|
||||
|
||||
### Fonts Included
|
||||
|
||||
* Cascadia Code, Cascadia Mono (2108.26)
|
||||
* from microsoft/cascadia-code@f91d08f703ee61cf4ae936b9700ca974de2748fe
|
||||
@@ -9,30 +9,22 @@ namespace winrt::SampleApp::implementation
|
||||
|
||||
IXamlType GetXamlType(::winrt::Windows::UI::Xaml::Interop::TypeName const& type)
|
||||
{
|
||||
return AppProvider()->GetXamlType(type);
|
||||
return _appProvider.GetXamlType(type);
|
||||
}
|
||||
|
||||
IXamlType GetXamlType(::winrt::hstring const& fullName)
|
||||
{
|
||||
return AppProvider()->GetXamlType(fullName);
|
||||
return _appProvider.GetXamlType(fullName);
|
||||
}
|
||||
|
||||
::winrt::com_array<::winrt::Windows::UI::Xaml::Markup::XmlnsDefinition> GetXmlnsDefinitions()
|
||||
{
|
||||
return AppProvider()->GetXmlnsDefinitions();
|
||||
return _appProvider.GetXmlnsDefinitions();
|
||||
}
|
||||
|
||||
private:
|
||||
bool _contentLoaded{ false };
|
||||
std::shared_ptr<XamlMetaDataProvider> _appProvider;
|
||||
std::shared_ptr<XamlMetaDataProvider> AppProvider()
|
||||
{
|
||||
if (!_appProvider)
|
||||
{
|
||||
_appProvider = std::make_shared<XamlMetaDataProvider>();
|
||||
}
|
||||
return _appProvider;
|
||||
}
|
||||
winrt::SampleApp::XamlMetaDataProvider _appProvider;
|
||||
};
|
||||
|
||||
template<typename D, typename... I>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
<ClCompile>
|
||||
@@ -148,13 +148,13 @@
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.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('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
@@ -177,5 +177,5 @@
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Import Project="..\..\..\build\rules\CollectWildcardResources.targets" />
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
</Project>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<!-- ========================= XAML files ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- DON'T PUT XAML FILES HERE! Put them in SampleAppLib.vcxproj -->
|
||||
@@ -77,13 +77,13 @@
|
||||
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.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('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.2" targetFramework="native" />
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<!-- Windows 10 1903 -->
|
||||
<!-- See https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/xaml-islands -->
|
||||
<!-- "maxversiontested" is CASE SENSITIVE. Do not change this.-->
|
||||
<maxversiontested Id="10.0.19041.0"/>
|
||||
<maxversiontested Id="10.0.18362.0"/>
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{b4427499-9fde-4208-b456-5bc580637633}</ProjectGuid>
|
||||
@@ -121,15 +121,15 @@
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.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.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets'))" />
|
||||
</Target>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.2" targetFramework="native" />
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" />
|
||||
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<EventProvider Id="EventProvider_TerminalWin32Host" Name="56c06166-2e2e-5f4d-7ff3-74f4b78c87d6" />
|
||||
<EventProvider Id="EventProvider_TerminalRemoting" Name="d6f04aad-629f-539a-77c1-73f5c3e4aa7b" />
|
||||
<EventProvider Id="EventProvider_TerminalDirectX" Name="c93e739e-ae50-5a14-78e7-f171e947535d" />
|
||||
<EventProvider Id="EventProvider_TerminalUIA" Name="e7ebce59-2161-572d-b263-2f16a6afb9e5"/>
|
||||
<Profile Id="Terminal.Verbose.File" Name="Terminal" Description="Terminal" LoggingMode="File" DetailLevel="Verbose">
|
||||
<Collectors>
|
||||
<EventCollectorId Value="EventCollector_Terminal">
|
||||
@@ -23,6 +24,7 @@
|
||||
<EventProviderId Value="EventProvider_TerminalWin32Host" />
|
||||
<EventProviderId Value="EventProvider_TerminalRemoting" />
|
||||
<EventProviderId Value="EventProvider_TerminalDirectX" />
|
||||
<EventProviderId Value="EventProvider_TerminalUIA" />
|
||||
</EventProviders>
|
||||
</EventCollectorId>
|
||||
</Collectors>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{9cf74355-f018-4c19-81ad-9dc6b7f2c6f5}</ProjectGuid>
|
||||
<RootNamespace>apimswincoresynchl120</RootNamespace>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)src\common.build.pre.props" />
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="definitions.def" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>kernel32.lib</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>definitions.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="definitions.def">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
19
src/api-ms-win-core-synch-l1-2-0/definitions.def
Normal file
19
src/api-ms-win-core-synch-l1-2-0/definitions.def
Normal file
@@ -0,0 +1,19 @@
|
||||
LIBRARY
|
||||
EXPORTS
|
||||
DeleteSynchronizationBarrier = kernel32.DeleteSynchronizationBarrier
|
||||
EnterSynchronizationBarrier = kernel32.EnterSynchronizationBarrier
|
||||
InitOnceBeginInitialize = kernel32.InitOnceBeginInitialize
|
||||
InitOnceComplete = kernel32.InitOnceComplete
|
||||
InitOnceExecuteOnce = kernel32.InitOnceExecuteOnce
|
||||
InitOnceInitialize = kernel32.InitOnceInitialize
|
||||
InitializeConditionVariable = kernel32.InitializeConditionVariable
|
||||
InitializeSynchronizationBarrier = kernel32.InitializeSynchronizationBarrier
|
||||
SignalObjectAndWait = kernel32.SignalObjectAndWait
|
||||
Sleep = kernel32.Sleep
|
||||
SleepConditionVariableCS = kernel32.SleepConditionVariableCS
|
||||
SleepConditionVariableSRW = kernel32.SleepConditionVariableSRW
|
||||
WaitOnAddress
|
||||
WakeAllConditionVariable = kernel32.WakeAllConditionVariable
|
||||
WakeByAddressAll
|
||||
WakeByAddressSingle
|
||||
WakeConditionVariable = kernel32.WakeConditionVariable
|
||||
189
src/api-ms-win-core-synch-l1-2-0/main.cpp
Normal file
189
src/api-ms-win-core-synch-l1-2-0/main.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//
|
||||
// The code in this file was adapted from the STL on the 2021-07-05. Commit:
|
||||
// https://github.com/microsoft/STL/blob/e745bad3b1d05b5b19ec652d68abb37865ffa454/stl/src/atomic_wait.cpp
|
||||
//
|
||||
// It backports the following Windows 8 functions to Windows 7:
|
||||
// * WaitOnAddress
|
||||
// * WakeByAddressSingle
|
||||
// * WakeByAddressAll
|
||||
//
|
||||
|
||||
#include <cstdint>
|
||||
#include <new>
|
||||
|
||||
#include <winsdkver.h>
|
||||
#define _WIN32_WINNT 0x0601
|
||||
#include <sdkddkver.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#include <intrin.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
class [[nodiscard]] SRWLockGuard
|
||||
{
|
||||
public:
|
||||
explicit SRWLockGuard(SRWLOCK & lock) noexcept :
|
||||
_lock(&lock)
|
||||
{
|
||||
AcquireSRWLockExclusive(_lock);
|
||||
}
|
||||
|
||||
~SRWLockGuard()
|
||||
{
|
||||
ReleaseSRWLockExclusive(_lock);
|
||||
}
|
||||
|
||||
SRWLockGuard(const SRWLockGuard&) = delete;
|
||||
SRWLockGuard& operator=(const SRWLockGuard&) = delete;
|
||||
|
||||
SRWLockGuard(SRWLockGuard &&) = delete;
|
||||
SRWLockGuard& operator=(SRWLockGuard&&) = delete;
|
||||
|
||||
private:
|
||||
SRWLOCK* _lock;
|
||||
};
|
||||
|
||||
struct WaitContext
|
||||
{
|
||||
const volatile void* address;
|
||||
WaitContext* next;
|
||||
WaitContext* prev;
|
||||
CONDITION_VARIABLE cv;
|
||||
};
|
||||
|
||||
struct [[nodiscard]] GuardedWaitContext : WaitContext
|
||||
{
|
||||
GuardedWaitContext(const volatile void* storage, WaitContext* head) noexcept :
|
||||
WaitContext{ storage, head, head->prev, CONDITION_VARIABLE_INIT }
|
||||
{
|
||||
prev->next = this;
|
||||
next->prev = this;
|
||||
}
|
||||
|
||||
~GuardedWaitContext()
|
||||
{
|
||||
const auto n = next;
|
||||
const auto p = prev;
|
||||
next->prev = p;
|
||||
prev->next = n;
|
||||
}
|
||||
|
||||
GuardedWaitContext(const GuardedWaitContext&) = delete;
|
||||
GuardedWaitContext& operator=(const GuardedWaitContext&) = delete;
|
||||
|
||||
GuardedWaitContext(GuardedWaitContext &&) = delete;
|
||||
GuardedWaitContext& operator=(GuardedWaitContext&&) = delete;
|
||||
};
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4324) // structure was padded due to alignment specifier
|
||||
struct alignas(std::hardware_destructive_interference_size) WaitTableEntry
|
||||
{
|
||||
SRWLOCK lock = SRWLOCK_INIT;
|
||||
WaitContext head = { nullptr, &head, &head, CONDITION_VARIABLE_INIT };
|
||||
};
|
||||
#pragma warning(pop)
|
||||
|
||||
[[nodiscard]] WaitTableEntry& GetWaitTableEntry(const volatile void* const storage) noexcept
|
||||
{
|
||||
// A prime number for the hash table size was chosen to prevent collisions.
|
||||
constexpr size_t size = 251;
|
||||
constexpr std::hash<uintptr_t> hasher;
|
||||
|
||||
static WaitTableEntry table[size];
|
||||
#pragma warning(suppress : 26446) // Prefer to use gsl::at() instead of unchecked subscript operator
|
||||
#pragma warning(suppress : 26482) // Only index into arrays using constant expressions
|
||||
#pragma warning(suppress : 26490) // Don't use reinterpret_cast
|
||||
return table[hasher(reinterpret_cast<uintptr_t>(storage)) % size];
|
||||
}
|
||||
|
||||
#pragma warning(suppress : 26429) // Symbol 'comparand' is never tested for nullness, it can be marked as not_null
|
||||
bool AreEqual(const volatile void* storage, const void* comparand, size_t size) noexcept
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
return __iso_volatile_load8(static_cast<const volatile __int8*>(storage)) == *static_cast<const __int8*>(comparand);
|
||||
case 2:
|
||||
return __iso_volatile_load16(static_cast<const volatile __int16*>(storage)) == *static_cast<const __int16*>(comparand);
|
||||
case 4:
|
||||
return __iso_volatile_load32(static_cast<const volatile __int32*>(storage)) == *static_cast<const __int32*>(comparand);
|
||||
case 8:
|
||||
return __iso_volatile_load64(static_cast<const volatile __int64*>(storage)) == *static_cast<const __int64*>(comparand);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
||||
extern "C" BOOL WINAPI WaitOnAddress(_In_reads_bytes_(AddressSize) volatile VOID* Address, _In_reads_bytes_(AddressSize) PVOID CompareAddress, _In_ SIZE_T AddressSize, _In_opt_ DWORD dwMilliseconds)
|
||||
{
|
||||
auto& entry = GetWaitTableEntry(Address);
|
||||
|
||||
SRWLockGuard guard{ entry.lock };
|
||||
GuardedWaitContext context{ Address, &entry.head };
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// NOTE: under lock to prevent lost wakes
|
||||
if (!AreEqual(Address, CompareAddress, AddressSize))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!SleepConditionVariableSRW(&context.cv, &entry.lock, dwMilliseconds, 0))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (GetLastError() != ERROR_TIMEOUT)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (dwMilliseconds != INFINITE)
|
||||
{
|
||||
// spurious wake to recheck the clock
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" VOID WINAPI WakeByAddressSingle(_In_ PVOID Address)
|
||||
{
|
||||
auto& entry = GetWaitTableEntry(Address);
|
||||
SRWLockGuard guard(entry.lock);
|
||||
|
||||
for (auto context = entry.head.next; context != &entry.head; context = context->next)
|
||||
{
|
||||
if (context->address == Address)
|
||||
{
|
||||
// Can't move wake outside SRWLOCKed section: SRWLOCK also protects the context itself
|
||||
WakeAllConditionVariable(&context->cv);
|
||||
// This break; is the difference between WakeByAddressSingle and WakeByAddressAll
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" VOID WINAPI WakeByAddressAll(_In_ PVOID Address)
|
||||
{
|
||||
auto& entry = GetWaitTableEntry(Address);
|
||||
SRWLockGuard guard(entry.lock);
|
||||
|
||||
for (auto context = entry.head.next; context != &entry.head; context = context->next)
|
||||
{
|
||||
if (context->address == Address)
|
||||
{
|
||||
// Can't move wake outside SRWLOCKed section: SRWLOCK also protects the context itself
|
||||
WakeAllConditionVariable(&context->cv);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ Module Name:
|
||||
- OutputCellView.hpp
|
||||
|
||||
Abstract:
|
||||
- Read-only view into a single cell of data that someone is attempting to write into the output buffer.
|
||||
- Read view into a single cell of data that someone is attempting to write into the output buffer.
|
||||
- This is done for performance reasons (avoid heap allocs and copies).
|
||||
|
||||
Author:
|
||||
@@ -36,6 +36,21 @@ public:
|
||||
TextAttribute TextAttr() const noexcept;
|
||||
TextAttributeBehavior TextAttrBehavior() const noexcept;
|
||||
|
||||
void UpdateText(const std::wstring_view& view) noexcept
|
||||
{
|
||||
_view = view;
|
||||
};
|
||||
|
||||
void UpdateDbcsAttribute(const DbcsAttribute& dbcsAttr) noexcept
|
||||
{
|
||||
_dbcsAttr = dbcsAttr;
|
||||
}
|
||||
|
||||
void UpdateTextAttribute(const TextAttribute& textAttr) noexcept
|
||||
{
|
||||
_textAttr = textAttr;
|
||||
}
|
||||
|
||||
bool operator==(const OutputCellView& view) const noexcept;
|
||||
bool operator!=(const OutputCellView& view) const noexcept;
|
||||
|
||||
|
||||
@@ -95,16 +95,18 @@ bool TextAttribute::IsLegacy() const noexcept
|
||||
// - defaultFgColor: the default foreground color rgb value.
|
||||
// - defaultBgColor: the default background color rgb value.
|
||||
// - reverseScreenMode: true if the screen mode is reversed.
|
||||
// - blinkingIsFaint: true if blinking should be interpreted as faint.
|
||||
// - blinkingIsFaint: true if blinking should be interpreted as faint. (defaults to false)
|
||||
// - boldIsBright: true if "bold" should be interpreted as bright. (defaults to true)
|
||||
// Return Value:
|
||||
// - the foreground and background colors that should be displayed.
|
||||
std::pair<COLORREF, COLORREF> TextAttribute::CalculateRgbColors(const gsl::span<const COLORREF> colorTable,
|
||||
const COLORREF defaultFgColor,
|
||||
const COLORREF defaultBgColor,
|
||||
const bool reverseScreenMode,
|
||||
const bool blinkingIsFaint) const noexcept
|
||||
const bool blinkingIsFaint,
|
||||
const bool boldIsBright) const noexcept
|
||||
{
|
||||
auto fg = _foreground.GetColor(colorTable, defaultFgColor, IsBold());
|
||||
auto fg = _foreground.GetColor(colorTable, defaultFgColor, boldIsBright && IsBold());
|
||||
auto bg = _background.GetColor(colorTable, defaultBgColor);
|
||||
if (IsFaint() || (IsBlinking() && blinkingIsFaint))
|
||||
{
|
||||
|
||||
@@ -68,7 +68,8 @@ public:
|
||||
const COLORREF defaultFgColor,
|
||||
const COLORREF defaultBgColor,
|
||||
const bool reverseScreenMode = false,
|
||||
const bool blinkingIsFaint = false) const noexcept;
|
||||
const bool blinkingIsFaint = false,
|
||||
const bool boldIsBright = true) const noexcept;
|
||||
|
||||
bool IsLeadingByte() const noexcept;
|
||||
bool IsTrailingByte() const noexcept;
|
||||
@@ -212,7 +213,7 @@ constexpr bool operator!=(const TextAttribute& a, const TextAttribute& b) noexce
|
||||
#ifdef UNIT_TESTING
|
||||
|
||||
#define LOG_ATTR(attr) (Log::Comment(NoThrowString().Format( \
|
||||
L#attr L"=%s", VerifyOutputTraits<TextAttribute>::ToString(attr).GetBuffer())))
|
||||
L## #attr L"=%s", VerifyOutputTraits<TextAttribute>::ToString(attr).GetBuffer())))
|
||||
|
||||
namespace WEX
|
||||
{
|
||||
|
||||
@@ -94,20 +94,93 @@ bool TextBufferCellIterator::operator!=(const TextBufferCellIterator& it) const
|
||||
// - Reference to self after movement.
|
||||
TextBufferCellIterator& TextBufferCellIterator::operator+=(const ptrdiff_t& movement)
|
||||
{
|
||||
// Note that this method is called intensively when the terminal is under heavy load.
|
||||
// We need to aggressively optimize it, comparing to the -= operator.
|
||||
ptrdiff_t move = movement;
|
||||
auto newPos = _pos;
|
||||
while (move > 0 && !_exceeded)
|
||||
if (move < 0)
|
||||
{
|
||||
_exceeded = !_bounds.IncrementInBounds(newPos);
|
||||
// Early branching to leave the rare case to -= operator.
|
||||
// This helps reducing the instruction count within this method, which is good for instruction cache.
|
||||
return *this -= -move;
|
||||
}
|
||||
|
||||
// The remaining code in this function is functionally equivalent to:
|
||||
// auto newPos = _pos;
|
||||
// while (move > 0 && !_exceeded)
|
||||
// {
|
||||
// _exceeded = !_bounds.IncrementInBounds(newPos);
|
||||
// move--;
|
||||
// }
|
||||
// _SetPos(newPos);
|
||||
//
|
||||
// _SetPos() necessitates calling _GenerateView() and thus the construction
|
||||
// of a new OutputCellView(). This has a high performance impact (ICache spill?).
|
||||
// The code below inlines _bounds.IncrementInBounds as well as SetPos.
|
||||
// In the hot path (_pos.Y doesn't change) we modify the _view directly.
|
||||
|
||||
// Hoist these integers which will be used frequently later.
|
||||
const auto boundsRightInclusive = _bounds.RightInclusive();
|
||||
const auto boundsLeft = _bounds.Left();
|
||||
const auto boundsBottomInclusive = _bounds.BottomInclusive();
|
||||
const auto boundsTop = _bounds.Top();
|
||||
const auto oldX = _pos.X;
|
||||
const auto oldY = _pos.Y;
|
||||
|
||||
// Under MSVC writing the individual members of a COORD generates worse assembly
|
||||
// compared to having them be local variables. This causes a performance impact.
|
||||
auto newX = oldX;
|
||||
auto newY = oldY;
|
||||
|
||||
while (move > 0)
|
||||
{
|
||||
if (newX == boundsRightInclusive)
|
||||
{
|
||||
newX = boundsLeft;
|
||||
newY++;
|
||||
if (newY > boundsBottomInclusive)
|
||||
{
|
||||
newY = boundsTop;
|
||||
_exceeded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newX++;
|
||||
_exceeded = false;
|
||||
}
|
||||
move--;
|
||||
}
|
||||
while (move < 0 && !_exceeded)
|
||||
|
||||
if (_exceeded)
|
||||
{
|
||||
_exceeded = !_bounds.DecrementInBounds(newPos);
|
||||
move++;
|
||||
// Early return because nothing needs to be done here.
|
||||
return *this;
|
||||
}
|
||||
_SetPos(newPos);
|
||||
return (*this);
|
||||
|
||||
if (newY == oldY)
|
||||
{
|
||||
// hot path
|
||||
const auto diff = gsl::narrow_cast<ptrdiff_t>(newX) - gsl::narrow_cast<ptrdiff_t>(oldX);
|
||||
_attrIter += diff;
|
||||
_view.UpdateTextAttribute(*_attrIter);
|
||||
|
||||
const CharRow& charRow = _pRow->GetCharRow();
|
||||
_view.UpdateText(charRow.GlyphAt(newX));
|
||||
_view.UpdateDbcsAttribute(charRow.DbcsAttrAt(newX));
|
||||
_pos.X = newX;
|
||||
}
|
||||
else
|
||||
{
|
||||
// cold path (_GenerateView is slow)
|
||||
_pRow = s_GetRow(_buffer, { newX, newY });
|
||||
_attrIter = _pRow->GetAttrRow().cbegin() + newX;
|
||||
_pos.X = newX;
|
||||
_pos.Y = newY;
|
||||
_GenerateView();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -118,7 +191,22 @@ TextBufferCellIterator& TextBufferCellIterator::operator+=(const ptrdiff_t& move
|
||||
// - Reference to self after movement.
|
||||
TextBufferCellIterator& TextBufferCellIterator::operator-=(const ptrdiff_t& movement)
|
||||
{
|
||||
return this->operator+=(-movement);
|
||||
ptrdiff_t move = movement;
|
||||
if (move < 0)
|
||||
{
|
||||
return (*this) += (-move);
|
||||
}
|
||||
|
||||
auto newPos = _pos;
|
||||
while (move > 0 && !_exceeded)
|
||||
{
|
||||
_exceeded = !_bounds.DecrementInBounds(newPos);
|
||||
move--;
|
||||
}
|
||||
_SetPos(newPos);
|
||||
|
||||
_GenerateView();
|
||||
return (*this);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -265,3 +353,8 @@ const OutputCellView* TextBufferCellIterator::operator->() const noexcept
|
||||
{
|
||||
return &_view;
|
||||
}
|
||||
|
||||
COORD TextBufferCellIterator::Pos() const noexcept
|
||||
{
|
||||
return _pos;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
const OutputCellView& operator*() const noexcept;
|
||||
const OutputCellView* operator->() const noexcept;
|
||||
|
||||
COORD Pos() const noexcept;
|
||||
|
||||
protected:
|
||||
void _SetPos(const COORD newPos);
|
||||
void _GenerateView();
|
||||
|
||||
@@ -22,6 +22,7 @@ class TextAttributeTests
|
||||
TEST_METHOD(TestTextAttributeColorGetters);
|
||||
TEST_METHOD(TestReverseDefaultColors);
|
||||
TEST_METHOD(TestRoundtripDefaultColors);
|
||||
TEST_METHOD(TestBoldAsBright);
|
||||
|
||||
static const int COLOR_TABLE_SIZE = 16;
|
||||
COLORREF _colorTable[COLOR_TABLE_SIZE];
|
||||
@@ -272,3 +273,56 @@ void TextAttributeTests::TestRoundtripDefaultColors()
|
||||
// Reset the legacy default colors to white on black.
|
||||
TextAttribute::SetLegacyDefaultAttributes(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
}
|
||||
|
||||
void TextAttributeTests::TestBoldAsBright()
|
||||
{
|
||||
const COLORREF darkBlack = _colorTable[0];
|
||||
const COLORREF brightBlack = _colorTable[8];
|
||||
const COLORREF darkGreen = _colorTable[2];
|
||||
|
||||
TextAttribute attr{};
|
||||
|
||||
// verify that calculated foreground/background are the same as the direct
|
||||
// values when not bold
|
||||
VERIFY_IS_FALSE(attr.IsBold());
|
||||
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
// with bold set, calculated foreground/background values shouldn't change for the default colors.
|
||||
attr.SetBold(true);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
attr.SetIndexedForeground(0);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
|
||||
Log::Comment(L"Foreground should be bright black when bold is bright is enabled");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
|
||||
Log::Comment(L"Foreground should be dark black when bold is bright is disabled");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
attr.SetIndexedBackground(2);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
|
||||
Log::Comment(L"background should be unaffected by 'bold is bright'");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
attr.SetBold(false);
|
||||
VERIFY_IS_FALSE(attr.IsBold());
|
||||
Log::Comment(L"when not bold, 'bold is bright' changes nothing");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
|
||||
Log::Comment(L"When set to a bright color, and bold, 'bold is bright' changes nothing");
|
||||
attr.SetBold(true);
|
||||
attr.SetIndexedForeground(8);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
}
|
||||
|
||||
@@ -140,8 +140,10 @@
|
||||
<Extensions>
|
||||
<uap7:Extension Category="windows.sharedFonts">
|
||||
<uap7:SharedFonts>
|
||||
<uap4:Font File="Cascadia.ttf" />
|
||||
<uap4:Font File="CascadiaCode.ttf" />
|
||||
<uap4:Font File="CascadiaCodeItalic.ttf" />
|
||||
<uap4:Font File="CascadiaMono.ttf" />
|
||||
<uap4:Font File="CascadiaMonoItalic.ttf" />
|
||||
</uap7:SharedFonts>
|
||||
</uap7:Extension>
|
||||
</Extensions>
|
||||
|
||||
@@ -140,8 +140,10 @@
|
||||
<Extensions>
|
||||
<uap7:Extension Category="windows.sharedFonts">
|
||||
<uap7:SharedFonts>
|
||||
<uap4:Font File="Cascadia.ttf" />
|
||||
<uap4:Font File="CascadiaCode.ttf" />
|
||||
<uap4:Font File="CascadiaCodeItalic.ttf" />
|
||||
<uap4:Font File="CascadiaMono.ttf" />
|
||||
<uap4:Font File="CascadiaMonoItalic.ttf" />
|
||||
</uap7:SharedFonts>
|
||||
</uap7:Extension>
|
||||
</Extensions>
|
||||
|
||||
@@ -12,13 +12,9 @@
|
||||
<Link>Images\%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
</Content>
|
||||
<!-- Fonts -->
|
||||
<Content Include="$(OpenConsoleDir)res\Cascadia.ttf" Condition="'$(WindowsTerminalOfficialBuild)'=='true'">
|
||||
<Content Include="$(OpenConsoleDir)res\fonts\*.ttf" Condition="'$(WindowsTerminalOfficialBuild)'=='true'">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
</Content>
|
||||
<Content Include="$(OpenConsoleDir)res\CascadiaMono.ttf" Condition="'$(WindowsTerminalOfficialBuild)'=='true'">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
<Link>%(FileName)%(Extension)</Link>
|
||||
</Content>
|
||||
<!-- Profile Icons -->
|
||||
<Content Include="$(OpenConsoleDir)src\cascadia\CascadiaPackage\ProfileIcons\**\*">
|
||||
|
||||
@@ -16,6 +16,7 @@ using namespace WEX::TestExecution;
|
||||
using namespace WEX::Common;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Microsoft::Terminal::Control;
|
||||
using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
|
||||
|
||||
namespace SettingsModelLocalTests
|
||||
{
|
||||
@@ -1970,9 +1971,9 @@ namespace SettingsModelLocalTests
|
||||
auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, settings->_globals->_actionMap->_KeyMap.size());
|
||||
VERIFY_IS_NULL(settings->_globals->_actionMap->GetActionByKeyChord({ KeyModifiers::Ctrl, static_cast<int32_t>('a') }));
|
||||
VERIFY_IS_NULL(settings->_globals->_actionMap->GetActionByKeyChord({ KeyModifiers::Ctrl, static_cast<int32_t>('b') }));
|
||||
VERIFY_IS_NULL(settings->_globals->_actionMap->GetActionByKeyChord({ KeyModifiers::Ctrl, static_cast<int32_t>('c') }));
|
||||
VERIFY_IS_NULL(settings->_globals->_actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('a') }));
|
||||
VERIFY_IS_NULL(settings->_globals->_actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('b') }));
|
||||
VERIFY_IS_NULL(settings->_globals->_actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('c') }));
|
||||
|
||||
for (const auto& warning : settings->_globals->_keybindingsWarnings)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@ using namespace winrt::Microsoft::Terminal::Control;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
using namespace WEX::Common;
|
||||
using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
|
||||
|
||||
namespace SettingsModelLocalTests
|
||||
{
|
||||
@@ -141,7 +142,7 @@ namespace SettingsModelLocalTests
|
||||
L"Try unbinding a key using `\"unbound\"` to unbind the key"));
|
||||
actionMap->LayerJson(bindings2Json);
|
||||
VERIFY_ARE_EQUAL(1u, actionMap->_KeyMap.size());
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ KeyModifiers::Ctrl, static_cast<int32_t>('c') }));
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('c') }));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Try unbinding a key using `null` to unbind the key"));
|
||||
@@ -151,7 +152,7 @@ namespace SettingsModelLocalTests
|
||||
// Then try layering in the bad setting
|
||||
actionMap->LayerJson(bindings3Json);
|
||||
VERIFY_ARE_EQUAL(1u, actionMap->_KeyMap.size());
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ KeyModifiers::Ctrl, static_cast<int32_t>('c') }));
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('c') }));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Try unbinding a key using an unrecognized command to unbind the key"));
|
||||
@@ -161,7 +162,7 @@ namespace SettingsModelLocalTests
|
||||
// Then try layering in the bad setting
|
||||
actionMap->LayerJson(bindings4Json);
|
||||
VERIFY_ARE_EQUAL(1u, actionMap->_KeyMap.size());
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ KeyModifiers::Ctrl, static_cast<int32_t>('c') }));
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('c') }));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Try unbinding a key using a straight up invalid value to unbind the key"));
|
||||
@@ -171,13 +172,13 @@ namespace SettingsModelLocalTests
|
||||
// Then try layering in the bad setting
|
||||
actionMap->LayerJson(bindings5Json);
|
||||
VERIFY_ARE_EQUAL(1u, actionMap->_KeyMap.size());
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ KeyModifiers::Ctrl, static_cast<int32_t>('c') }));
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('c') }));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Try unbinding a key that wasn't bound at all"));
|
||||
actionMap->LayerJson(bindings2Json);
|
||||
VERIFY_ARE_EQUAL(1u, actionMap->_KeyMap.size());
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ KeyModifiers::Ctrl, static_cast<int32_t>('c') }));
|
||||
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('c') }));
|
||||
}
|
||||
|
||||
void KeyBindingsTests::TestArbitraryArgs()
|
||||
@@ -676,7 +677,7 @@ namespace SettingsModelLocalTests
|
||||
actionMap->LayerJson(bindings0Json);
|
||||
VERIFY_ARE_EQUAL(1u, actionMap->_KeyMap.size());
|
||||
const auto& kbd{ actionMap->GetKeyBindingForAction(ShortcutAction::CloseWindow) };
|
||||
VerifyKeyChordEquality({ KeyModifiers::Ctrl, static_cast<int32_t>('A') }, kbd);
|
||||
VerifyKeyChordEquality({ VirtualKeyModifiers::Control, static_cast<int32_t>('A') }, kbd);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"command with args");
|
||||
@@ -687,7 +688,7 @@ namespace SettingsModelLocalTests
|
||||
args->SingleLine(true);
|
||||
|
||||
const auto& kbd{ actionMap->GetKeyBindingForAction(ShortcutAction::CopyText, *args) };
|
||||
VerifyKeyChordEquality({ KeyModifiers::Ctrl, static_cast<int32_t>('B') }, kbd);
|
||||
VerifyKeyChordEquality({ VirtualKeyModifiers::Control, static_cast<int32_t>('B') }, kbd);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"command with new terminal args");
|
||||
@@ -699,7 +700,7 @@ namespace SettingsModelLocalTests
|
||||
auto args{ winrt::make_self<implementation::NewTabArgs>(*newTerminalArgs) };
|
||||
|
||||
const auto& kbd{ actionMap->GetKeyBindingForAction(ShortcutAction::NewTab, *args) };
|
||||
VerifyKeyChordEquality({ KeyModifiers::Ctrl, static_cast<int32_t>('C') }, kbd);
|
||||
VerifyKeyChordEquality({ VirtualKeyModifiers::Control, static_cast<int32_t>('C') }, kbd);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"command with hidden args");
|
||||
@@ -707,7 +708,7 @@ namespace SettingsModelLocalTests
|
||||
VERIFY_ARE_EQUAL(4u, actionMap->_KeyMap.size());
|
||||
|
||||
const auto& kbd{ actionMap->GetKeyBindingForAction(ShortcutAction::ToggleCommandPalette) };
|
||||
VerifyKeyChordEquality({ KeyModifiers::Ctrl | KeyModifiers::Shift, static_cast<int32_t>('P') }, kbd);
|
||||
VerifyKeyChordEquality({ VirtualKeyModifiers::Control | VirtualKeyModifiers::Shift, static_cast<int32_t>('P') }, kbd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace SettingsModelLocalTests
|
||||
TEST_METHOD(ColorScheme);
|
||||
TEST_METHOD(Actions);
|
||||
TEST_METHOD(CascadiaSettings);
|
||||
TEST_METHOD(LegacyFontSettings);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
@@ -138,9 +139,11 @@ namespace SettingsModelLocalTests
|
||||
"tabTitle": "Cool Tab",
|
||||
"suppressApplicationTitle": false,
|
||||
|
||||
"fontFace": "Cascadia Mono",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "normal",
|
||||
"font": {
|
||||
"face": "Cascadia Mono",
|
||||
"size": 12,
|
||||
"weight": "normal"
|
||||
},
|
||||
"padding": "8, 8, 8, 8",
|
||||
"antialiasingMode": "grayscale",
|
||||
|
||||
@@ -253,10 +256,14 @@ namespace SettingsModelLocalTests
|
||||
])" };
|
||||
|
||||
// complex command with key chords
|
||||
const std::string actionsString4{ R"([
|
||||
const std::string actionsString4A{ R"([
|
||||
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+c" },
|
||||
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+d" }
|
||||
])" };
|
||||
const std::string actionsString4B{ R"([
|
||||
{ "command": { "action": "findMatch", "direction": "next" }, "keys": "ctrl+shift+s" },
|
||||
{ "command": { "action": "findMatch", "direction": "prev" }, "keys": "ctrl+shift+r" }
|
||||
])" };
|
||||
|
||||
// command with name and icon and multiple key chords
|
||||
const std::string actionsString5{ R"([
|
||||
@@ -369,7 +376,8 @@ namespace SettingsModelLocalTests
|
||||
RoundtripTest<implementation::ActionMap>(actionsString3);
|
||||
|
||||
Log::Comment(L"complex commands with key chords");
|
||||
RoundtripTest<implementation::ActionMap>(actionsString4);
|
||||
RoundtripTest<implementation::ActionMap>(actionsString4A);
|
||||
RoundtripTest<implementation::ActionMap>(actionsString4B);
|
||||
|
||||
Log::Comment(L"command with name and icon and multiple key chords");
|
||||
RoundtripTest<implementation::ActionMap>(actionsString5);
|
||||
@@ -402,11 +410,13 @@ namespace SettingsModelLocalTests
|
||||
|
||||
"profiles": {
|
||||
"defaults": {
|
||||
"fontFace": "Zamora Code"
|
||||
"font": {
|
||||
"face": "Zamora Code"
|
||||
}
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"fontFace": "Cascadia Code",
|
||||
"font": { "face": "Cascadia Code" },
|
||||
"guid": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||
"name": "HowettShell"
|
||||
},
|
||||
@@ -464,4 +474,35 @@ namespace SettingsModelLocalTests
|
||||
const auto result{ settings->ToJson() };
|
||||
VERIFY_ARE_EQUAL(toString(settings->_userSettings), toString(result));
|
||||
}
|
||||
|
||||
void SerializationTests::LegacyFontSettings()
|
||||
{
|
||||
const std::string profileString{ R"(
|
||||
{
|
||||
"name": "Profile with legacy font settings",
|
||||
|
||||
"fontFace": "Cascadia Mono",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "normal"
|
||||
})" };
|
||||
|
||||
const std::string expectedOutput{ R"(
|
||||
{
|
||||
"name": "Profile with legacy font settings",
|
||||
|
||||
"font": {
|
||||
"face": "Cascadia Mono",
|
||||
"size": 12,
|
||||
"weight": "normal"
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto json{ VerifyParseSucceeded(profileString) };
|
||||
const auto settings{ implementation::Profile::FromJson(json) };
|
||||
const auto result{ settings->ToJson() };
|
||||
|
||||
const auto jsonOutput{ VerifyParseSucceeded(expectedOutput) };
|
||||
|
||||
VERIFY_ARE_EQUAL(toString(jsonOutput), toString(result));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,16 +26,18 @@ public:
|
||||
static const winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs GetActionAndArgs(const winrt::Microsoft::Terminal::Settings::Model::ActionMap& actionMap,
|
||||
const winrt::Microsoft::Terminal::Control::KeyChord& kc)
|
||||
{
|
||||
using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
|
||||
|
||||
std::wstring buffer{ L"" };
|
||||
if (WI_IsFlagSet(kc.Modifiers(), winrt::Microsoft::Terminal::Control::KeyModifiers::Ctrl))
|
||||
if (WI_IsFlagSet(kc.Modifiers(), VirtualKeyModifiers::Control))
|
||||
{
|
||||
buffer += L"Ctrl+";
|
||||
}
|
||||
if (WI_IsFlagSet(kc.Modifiers(), winrt::Microsoft::Terminal::Control::KeyModifiers::Shift))
|
||||
if (WI_IsFlagSet(kc.Modifiers(), VirtualKeyModifiers::Shift))
|
||||
{
|
||||
buffer += L"Shift+";
|
||||
}
|
||||
if (WI_IsFlagSet(kc.Modifiers(), winrt::Microsoft::Terminal::Control::KeyModifiers::Alt))
|
||||
if (WI_IsFlagSet(kc.Modifiers(), VirtualKeyModifiers::Menu))
|
||||
{
|
||||
buffer += L"Alt+";
|
||||
}
|
||||
|
||||
@@ -97,6 +97,6 @@
|
||||
|
||||
<!-- We actually can just straight up reference MUX here, it's fine -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestExecutor.WinRTCore">
|
||||
<HintPath>$(OpenConsoleDir)\packages\Microsoft.Taef.10.58.210305002\lib\Microsoft.VisualStudio.TestPlatform.TestExecutor.WinRTCore.winmd</HintPath>
|
||||
<HintPath>$(OpenConsoleDir)\packages\Microsoft.Taef.10.60.210621002\lib\Microsoft.VisualStudio.TestPlatform.TestExecutor.WinRTCore.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
|
||||
<!-- This path is _relative to the .winmd_ -->
|
||||
|
||||
@@ -798,7 +798,7 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
|
||||
}
|
||||
}
|
||||
|
||||
publicTerminal->_terminal->SetCursorStyle(theme.CursorStyle);
|
||||
publicTerminal->_terminal->SetCursorStyle(static_cast<DispatchTypes::CursorStyle>(theme.CursorStyle));
|
||||
|
||||
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, { 0, fontSize }, CP_UTF8 };
|
||||
publicTerminal->_UpdateFont(newDpi);
|
||||
|
||||
@@ -19,7 +19,7 @@ typedef struct _TerminalTheme
|
||||
COLORREF DefaultForeground;
|
||||
COLORREF DefaultSelectionBackground;
|
||||
float SelectionBackgroundAlpha;
|
||||
DispatchTypes::CursorStyle CursorStyle;
|
||||
uint32_t CursorStyle; // This will be converted to DispatchTypes::CursorStyle (size_t), but C# cannot marshal an enum type and have it fit in a size_t.
|
||||
COLORREF ColorTable[16];
|
||||
} TerminalTheme, *LPTerminalTheme;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<ProjectName>PublicTerminalCore</ProjectName>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(SolutionDir)src\common.build.pre.props" />
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@@ -21,27 +20,24 @@
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\terminal\input\lib\terminalinput.vcxproj">
|
||||
<ProjectReference Include="$(SolutionDir)src\terminal\input\lib\terminalinput.vcxproj">
|
||||
<Project>{1cf55140-ef6a-4736-a403-957e4f7430bb}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\TerminalCore\lib\TerminalCore-lib.vcxproj">
|
||||
<ProjectReference Include="$(SolutionDir)src\cascadia\TerminalCore\lib\TerminalCore-lib.vcxproj">
|
||||
<Project>{ca5cad1a-abcd-429c-b551-8562ec954746}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj">
|
||||
<ProjectReference Include="$(SolutionDir)src\types\lib\types.vcxproj">
|
||||
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\buffer\out\lib\bufferout.vcxproj">
|
||||
<Project>{0cf235bd-2da0-407e-90ee-c467e8bbc714}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\renderer\base\lib\base.vcxproj">
|
||||
<ProjectReference Include="$(SolutionDir)src\renderer\base\lib\base.vcxproj">
|
||||
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\terminal\parser\lib\parser.vcxproj">
|
||||
<Project>{3ae13314-1939-4dfa-9c14-38ca0834050c}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\renderer\dx\lib\dx.vcxproj">
|
||||
<ProjectReference Include="$(SolutionDir)src\renderer\dx\lib\dx.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(SolutionDir)src\api-ms-win-core-synch-l1-2-0\api-ms-win-core-synch-l1-2-0.vcxproj">
|
||||
<Project>{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
|
||||
@@ -56,16 +56,17 @@ HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
||||
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
||||
|
||||
// Append a "\." to the given path, so that this will work in "C:\"
|
||||
auto cmdline{ wil::str_printf<std::wstring>(LR"-("%s" -d "%s\.")-", GetWtExePath().c_str(), pszName.get()) };
|
||||
auto path{ wil::str_printf<std::wstring>(LR"-(%s\.)-", pszName.get()) };
|
||||
auto cmdline{ wil::str_printf<std::wstring>(LR"-("%s" -d "%s")-", GetWtExePath().c_str(), path.c_str()) };
|
||||
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
nullptr,
|
||||
nullptr, // lpApplicationName
|
||||
cmdline.data(),
|
||||
nullptr, // lpProcessAttributes
|
||||
nullptr, // lpThreadAttributes
|
||||
false, // bInheritHandles
|
||||
EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
|
||||
nullptr, // lpEnvironment
|
||||
nullptr,
|
||||
path.data(),
|
||||
&siEx.StartupInfo, // lpStartupInfo
|
||||
&_piClient // lpProcessInformation
|
||||
));
|
||||
|
||||
@@ -46,8 +46,26 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_HandleCloseTab(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_CloseFocusedTab();
|
||||
args.Handled(true);
|
||||
if (const auto realArgs = args.ActionArgs().try_as<CloseTabArgs>())
|
||||
{
|
||||
uint32_t index;
|
||||
if (realArgs.Index())
|
||||
{
|
||||
index = realArgs.Index().Value();
|
||||
}
|
||||
else if (auto focusedTabIndex = _GetFocusedTabIndex())
|
||||
{
|
||||
index = *focusedTabIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Handled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
_CloseTabAtIndex(index);
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleClosePane(const IInspectable& /*sender*/,
|
||||
@@ -239,12 +257,12 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (args == nullptr)
|
||||
{
|
||||
_OpenNewTab(nullptr);
|
||||
LOG_IF_FAILED(_OpenNewTab(nullptr));
|
||||
args.Handled(true);
|
||||
}
|
||||
else if (const auto& realArgs = args.ActionArgs().try_as<NewTabArgs>())
|
||||
{
|
||||
_OpenNewTab(realArgs.TerminalArgs());
|
||||
LOG_IF_FAILED(_OpenNewTab(realArgs.TerminalArgs()));
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
@@ -289,8 +307,11 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
_MoveFocus(realArgs.FocusDirection());
|
||||
args.Handled(true);
|
||||
// Mark as handled only when the move succeeded (e.g. when there
|
||||
// is a pane to move to), otherwise mark as unhandled so the
|
||||
// keychord can propagate to the terminal (GH#6129)
|
||||
const auto moveSucceeded = _MoveFocus(realArgs.FocusDirection());
|
||||
args.Handled(moveSucceeded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,9 +189,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
AppLogic::AppLogic() :
|
||||
_dialogLock{},
|
||||
_loadedInitialSettings{ false },
|
||||
_settingsLoadedResult{ S_OK }
|
||||
_reloadState{ std::chrono::milliseconds(100), []() { ApplicationState::SharedInstance().Reload(); } }
|
||||
{
|
||||
// For your own sanity, it's better to do setup outside the ctor.
|
||||
// If you do any setup in the ctor that ends up throwing an exception,
|
||||
@@ -204,6 +202,13 @@ namespace winrt::TerminalApp::implementation
|
||||
// SetTitleBarContent
|
||||
_isElevated = _isUserAdmin();
|
||||
_root = winrt::make_self<TerminalPage>();
|
||||
|
||||
_reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(_root->Dispatcher(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() {
|
||||
if (auto self{ weakSelf.get() })
|
||||
{
|
||||
self->_ReloadSettings();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -859,59 +864,29 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void AppLogic::_RegisterSettingsChange()
|
||||
{
|
||||
// Get the containing folder.
|
||||
const std::filesystem::path settingsPath{ std::wstring_view{ CascadiaSettings::SettingsPath() } };
|
||||
const auto folder = settingsPath.parent_path();
|
||||
const std::filesystem::path statePath{ std::wstring_view{ ApplicationState::SharedInstance().FilePath() } };
|
||||
|
||||
_reader.create(folder.c_str(),
|
||||
false,
|
||||
wil::FolderChangeEvents::All,
|
||||
[this, settingsPath](wil::FolderChangeEvent event, PCWSTR fileModified) {
|
||||
// We want file modifications, AND when files are renamed to be
|
||||
// settings.json. This second case will oftentimes happen with text
|
||||
// editors, who will write a temp file, then rename it to be the
|
||||
// actual file you wrote. So listen for that too.
|
||||
if (!(event == wil::FolderChangeEvent::Modified ||
|
||||
event == wil::FolderChangeEvent::RenameNewName ||
|
||||
event == wil::FolderChangeEvent::Removed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_reader.create(
|
||||
settingsPath.parent_path().c_str(),
|
||||
false,
|
||||
// We want file modifications, AND when files are renamed to be
|
||||
// settings.json. This second case will oftentimes happen with text
|
||||
// editors, who will write a temp file, then rename it to be the
|
||||
// actual file you wrote. So listen for that too.
|
||||
wil::FolderChangeEvents::FileName | wil::FolderChangeEvents::LastWriteTime,
|
||||
[this, settingsBasename = settingsPath.filename(), stateBasename = statePath.filename()](wil::FolderChangeEvent, PCWSTR fileModified) {
|
||||
const auto modifiedBasename = std::filesystem::path{ fileModified }.filename();
|
||||
|
||||
std::filesystem::path modifiedFilePath = fileModified;
|
||||
|
||||
// Getting basename (filename.ext)
|
||||
const auto settingsBasename = settingsPath.filename();
|
||||
const auto modifiedBasename = modifiedFilePath.filename();
|
||||
|
||||
if (settingsBasename == modifiedBasename)
|
||||
{
|
||||
this->_DispatchReloadSettings();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Dispatches a settings reload with debounce.
|
||||
// Text editors implement Save in a bunch of different ways, so
|
||||
// this stops us from reloading too many times or too quickly.
|
||||
fire_and_forget AppLogic::_DispatchReloadSettings()
|
||||
{
|
||||
if (_settingsReloadQueued.exchange(true))
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
auto weakSelf = get_weak();
|
||||
|
||||
co_await winrt::resume_after(std::chrono::milliseconds(100));
|
||||
co_await winrt::resume_foreground(_root->Dispatcher());
|
||||
|
||||
if (auto self{ weakSelf.get() })
|
||||
{
|
||||
_ReloadSettings();
|
||||
_settingsReloadQueued.store(false);
|
||||
}
|
||||
if (modifiedBasename == settingsBasename)
|
||||
{
|
||||
_reloadSettings->Run();
|
||||
}
|
||||
else if (modifiedBasename == stateBasename)
|
||||
{
|
||||
_reloadState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AppLogic::_ApplyLanguageSettingChange() noexcept
|
||||
@@ -1254,6 +1229,11 @@ namespace winrt::TerminalApp::implementation
|
||||
auto actions = winrt::single_threaded_vector<ActionAndArgs>(std::move(appArgs.GetStartupActions()));
|
||||
|
||||
_root->ProcessStartupActions(actions, false, cwd);
|
||||
|
||||
if (appArgs.IsHandoffListener())
|
||||
{
|
||||
_root->SetInboundListener(true);
|
||||
}
|
||||
}
|
||||
// Return the result of parsing with commandline, though it may or may not be used.
|
||||
return result;
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include "FindTargetWindowResult.g.h"
|
||||
#include "TerminalPage.h"
|
||||
#include "Jumplist.h"
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
#include <inc/cppwinrt_utils.h>
|
||||
#include <ThrottledFunc.h>
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
// fwdecl unittest classes
|
||||
@@ -111,17 +113,15 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
|
||||
|
||||
HRESULT _settingsLoadedResult;
|
||||
winrt::hstring _settingsLoadExceptionText{};
|
||||
|
||||
bool _loadedInitialSettings;
|
||||
|
||||
wil::unique_folder_change_reader_nothrow _reader;
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _reloadSettings;
|
||||
til::throttled_func_trailing<> _reloadState;
|
||||
winrt::hstring _settingsLoadExceptionText;
|
||||
HRESULT _settingsLoadedResult = S_OK;
|
||||
bool _loadedInitialSettings = false;
|
||||
|
||||
std::shared_mutex _dialogLock;
|
||||
|
||||
std::atomic<bool> _settingsReloadQueued{ false };
|
||||
|
||||
::TerminalApp::AppCommandlineArgs _appArgs;
|
||||
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
|
||||
static TerminalApp::FindTargetWindowResult _doFindTargetWindow(winrt::array_view<const hstring> args,
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - existingConnection: An optional connection that is already established to a PTY
|
||||
// for this tab to host instead of creating one.
|
||||
// If not defined, the tab will create the connection.
|
||||
void TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection)
|
||||
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection)
|
||||
try
|
||||
{
|
||||
const auto profileGuid{ _settings.GetProfileForArgs(newTerminalArgs) };
|
||||
@@ -89,8 +89,10 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_LOG();
|
||||
CATCH_RETURN();
|
||||
|
||||
// Method Description:
|
||||
// - Creates a new tab with the given settings. If the tab bar is not being
|
||||
@@ -105,6 +107,14 @@ namespace winrt::TerminalApp::implementation
|
||||
// Create a connection based on the values in our settings object if we weren't given one.
|
||||
auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profileGuid, settings.DefaultSettings());
|
||||
|
||||
// If we had an `existingConnection`, then this is an inbound handoff from somewhere else.
|
||||
// We need to tell it about our size information so it can match the dimensions of what
|
||||
// we are about to present.
|
||||
if (existingConnection)
|
||||
{
|
||||
connection.Resize(settings.DefaultSettings().InitialRows(), settings.DefaultSettings().InitialCols());
|
||||
}
|
||||
|
||||
TerminalConnection::ITerminalConnection debugConnection{ nullptr };
|
||||
if (_settings.GlobalSettings().DebugFeaturesEnabled())
|
||||
{
|
||||
@@ -617,17 +627,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Close the currently focused tab. Focus will move to the left, if possible.
|
||||
void TerminalPage::_CloseFocusedTab()
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
{
|
||||
auto tab{ _tabs.GetAt(*index) };
|
||||
_HandleCloseTabRequested(tab);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -675,6 +674,20 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Close the tab at the given index.
|
||||
void TerminalPage::_CloseTabAtIndex(uint32_t index)
|
||||
{
|
||||
if (index >= _tabs.Size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (auto tab{ _tabs.GetAt(index) })
|
||||
{
|
||||
_HandleCloseTabRequested(tab);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Closes provided tabs one by one
|
||||
// Arguments:
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
<ClCompile>
|
||||
@@ -372,13 +372,13 @@
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.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('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "RenameWindowRequestedArgs.g.cpp"
|
||||
#include "../inc/WindowingBehavior.h"
|
||||
|
||||
#include <til/latch.h>
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
@@ -41,6 +43,7 @@ namespace winrt
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
namespace WUX = Windows::UI::Xaml;
|
||||
using IInspectable = Windows::Foundation::IInspectable;
|
||||
using VirtualKeyModifiers = Windows::System::VirtualKeyModifiers;
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
@@ -203,7 +206,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
page->_OpenNewTab(nullptr);
|
||||
LOG_IF_FAILED(page->_OpenNewTab(nullptr));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -343,34 +346,12 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::StartInboundListener();
|
||||
}
|
||||
// If we failed to start the listener, it will throw.
|
||||
// We should fail fast here or the Terminal will be in a very strange state.
|
||||
// We only start the listener if the Terminal was started with the COM server
|
||||
// `-Embedding` flag and we make no tabs as a result.
|
||||
// Therefore, if the listener cannot start itself up to make that tab with
|
||||
// the inbound connection that caused the COM activation in the first place...
|
||||
// we would be left with an empty terminal frame with no tabs.
|
||||
// Instead, crash out so COM sees the server die and things unwind
|
||||
// without a weird empty frame window.
|
||||
// We don't want to fail fast here because if a peasant has some trouble with
|
||||
// starting the listener, we don't want it to crash and take all its tabs down
|
||||
// with it.
|
||||
catch (...)
|
||||
{
|
||||
// However, we cannot always fail fast because of MSFT:33501832. Sometimes the COM catalog
|
||||
// tears the state between old and new versions and fails here for that reason.
|
||||
// As we're always becoming an inbound server in the monarch, even when COM didn't strictly
|
||||
// ask us yet...we might just crash always.
|
||||
// Instead... we're going to differentiate. If COM started us... we will fail fast
|
||||
// so it sees the process die and falls back.
|
||||
// If we were just starting normally as a Monarch and opportunistically listening for
|
||||
// inbound connections... then we'll just log the failure and move on assuming
|
||||
// the version state is torn and will fix itself whenever the packaging upgrade
|
||||
// tasks decide to clean up.
|
||||
if (_isEmbeddingInboundListener)
|
||||
{
|
||||
FAIL_FAST_CAUGHT_EXCEPTION();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,6 +415,14 @@ namespace winrt::TerminalApp::implementation
|
||||
co_return;
|
||||
}
|
||||
}
|
||||
|
||||
// GH#6586: now that we're done processing all startup commands,
|
||||
// focus the active control. This will work as expected for both
|
||||
// commandline invocations and for `wt` action invocations.
|
||||
if (const auto control = _GetActiveControl())
|
||||
{
|
||||
control.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
if (initial)
|
||||
{
|
||||
@@ -656,7 +645,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
page->_OpenNewTab(newTerminalArgs);
|
||||
LOG_IF_FAILED(page->_OpenNewTab(newTerminalArgs));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1100,14 +1089,16 @@ namespace winrt::TerminalApp::implementation
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_MoveFocus(const FocusDirection& direction)
|
||||
// - Whether changing the focus succeeded. This allows a keychord to propagate
|
||||
// to the terminal when no other panes are present (GH#6219)
|
||||
bool TerminalPage::_MoveFocus(const FocusDirection& direction)
|
||||
{
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
_UnZoomIfNeeded();
|
||||
terminalTab->NavigateFocus(direction);
|
||||
return terminalTab->NavigateFocus(direction);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TermControl TerminalPage::_GetActiveControl()
|
||||
@@ -1265,6 +1256,14 @@ namespace winrt::TerminalApp::implementation
|
||||
_UnZoomIfNeeded();
|
||||
|
||||
focusedTab->SplitPane(realSplitType, splitSize, realGuid, newControl);
|
||||
|
||||
// After GH#6586, the control will no longer focus itself
|
||||
// automatically when it's finished being laid out. Manually focus
|
||||
// the control here instead.
|
||||
if (_startupState == StartupState::Initialized)
|
||||
{
|
||||
_GetActiveControl().Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -1348,26 +1347,26 @@ namespace winrt::TerminalApp::implementation
|
||||
// Return Value:
|
||||
// - a string representation of the key modifiers for the shortcut
|
||||
//NOTE: This needs to be localized with https://github.com/microsoft/terminal/issues/794 if XAML framework issue not resolved before then
|
||||
static std::wstring _FormatOverrideShortcutText(KeyModifiers modifiers)
|
||||
static std::wstring _FormatOverrideShortcutText(VirtualKeyModifiers modifiers)
|
||||
{
|
||||
std::wstring buffer{ L"" };
|
||||
|
||||
if (WI_IsFlagSet(modifiers, KeyModifiers::Ctrl))
|
||||
if (WI_IsFlagSet(modifiers, VirtualKeyModifiers::Control))
|
||||
{
|
||||
buffer += L"Ctrl+";
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(modifiers, KeyModifiers::Shift))
|
||||
if (WI_IsFlagSet(modifiers, VirtualKeyModifiers::Shift))
|
||||
{
|
||||
buffer += L"Shift+";
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(modifiers, KeyModifiers::Alt))
|
||||
if (WI_IsFlagSet(modifiers, VirtualKeyModifiers::Menu))
|
||||
{
|
||||
buffer += L"Alt+";
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(modifiers, KeyModifiers::Windows))
|
||||
if (WI_IsFlagSet(modifiers, VirtualKeyModifiers::Windows))
|
||||
{
|
||||
buffer += L"Win+";
|
||||
}
|
||||
@@ -1393,11 +1392,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// TODO: Modify this when https://github.com/microsoft/terminal/issues/877 is resolved
|
||||
menuShortcut.Key(static_cast<Windows::System::VirtualKey>(keyChord.Vkey()));
|
||||
|
||||
// inspect the modifiers from the KeyChord and set the flags int he XAML value
|
||||
auto modifiers = ActionMap::ConvertVKModifiers(keyChord.Modifiers());
|
||||
|
||||
// add the modifiers to the shortcut
|
||||
menuShortcut.Modifiers(modifiers);
|
||||
menuShortcut.Modifiers(keyChord.Modifiers());
|
||||
|
||||
// add to the menu
|
||||
menuItem.KeyboardAccelerators().Append(menuShortcut);
|
||||
@@ -2327,13 +2323,38 @@ namespace winrt::TerminalApp::implementation
|
||||
return _isAlwaysOnTop;
|
||||
}
|
||||
|
||||
void TerminalPage::_OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection)
|
||||
HRESULT TerminalPage::_OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection)
|
||||
{
|
||||
// TODO: GH 9458 will give us more context so we can try to choose a better profile.
|
||||
_OpenNewTab(nullptr, connection);
|
||||
// We need to be on the UI thread in order for _OpenNewTab to run successfully.
|
||||
// HasThreadAccess will return true if we're currently on a UI thread and false otherwise.
|
||||
// When we're on a COM thread, we'll need to dispatch the calls to the UI thread
|
||||
// and wait on it hence the locking mechanism.
|
||||
if (Dispatcher().HasThreadAccess())
|
||||
{
|
||||
// TODO: GH 9458 will give us more context so we can try to choose a better profile.
|
||||
auto hr = _OpenNewTab(nullptr, connection);
|
||||
|
||||
// Request a summon of this window to the foreground
|
||||
_SummonWindowRequestedHandlers(*this, nullptr);
|
||||
// Request a summon of this window to the foreground
|
||||
_SummonWindowRequestedHandlers(*this, nullptr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
else
|
||||
{
|
||||
til::latch latch{ 1 };
|
||||
HRESULT finalVal = S_OK;
|
||||
|
||||
Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [&]() {
|
||||
finalVal = _OpenNewTab(nullptr, connection);
|
||||
|
||||
_SummonWindowRequestedHandlers(*this, nullptr);
|
||||
|
||||
latch.count_down();
|
||||
});
|
||||
|
||||
latch.wait();
|
||||
return finalVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -186,7 +186,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _CreateNewTabFlyout();
|
||||
void _OpenNewTabDropdown();
|
||||
void _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
void _CreateNewTabFromSettings(GUID profileGuid, const Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(GUID profileGuid, Microsoft::Terminal::Settings::Model::TerminalSettings settings);
|
||||
|
||||
@@ -216,6 +216,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void _DuplicateTab(const TerminalTab& tab);
|
||||
|
||||
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::TabBase tab);
|
||||
void _CloseTabAtIndex(uint32_t index);
|
||||
void _RemoveTab(const winrt::TerminalApp::TabBase& tab);
|
||||
winrt::fire_and_forget _RemoveTabs(const std::vector<winrt::TerminalApp::TabBase> tabs);
|
||||
|
||||
@@ -229,7 +230,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _SelectNextTab(const bool bMoveRight, const Windows::Foundation::IReference<Microsoft::Terminal::Settings::Model::TabSwitcherMode>& customTabSwitcherMode);
|
||||
bool _SelectTab(const uint32_t tabIndex);
|
||||
void _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
|
||||
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl();
|
||||
std::optional<uint32_t> _GetFocusedTabIndex() const noexcept;
|
||||
@@ -238,7 +239,6 @@ namespace winrt::TerminalApp::implementation
|
||||
TerminalApp::TabBase _GetTabByTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept;
|
||||
|
||||
winrt::fire_and_forget _SetFocusedTab(const winrt::TerminalApp::TabBase tab);
|
||||
void _CloseFocusedTab();
|
||||
winrt::fire_and_forget _CloseFocusedPane();
|
||||
|
||||
winrt::fire_and_forget _RemoveOnCloseRoutine(Microsoft::UI::Xaml::Controls::TabViewItem tabViewItem, winrt::com_ptr<TerminalPage> page);
|
||||
@@ -331,7 +331,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Microsoft::Terminal::Settings::Model::Command _lastPreviewedCommand{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Model::TerminalSettings _originalSettings{ nullptr };
|
||||
|
||||
void _OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||
HRESULT _OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||
void _HandleToggleInboundPty(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
|
||||
void _WindowRenamerActionClick(const IInspectable& sender, const IInspectable& eventArgs);
|
||||
|
||||
@@ -481,19 +481,24 @@ namespace winrt::TerminalApp::implementation
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::NavigateFocus(const FocusDirection& direction)
|
||||
// - Whether changing the focus succeeded. This allows a keychord to propagate
|
||||
// to the terminal when no other panes are present (GH#6219)
|
||||
bool TerminalTab::NavigateFocus(const FocusDirection& direction)
|
||||
{
|
||||
if (direction == FocusDirection::Previous)
|
||||
{
|
||||
if (_mruPanes.size() < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// To get to the previous pane, get the id of the previous pane and focus to that
|
||||
_rootPane->FocusPane(_mruPanes.at(1));
|
||||
return _rootPane->FocusPane(_mruPanes.at(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: This _must_ be called on the root pane, so that it can propagate
|
||||
// throughout the entire tree.
|
||||
_rootPane->NavigateFocus(direction);
|
||||
return _rootPane->NavigateFocus(direction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
|
||||
void ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
|
||||
void NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool FocusPane(const uint32_t id);
|
||||
|
||||
void UpdateSettings(const Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, const GUID& profile);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<!-- ========================= XAML files ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- DON'T PUT XAML FILES HERE! Put them in TerminalAppLib.vcxproj -->
|
||||
@@ -90,13 +90,13 @@
|
||||
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.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('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.2" targetFramework="native" />
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -11,6 +11,8 @@ using namespace Microsoft::WRL;
|
||||
static NewHandoffFunction _pfnHandoff = nullptr;
|
||||
// The registration ID of the class object for clean up later
|
||||
static DWORD g_cTerminalHandoffRegistration = 0;
|
||||
// Mutex so we only do start/stop/establish one at a time.
|
||||
static std::shared_mutex _mtx;
|
||||
|
||||
// Routine Description:
|
||||
// - Starts listening for TerminalHandoff requests by registering
|
||||
@@ -19,9 +21,11 @@ static DWORD g_cTerminalHandoffRegistration = 0;
|
||||
// - pfnHandoff - Function to callback when a handoff is received
|
||||
// Return Value:
|
||||
// - S_OK, E_NOT_VALID_STATE (start called when already started) or relevant COM registration error.
|
||||
HRESULT CTerminalHandoff::s_StartListening(NewHandoffFunction pfnHandoff) noexcept
|
||||
HRESULT CTerminalHandoff::s_StartListening(NewHandoffFunction pfnHandoff)
|
||||
try
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
|
||||
RETURN_HR_IF(E_NOT_VALID_STATE, _pfnHandoff != nullptr);
|
||||
|
||||
const auto classFactory = Make<SimpleClassFactory<CTerminalHandoff>>();
|
||||
@@ -31,7 +35,7 @@ try
|
||||
ComPtr<IUnknown> unk;
|
||||
RETURN_IF_FAILED(classFactory.As(&unk));
|
||||
|
||||
RETURN_IF_FAILED(CoRegisterClassObject(__uuidof(CTerminalHandoff), unk.Get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &g_cTerminalHandoffRegistration));
|
||||
RETURN_IF_FAILED(CoRegisterClassObject(__uuidof(CTerminalHandoff), unk.Get(), CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &g_cTerminalHandoffRegistration));
|
||||
|
||||
_pfnHandoff = pfnHandoff;
|
||||
|
||||
@@ -46,8 +50,10 @@ CATCH_RETURN()
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK, E_NOT_VALID_STATE (stop called when not started), or relevant COM class revoke error
|
||||
HRESULT CTerminalHandoff::s_StopListening() noexcept
|
||||
HRESULT CTerminalHandoff::s_StopListening()
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
|
||||
_pfnHandoff = nullptr;
|
||||
@@ -91,10 +97,19 @@ static HRESULT _duplicateHandle(const HANDLE in, HANDLE& out) noexcept
|
||||
// - E_NOT_VALID_STATE if a event handler is not registered before calling. `::DuplicateHandle`
|
||||
// error codes if we cannot manage to make our own copy of handles to retain. Or S_OK/error
|
||||
// from the registered handler event function.
|
||||
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept
|
||||
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client)
|
||||
{
|
||||
// Stash a local copy of _pfnHandoff before we stop listening.
|
||||
auto localPfnHandoff = _pfnHandoff;
|
||||
|
||||
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
|
||||
// COM does not automatically clean that up for us. We must do it.
|
||||
s_StopListening();
|
||||
|
||||
std::unique_lock lock{ _mtx };
|
||||
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
|
||||
|
||||
// Duplicate the handles from what we received.
|
||||
// The contract with COM specifies that any HANDLEs we receive from the caller belong
|
||||
@@ -108,5 +123,5 @@ HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE sign
|
||||
RETURN_IF_FAILED(_duplicateHandle(client, client));
|
||||
|
||||
// Call registered handler from when we started listening.
|
||||
return _pfnHandoff(in, out, signal, ref, server, client);
|
||||
return localPfnHandoff(in, out, signal, ref, server, client);
|
||||
}
|
||||
|
||||
@@ -37,12 +37,12 @@ struct __declspec(uuid(__CLSID_CTerminalHandoff))
|
||||
HANDLE signal,
|
||||
HANDLE ref,
|
||||
HANDLE server,
|
||||
HANDLE client) noexcept override;
|
||||
HANDLE client) override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff) noexcept;
|
||||
static HRESULT s_StopListening() noexcept;
|
||||
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff);
|
||||
static HRESULT s_StopListening();
|
||||
};
|
||||
|
||||
// Disable warnings from the CoCreatableClass macro as the value it provides for
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "ConptyConnection.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <userenv.h>
|
||||
|
||||
#include "ConptyConnection.g.cpp"
|
||||
#include "CTerminalHandoff.h"
|
||||
@@ -95,11 +94,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
environment.clear();
|
||||
});
|
||||
|
||||
{
|
||||
const auto newEnvironmentBlock{ Utils::CreateEnvironmentBlock() };
|
||||
// Populate the environment map with the current environment.
|
||||
RETURN_IF_FAILED(Utils::UpdateEnvironmentMapW(environment, newEnvironmentBlock.get()));
|
||||
}
|
||||
// Populate the environment map with the current environment.
|
||||
RETURN_IF_FAILED(Utils::UpdateEnvironmentMapW(environment));
|
||||
|
||||
{
|
||||
// Convert connection Guid to string and ignore the enclosing '{}'.
|
||||
@@ -253,12 +249,21 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
{
|
||||
_transitionToState(ConnectionState::Connecting);
|
||||
|
||||
const COORD dimensions{ gsl::narrow_cast<SHORT>(_initialCols), gsl::narrow_cast<SHORT>(_initialRows) };
|
||||
|
||||
// If we do not have pipes already, then this is a fresh connection... not an inbound one that is a received
|
||||
// handoff from an already-started PTY process.
|
||||
if (!_inPipe)
|
||||
{
|
||||
const COORD dimensions{ gsl::narrow_cast<SHORT>(_initialCols), gsl::narrow_cast<SHORT>(_initialRows) };
|
||||
THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(dimensions, PSEUDOCONSOLE_RESIZE_QUIRK | PSEUDOCONSOLE_WIN32_INPUT_MODE, &_inPipe, &_outPipe, &_hPC));
|
||||
THROW_IF_FAILED(_LaunchAttachedClient());
|
||||
}
|
||||
// But if it was an inbound handoff... attempt to synchronize the size of it with what our connection
|
||||
// window is expecting it to be on the first layout.
|
||||
else
|
||||
{
|
||||
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), dimensions));
|
||||
}
|
||||
|
||||
_startTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
@@ -387,11 +392,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
void ConptyConnection::Resize(uint32_t rows, uint32_t columns)
|
||||
{
|
||||
if (!_hPC)
|
||||
// If we haven't started connecting at all, it's still fair to update
|
||||
// the initial rows and columns before we set things up.
|
||||
if (!_isStateAtOrBeyond(ConnectionState::Connecting))
|
||||
{
|
||||
_initialRows = rows;
|
||||
_initialCols = columns;
|
||||
}
|
||||
// Otherwise, we can really only dispatch a resize if we're already connected.
|
||||
else if (_isConnected())
|
||||
{
|
||||
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), { Utils::ClampToShortMax(columns, 1), Utils::ClampToShortMax(rows, 1) }));
|
||||
|
||||
@@ -94,6 +94,32 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto pfnTerminalTaskbarProgressChanged = std::bind(&ControlCore::_terminalTaskbarProgressChanged, this);
|
||||
_terminal->TaskbarProgressChangedCallback(pfnTerminalTaskbarProgressChanged);
|
||||
|
||||
// MSFT 33353327: Initialize the renderer in the ctor instead of Initialize().
|
||||
// We need the renderer to be ready to accept new engines before the SwapChainPanel is ready to go.
|
||||
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
|
||||
// the UIA Engine to the renderer. This prevents us from signaling changes to the cursor or buffer.
|
||||
{
|
||||
// First create the render thread.
|
||||
// Then stash a local pointer to the render thread so we can initialize it and enable it
|
||||
// to paint itself *after* we hand off its ownership to the renderer.
|
||||
// We split up construction and initialization of the render thread object this way
|
||||
// because the renderer and render thread have circular references to each other.
|
||||
auto renderThread = std::make_unique<::Microsoft::Console::Render::RenderThread>();
|
||||
auto* const localPointerToThread = renderThread.get();
|
||||
|
||||
// Now create the renderer and initialize the render thread.
|
||||
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(_terminal.get(), nullptr, 0, std::move(renderThread));
|
||||
|
||||
_renderer->SetRendererEnteredErrorStateCallback([weakThis = get_weak()]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
strongThis->_RendererEnteredErrorStateHandlers(*strongThis, nullptr);
|
||||
}
|
||||
});
|
||||
|
||||
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
}
|
||||
|
||||
UpdateSettings(settings);
|
||||
}
|
||||
|
||||
@@ -131,27 +157,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return false;
|
||||
}
|
||||
|
||||
// First create the render thread.
|
||||
// Then stash a local pointer to the render thread so we can initialize it and enable it
|
||||
// to paint itself *after* we hand off its ownership to the renderer.
|
||||
// We split up construction and initialization of the render thread object this way
|
||||
// because the renderer and render thread have circular references to each other.
|
||||
auto renderThread = std::make_unique<::Microsoft::Console::Render::RenderThread>();
|
||||
auto* const localPointerToThread = renderThread.get();
|
||||
|
||||
// Now create the renderer and initialize the render thread.
|
||||
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(_terminal.get(), nullptr, 0, std::move(renderThread));
|
||||
::Microsoft::Console::Render::IRenderTarget& renderTarget = *_renderer;
|
||||
|
||||
_renderer->SetRendererEnteredErrorStateCallback([weakThis = get_weak()]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
strongThis->_RendererEnteredErrorStateHandlers(*strongThis, nullptr);
|
||||
}
|
||||
});
|
||||
|
||||
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
|
||||
// Set up the DX Engine
|
||||
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
|
||||
_renderer->AddRenderEngine(dxEngine.get());
|
||||
@@ -182,7 +187,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_settings.InitialCols(width);
|
||||
_settings.InitialRows(height);
|
||||
|
||||
_terminal->CreateFromSettings(_settings, renderTarget);
|
||||
_terminal->CreateFromSettings(_settings, *_renderer);
|
||||
|
||||
// IMPORTANT! Set this callback up sooner than later. If we do it
|
||||
// after Enable, then it'll be possible to paint the frame once
|
||||
@@ -198,6 +203,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
dxEngine->SetPixelShaderPath(_settings.PixelShaderPath());
|
||||
dxEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
||||
dxEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
dxEngine->SetIntenseIsBold(_settings.IntenseIsBold());
|
||||
|
||||
_updateAntiAliasingMode(dxEngine.get());
|
||||
|
||||
@@ -526,6 +532,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
||||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
|
||||
_updateAntiAliasingMode(_renderEngine.get());
|
||||
|
||||
// Refresh our font with the renderer
|
||||
@@ -555,6 +562,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_renderEngine->SetSelectionBackground(til::color{ newAppearance.SelectionBackground() });
|
||||
_renderEngine->SetRetroTerminalEffect(newAppearance.RetroTerminalEffect());
|
||||
_renderEngine->SetPixelShaderPath(newAppearance.PixelShaderPath());
|
||||
_renderEngine->SetIntenseIsBold(_settings.IntenseIsBold());
|
||||
_renderer->TriggerRedrawAll();
|
||||
}
|
||||
}
|
||||
@@ -592,6 +600,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const int newDpi = static_cast<int>(static_cast<double>(USER_DEFAULT_SCREEN_DPI) *
|
||||
_compositionScale);
|
||||
|
||||
_terminal->SetFontInfo(_actualFont);
|
||||
|
||||
// TODO: MSFT:20895307 If the font doesn't exist, this doesn't
|
||||
// actually fail. We need a way to gracefully fallback.
|
||||
_renderer->TriggerFontChange(newDpi, _desiredFont, _actualFont);
|
||||
@@ -703,6 +713,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert our new dimensions to characters
|
||||
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 },
|
||||
{ static_cast<short>(size.cx), static_cast<short>(size.cy) });
|
||||
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
|
||||
const auto currentVP = _terminal->GetViewport();
|
||||
|
||||
// Don't actually resize if viewport dimensions didn't change
|
||||
if (vp.Height() == currentVP.Height() && vp.Width() == currentVP.Width())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_terminal->ClearSelection();
|
||||
|
||||
// Tell the dx engine that our window is now the new size.
|
||||
@@ -711,11 +733,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Invalidate everything
|
||||
_renderer->TriggerRedrawAll();
|
||||
|
||||
// Convert our new dimensions to characters
|
||||
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 },
|
||||
{ static_cast<short>(size.cx), static_cast<short>(size.cy) });
|
||||
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
|
||||
|
||||
// If this function succeeds with S_FALSE, then the terminal didn't
|
||||
// actually change size. No need to notify the connection of this no-op.
|
||||
const HRESULT hr = _terminal->UserResize({ vp.Width(), vp.Height() });
|
||||
@@ -885,6 +902,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
_terminal->WritePastedText(hstr);
|
||||
_terminal->ClearSelection();
|
||||
_renderer->TriggerSelection();
|
||||
_terminal->TrySnapOnInput();
|
||||
}
|
||||
|
||||
@@ -1313,10 +1331,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ControlCore::AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
|
||||
{
|
||||
if (_renderer)
|
||||
{
|
||||
_renderer->AddRenderEngine(pEngine);
|
||||
}
|
||||
_renderer->AddRenderEngine(pEngine);
|
||||
}
|
||||
|
||||
bool ControlCore::IsInReadOnlyMode() const
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "../buffer/out/search.h"
|
||||
#include "cppwinrt_utils.h"
|
||||
#include "ThrottledFunc.h"
|
||||
|
||||
namespace ControlUnitTests
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ static constexpr unsigned int MAX_CLICK_COUNT = 3;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
ControlInteractivity::ControlInteractivity(IControlSettings settings,
|
||||
ControlInteractivity::ControlInteractivity(IControlSettings settings,
|
||||
TerminalConnection::ITerminalConnection connection) :
|
||||
_touchAnchor{ std::nullopt },
|
||||
_lastMouseClickTimestamp{},
|
||||
@@ -182,7 +182,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
else if (_canSendVTMouseInput(modifiers))
|
||||
{
|
||||
_core->SendMouseEvent(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
|
||||
_sendMouseEventHelper(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
|
||||
}
|
||||
else if (buttonState.isLeftButtonDown)
|
||||
{
|
||||
@@ -249,7 +249,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (focused && !_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
{
|
||||
_core->SendMouseEvent(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
|
||||
_sendMouseEventHelper(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
|
||||
}
|
||||
else if (focused && buttonState.isLeftButtonDown)
|
||||
{
|
||||
@@ -328,7 +328,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (!_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
{
|
||||
_core->SendMouseEvent(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
|
||||
_sendMouseEventHelper(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// here with a PointerPoint. However, as of #979, we don't have a
|
||||
// PointerPoint to work with. So, we're just going to do a
|
||||
// mousewheel event manually
|
||||
return _core->SendMouseEvent(terminalPosition,
|
||||
return _sendMouseEventHelper(terminalPosition,
|
||||
WM_MOUSEWHEEL,
|
||||
modifiers,
|
||||
::base::saturated_cast<short>(delta),
|
||||
@@ -557,4 +557,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Convert the location in pixels to characters within the current viewport.
|
||||
return til::point{ pixelPosition / fontSize };
|
||||
}
|
||||
|
||||
bool ControlInteractivity::_sendMouseEventHelper(const til::point terminalPosition,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const SHORT wheelDelta,
|
||||
TerminalInput::MouseButtonState buttonState)
|
||||
{
|
||||
const auto adjustment = _core->ScrollOffset() > 0 ? _core->BufferHeight() - _core->ScrollOffset() - _core->ViewHeight() : 0;
|
||||
// If the click happened outside the active region, just don't send any mouse event
|
||||
if (const auto adjustedY = terminalPosition.y() - adjustment; adjustedY >= 0)
|
||||
{
|
||||
return _core->SendMouseEvent({ terminalPosition.x(), adjustedY }, pointerUpdateKind, modifiers, wheelDelta, buttonState);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -132,6 +132,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
||||
TYPED_EVENT(ScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
|
||||
|
||||
bool _sendMouseEventHelper(const til::point terminalPosition,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const SHORT wheelDelta,
|
||||
::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState buttonState);
|
||||
|
||||
friend class ControlUnitTests::ControlCoreTests;
|
||||
friend class ControlUnitTests::ControlInteractivityTests;
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Microsoft.Terminal.Control
|
||||
Windows.UI.Xaml.Media.Stretch BackgroundImageStretchMode;
|
||||
Windows.UI.Xaml.HorizontalAlignment BackgroundImageHorizontalAlignment;
|
||||
Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment;
|
||||
Boolean IntenseIsBold;
|
||||
// IntenseIsBright is in Core Appearance
|
||||
|
||||
// Experimental settings
|
||||
Boolean RetroTerminalEffect;
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "KeyChord.g.cpp"
|
||||
|
||||
using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
KeyChord::KeyChord() noexcept :
|
||||
@@ -15,34 +17,34 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
KeyChord::KeyChord(bool ctrl, bool alt, bool shift, int32_t vkey) noexcept :
|
||||
_modifiers{ (ctrl ? Control::KeyModifiers::Ctrl : Control::KeyModifiers::None) |
|
||||
(alt ? Control::KeyModifiers::Alt : Control::KeyModifiers::None) |
|
||||
(shift ? Control::KeyModifiers::Shift : Control::KeyModifiers::None) },
|
||||
_modifiers{ (ctrl ? VirtualKeyModifiers::Control : VirtualKeyModifiers::None) |
|
||||
(alt ? VirtualKeyModifiers::Menu : VirtualKeyModifiers::None) |
|
||||
(shift ? VirtualKeyModifiers::Shift : VirtualKeyModifiers::None) },
|
||||
_vkey{ vkey }
|
||||
{
|
||||
}
|
||||
|
||||
KeyChord::KeyChord(bool ctrl, bool alt, bool shift, bool win, int32_t vkey) noexcept :
|
||||
_modifiers{ (ctrl ? Control::KeyModifiers::Ctrl : Control::KeyModifiers::None) |
|
||||
(alt ? Control::KeyModifiers::Alt : Control::KeyModifiers::None) |
|
||||
(shift ? Control::KeyModifiers::Shift : Control::KeyModifiers::None) |
|
||||
(win ? Control::KeyModifiers::Windows : Control::KeyModifiers::None) },
|
||||
_modifiers{ (ctrl ? VirtualKeyModifiers::Control : VirtualKeyModifiers::None) |
|
||||
(alt ? VirtualKeyModifiers::Menu : VirtualKeyModifiers::None) |
|
||||
(shift ? VirtualKeyModifiers::Shift : VirtualKeyModifiers::None) |
|
||||
(win ? VirtualKeyModifiers::Windows : VirtualKeyModifiers::None) },
|
||||
_vkey{ vkey }
|
||||
{
|
||||
}
|
||||
|
||||
KeyChord::KeyChord(Control::KeyModifiers const& modifiers, int32_t vkey) noexcept :
|
||||
KeyChord::KeyChord(VirtualKeyModifiers const& modifiers, int32_t vkey) noexcept :
|
||||
_modifiers{ modifiers },
|
||||
_vkey{ vkey }
|
||||
{
|
||||
}
|
||||
|
||||
Control::KeyModifiers KeyChord::Modifiers() noexcept
|
||||
VirtualKeyModifiers KeyChord::Modifiers() noexcept
|
||||
{
|
||||
return _modifiers;
|
||||
}
|
||||
|
||||
void KeyChord::Modifiers(Control::KeyModifiers const& value) noexcept
|
||||
void KeyChord::Modifiers(VirtualKeyModifiers const& value) noexcept
|
||||
{
|
||||
_modifiers = value;
|
||||
}
|
||||
|
||||
@@ -10,17 +10,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
struct KeyChord : KeyChordT<KeyChord>
|
||||
{
|
||||
KeyChord() noexcept;
|
||||
KeyChord(Control::KeyModifiers const& modifiers, int32_t vkey) noexcept;
|
||||
KeyChord(winrt::Windows::System::VirtualKeyModifiers const& modifiers, int32_t vkey) noexcept;
|
||||
KeyChord(bool ctrl, bool alt, bool shift, int32_t vkey) noexcept;
|
||||
KeyChord(bool ctrl, bool alt, bool shift, bool win, int32_t vkey) noexcept;
|
||||
|
||||
Control::KeyModifiers Modifiers() noexcept;
|
||||
void Modifiers(Control::KeyModifiers const& value) noexcept;
|
||||
winrt::Windows::System::VirtualKeyModifiers Modifiers() noexcept;
|
||||
void Modifiers(winrt::Windows::System::VirtualKeyModifiers const& value) noexcept;
|
||||
int32_t Vkey() noexcept;
|
||||
void Vkey(int32_t value) noexcept;
|
||||
|
||||
private:
|
||||
Control::KeyModifiers _modifiers;
|
||||
winrt::Windows::System::VirtualKeyModifiers _modifiers;
|
||||
int32_t _vkey;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,25 +3,15 @@
|
||||
|
||||
namespace Microsoft.Terminal.Control
|
||||
{
|
||||
[flags]
|
||||
enum KeyModifiers
|
||||
{
|
||||
None = 0x0000,
|
||||
Alt = 0x0001,
|
||||
Ctrl = 0x0002,
|
||||
Shift = 0x0004,
|
||||
Windows = 0x0008
|
||||
};
|
||||
|
||||
[default_interface]
|
||||
runtimeclass KeyChord
|
||||
{
|
||||
KeyChord();
|
||||
KeyChord(KeyModifiers modifiers, Int32 vkey);
|
||||
KeyChord(Windows.System.VirtualKeyModifiers modifiers, Int32 vkey);
|
||||
KeyChord(Boolean ctrl, Boolean alt, Boolean shift, Int32 vkey);
|
||||
KeyChord(Boolean ctrl, Boolean alt, Boolean shift, Boolean win, Int32 vkey);
|
||||
|
||||
KeyModifiers Modifiers;
|
||||
Windows.System.VirtualKeyModifiers Modifiers;
|
||||
Int32 Vkey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
TermControl::TermControl(IControlSettings settings,
|
||||
TerminalConnection::ITerminalConnection connection) :
|
||||
_initializedTerminal{ false },
|
||||
_settings{ settings },
|
||||
_closing{ false },
|
||||
_isInternalScrollBarUpdate{ false },
|
||||
_autoScrollVelocity{ 0 },
|
||||
_autoScrollingPointerPoint{ std::nullopt },
|
||||
@@ -110,11 +108,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Core eventually won't have access to. When we get to
|
||||
// https://github.com/microsoft/terminal/projects/5#card-50760282
|
||||
// then we'll move the applicable ones.
|
||||
//
|
||||
// These four throttled functions are triggered by terminal output and interact with the UI.
|
||||
// Since Close() is the point after which we are removed from the UI, but before the
|
||||
// destructor has run, we MUST check control->_IsClosing() before actually doing anything.
|
||||
_tsfTryRedrawCanvas = std::make_shared<ThrottledFuncTrailing<>>(
|
||||
Dispatcher(),
|
||||
TsfRedrawInterval,
|
||||
[weakThis = get_weak()]() {
|
||||
if (auto control{ weakThis.get() })
|
||||
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||
{
|
||||
control->TSFInputControl().TryRedrawCanvas();
|
||||
}
|
||||
@@ -124,7 +126,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Dispatcher(),
|
||||
UpdatePatternLocationsInterval,
|
||||
[weakThis = get_weak()]() {
|
||||
if (auto control{ weakThis.get() })
|
||||
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||
{
|
||||
control->_core->UpdatePatternLocations();
|
||||
}
|
||||
@@ -134,7 +136,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Dispatcher(),
|
||||
TerminalWarningBellInterval,
|
||||
[weakThis = get_weak()]() {
|
||||
if (auto control{ weakThis.get() })
|
||||
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||
{
|
||||
control->_WarningBellHandlers(*control, nullptr);
|
||||
}
|
||||
@@ -144,14 +146,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Dispatcher(),
|
||||
ScrollBarUpdateInterval,
|
||||
[weakThis = get_weak()](const auto& update) {
|
||||
if (auto control{ weakThis.get() })
|
||||
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||
{
|
||||
control->_isInternalScrollBarUpdate = true;
|
||||
|
||||
auto scrollBar = control->ScrollBar();
|
||||
if (update.newValue.has_value())
|
||||
if (update.newValue)
|
||||
{
|
||||
scrollBar.Value(update.newValue.value());
|
||||
scrollBar.Value(*update.newValue);
|
||||
}
|
||||
scrollBar.Maximum(update.newMaximum);
|
||||
scrollBar.Minimum(update.newMinimum);
|
||||
@@ -205,7 +207,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void TermControl::SearchMatch(const bool goForward)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -296,7 +298,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - newSettings: the new settings to set
|
||||
void TermControl::_UpdateSettingsFromUIThread(IControlSettings newSettings)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -314,7 +316,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - newAppearance: the new appearance to set
|
||||
void TermControl::_UpdateAppearanceFromUIThread(IControlAppearance newAppearance)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -527,7 +529,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Windows::UI::Xaml::Automation::Peers::AutomationPeer TermControl::OnCreateAutomationPeer()
|
||||
try
|
||||
{
|
||||
if (_initializedTerminal && !_closing) // only set up the automation peer if we're ready to go live
|
||||
if (!_IsClosing())
|
||||
{
|
||||
// create a custom automation peer with this code pattern:
|
||||
// (https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/custom-automation-peers)
|
||||
@@ -700,8 +702,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
DispatcherTimer cursorTimer;
|
||||
cursorTimer.Interval(std::chrono::milliseconds(blinkTime));
|
||||
cursorTimer.Tick({ get_weak(), &TermControl::_CursorTimerTick });
|
||||
cursorTimer.Start();
|
||||
_cursorTimer.emplace(std::move(cursorTimer));
|
||||
// As of GH#6586, don't start the cursor timer immediately, and
|
||||
// don't show the cursor initially. We'll show the cursor and start
|
||||
// the timer when the control is first focused. cursorTimer.Start();
|
||||
_core->CursorOn(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -730,12 +735,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Now that the renderer is set up, update the appearance for initialization
|
||||
_UpdateAppearanceFromUIThread(_settings);
|
||||
|
||||
// Focus the control here. If we do it during control initialization, then
|
||||
// focus won't actually get passed to us. I believe this is because
|
||||
// we're not technically a part of the UI tree yet, so focusing us
|
||||
// becomes a no-op.
|
||||
this->Focus(FocusState::Programmatic);
|
||||
|
||||
_initializedTerminal = true;
|
||||
|
||||
// Likewise, run the event handlers outside of lock (they could
|
||||
@@ -747,7 +746,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_CharacterHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Input::CharacterReceivedRoutedEventArgs const& e)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -837,6 +836,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
const auto keyStatus = e.KeyStatus();
|
||||
const auto vkey = gsl::narrow_cast<WORD>(e.OriginalKey());
|
||||
const auto scanCode = gsl::narrow_cast<WORD>(keyStatus.ScanCode);
|
||||
auto modifiers = _GetPressedModifierKeys();
|
||||
|
||||
// GH#11076:
|
||||
// For some weird reason we sometimes receive a WM_KEYDOWN
|
||||
// message without vkey or scanCode if a user drags a tab.
|
||||
// The KeyChord constructor has a debug assertion ensuring that all KeyChord
|
||||
// either have a valid vkey/scanCode. This is important, because this prevents
|
||||
// accidential insertion of invalid KeyChords into classes like ActionMap.
|
||||
if (!vkey && !scanCode)
|
||||
{
|
||||
e.Handled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark the event as handled and do nothing if we're closing, or the key
|
||||
// was the Windows key.
|
||||
//
|
||||
@@ -845,19 +861,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// win32-input-mode, then we'll send all these keystrokes to the
|
||||
// terminal - it's smart enough to ignore the keys it doesn't care
|
||||
// about.
|
||||
if (_closing ||
|
||||
e.OriginalKey() == VirtualKey::LeftWindows ||
|
||||
e.OriginalKey() == VirtualKey::RightWindows)
|
||||
|
||||
if (_IsClosing() || vkey == VK_LWIN || vkey == VK_RWIN)
|
||||
{
|
||||
e.Handled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
auto modifiers = _GetPressedModifierKeys();
|
||||
const auto vkey = gsl::narrow_cast<WORD>(e.OriginalKey());
|
||||
const auto scanCode = gsl::narrow_cast<WORD>(e.KeyStatus().ScanCode);
|
||||
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (_core->IsInReadOnlyMode())
|
||||
{
|
||||
@@ -865,7 +874,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.KeyStatus().IsExtendedKey)
|
||||
if (keyStatus.IsExtendedKey)
|
||||
{
|
||||
modifiers |= ControlKeyStates::EnhancedKey;
|
||||
}
|
||||
@@ -875,8 +884,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// will be sent through the TSFInputControl. See GH#1401 for more
|
||||
// details
|
||||
if (modifiers.IsAltPressed() &&
|
||||
(e.OriginalKey() >= VirtualKey::NumberPad0 && e.OriginalKey() <= VirtualKey::NumberPad9))
|
||||
|
||||
(vkey >= VK_NUMPAD0 && vkey <= VK_NUMPAD9))
|
||||
{
|
||||
e.Handled(true);
|
||||
return;
|
||||
@@ -906,7 +914,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Manually prevent keyboard navigation with tab. We want to send tab to
|
||||
// the terminal, and we don't want to be able to escape focus of the
|
||||
// control with tab.
|
||||
e.Handled(e.OriginalKey() == VirtualKey::Tab);
|
||||
e.Handled(vkey == VK_TAB);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -997,12 +1005,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
keyDown) :
|
||||
true;
|
||||
|
||||
if (_cursorTimer.has_value())
|
||||
if (_cursorTimer)
|
||||
{
|
||||
// Manually show the cursor when a key is pressed. Restarting
|
||||
// the timer prevents flickering.
|
||||
_core->CursorOn(true);
|
||||
_cursorTimer.value().Start();
|
||||
_cursorTimer->Start();
|
||||
}
|
||||
|
||||
return handled;
|
||||
@@ -1027,7 +1035,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_PointerPressedHandler(Windows::Foundation::IInspectable const& sender,
|
||||
Input::PointerRoutedEventArgs const& args)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1078,7 +1086,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_PointerMovedHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Input::PointerRoutedEventArgs const& args)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1151,7 +1159,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_PointerReleasedHandler(Windows::Foundation::IInspectable const& sender,
|
||||
Input::PointerRoutedEventArgs const& args)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1193,7 +1201,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_MouseWheelHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Input::PointerRoutedEventArgs const& args)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1201,6 +1209,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_RestorePointerCursorHandlers(*this, nullptr);
|
||||
|
||||
const auto point = args.GetCurrentPoint(*this);
|
||||
// GH#10329 - we don't need to handle horizontal scrolls. Only vertical ones.
|
||||
// So filter out the horizontal ones.
|
||||
if (point.Properties().IsHorizontalMouseWheel())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = _interactivity->MouseWheel(ControlKeyStates{ args.KeyModifiers() },
|
||||
point.Properties().MouseWheelDelta(),
|
||||
@@ -1295,7 +1309,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_ScrollbarChangeHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Controls::Primitives::RangeBaseValueChangedEventArgs const& args)
|
||||
{
|
||||
if (_isInternalScrollBarUpdate || _closing)
|
||||
if (_isInternalScrollBarUpdate || _IsClosing())
|
||||
{
|
||||
// The update comes from ourselves, more specifically from the
|
||||
// terminal. So we don't have to update the terminal because it
|
||||
@@ -1361,15 +1375,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_TryStartAutoScroll(Windows::UI::Input::PointerPoint const& pointerPoint, const double scrollVelocity)
|
||||
{
|
||||
// Allow only one pointer at the time
|
||||
if (!_autoScrollingPointerPoint.has_value() ||
|
||||
_autoScrollingPointerPoint.value().PointerId() == pointerPoint.PointerId())
|
||||
if (!_autoScrollingPointerPoint ||
|
||||
_autoScrollingPointerPoint->PointerId() == pointerPoint.PointerId())
|
||||
{
|
||||
_autoScrollingPointerPoint = pointerPoint;
|
||||
_autoScrollVelocity = scrollVelocity;
|
||||
|
||||
// If this is first time the auto scroll update is about to be called,
|
||||
// kick-start it by initializing its time delta as if it started now
|
||||
if (!_lastAutoScrollUpdateTime.has_value())
|
||||
if (!_lastAutoScrollUpdateTime)
|
||||
{
|
||||
_lastAutoScrollUpdateTime = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
@@ -1388,8 +1402,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - pointerId: id of pointer for which to stop auto scroll
|
||||
void TermControl::_TryStopAutoScroll(const uint32_t pointerId)
|
||||
{
|
||||
if (_autoScrollingPointerPoint.has_value() &&
|
||||
pointerId == _autoScrollingPointerPoint.value().PointerId())
|
||||
if (_autoScrollingPointerPoint &&
|
||||
pointerId == _autoScrollingPointerPoint->PointerId())
|
||||
{
|
||||
_autoScrollingPointerPoint = std::nullopt;
|
||||
_autoScrollVelocity = 0;
|
||||
@@ -1415,15 +1429,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
const auto timeNow = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (_lastAutoScrollUpdateTime.has_value())
|
||||
if (_lastAutoScrollUpdateTime)
|
||||
{
|
||||
static constexpr double microSecPerSec = 1000000.0;
|
||||
const double deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(timeNow - _lastAutoScrollUpdateTime.value()).count() / microSecPerSec;
|
||||
const double deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(timeNow - *_lastAutoScrollUpdateTime).count() / microSecPerSec;
|
||||
ScrollBar().Value(ScrollBar().Value() + _autoScrollVelocity * deltaTime);
|
||||
|
||||
if (_autoScrollingPointerPoint.has_value())
|
||||
if (_autoScrollingPointerPoint)
|
||||
{
|
||||
_SetEndSelectionPointAtCursor(_autoScrollingPointerPoint.value().Position());
|
||||
_SetEndSelectionPointAtCursor(_autoScrollingPointerPoint->Position());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1439,7 +1453,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_GotFocusHandler(Windows::Foundation::IInspectable const& /* sender */,
|
||||
RoutedEventArgs const& /* args */)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1468,16 +1482,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TSFInputControl().NotifyFocusEnter();
|
||||
}
|
||||
|
||||
if (_cursorTimer.has_value())
|
||||
if (_cursorTimer)
|
||||
{
|
||||
// When the terminal focuses, show the cursor immediately
|
||||
_core->CursorOn(true);
|
||||
_cursorTimer.value().Start();
|
||||
_cursorTimer->Start();
|
||||
}
|
||||
|
||||
if (_blinkTimer.has_value())
|
||||
if (_blinkTimer)
|
||||
{
|
||||
_blinkTimer.value().Start();
|
||||
_blinkTimer->Start();
|
||||
}
|
||||
|
||||
_interactivity->GainFocus();
|
||||
@@ -1498,7 +1512,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_LostFocusHandler(Windows::Foundation::IInspectable const& /* sender */,
|
||||
RoutedEventArgs const& /* args */)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1517,15 +1531,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TSFInputControl().NotifyFocusLeave();
|
||||
}
|
||||
|
||||
if (_cursorTimer.has_value())
|
||||
if (_cursorTimer)
|
||||
{
|
||||
_cursorTimer.value().Stop();
|
||||
_cursorTimer->Stop();
|
||||
_core->CursorOn(false);
|
||||
}
|
||||
|
||||
if (_blinkTimer.has_value())
|
||||
if (_blinkTimer)
|
||||
{
|
||||
_blinkTimer.value().Stop();
|
||||
_blinkTimer->Stop();
|
||||
}
|
||||
|
||||
// Check if there is an unfocused config we should set the appearance to
|
||||
@@ -1544,7 +1558,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_SwapChainSizeChanged(winrt::Windows::Foundation::IInspectable const& /*sender*/,
|
||||
SizeChangedEventArgs const& e)
|
||||
{
|
||||
if (!_initializedTerminal || _closing)
|
||||
if (!_initializedTerminal || _IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1596,7 +1610,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_CursorTimerTick(Windows::Foundation::IInspectable const& /* sender */,
|
||||
Windows::Foundation::IInspectable const& /* e */)
|
||||
{
|
||||
if (!_closing)
|
||||
if (!_IsClosing())
|
||||
{
|
||||
_core->BlinkCursor();
|
||||
}
|
||||
@@ -1610,7 +1624,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_BlinkTimerTick(Windows::Foundation::IInspectable const& /* sender */,
|
||||
Windows::Foundation::IInspectable const& /* e */)
|
||||
{
|
||||
if (!_closing)
|
||||
if (!_IsClosing())
|
||||
{
|
||||
_core->BlinkAttributeTick();
|
||||
}
|
||||
@@ -1638,13 +1652,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_ScrollPositionChanged(const IInspectable& /*sender*/,
|
||||
const Control::ScrollPositionChangedArgs& args)
|
||||
{
|
||||
// Since this callback fires from non-UI thread, we might be already
|
||||
// closed/closing.
|
||||
if (_closing.load())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ScrollBarUpdate update;
|
||||
const auto hiddenContent = args.BufferSize() - args.ViewHeight();
|
||||
update.newMaximum = hiddenContent;
|
||||
@@ -1664,10 +1671,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_CursorPositionChanged(const IInspectable& /*sender*/,
|
||||
const IInspectable& /*args*/)
|
||||
{
|
||||
if (_tsfTryRedrawCanvas)
|
||||
{
|
||||
_tsfTryRedrawCanvas->Run();
|
||||
}
|
||||
_tsfTryRedrawCanvas->Run();
|
||||
}
|
||||
|
||||
hstring TermControl::Title()
|
||||
@@ -1700,7 +1704,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// if we should defer which formats are copied to the global setting
|
||||
bool TermControl::CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1717,21 +1721,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void TermControl::Close()
|
||||
{
|
||||
if (!_closing.exchange(true))
|
||||
if (!_IsClosing())
|
||||
{
|
||||
_closing = true;
|
||||
|
||||
_core->ReceivedOutput(_coreOutputEventToken);
|
||||
|
||||
_RestorePointerCursorHandlers(*this, nullptr);
|
||||
|
||||
// These four throttled functions are triggered by terminal output and interact with the UI.
|
||||
// Since Close() is the point after which we are removed from the UI, but before the destructor
|
||||
// has run, we should disconnect them *right now*. If we don't, they may fire between the
|
||||
// throttle delay (from the final output) and the dtor.
|
||||
_tsfTryRedrawCanvas.reset();
|
||||
_updatePatternLocations.reset();
|
||||
_updateScrollBar.reset();
|
||||
_playWarningBell.reset();
|
||||
|
||||
// Disconnect the TSF input control so it doesn't receive EditContext events.
|
||||
TSFInputControl().Close();
|
||||
_autoScrollTimer.Stop();
|
||||
@@ -2097,7 +2092,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TermControl::_CompositionCompleted(winrt::hstring text)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -2174,7 +2169,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
winrt::fire_and_forget TermControl::_DragDropHandler(Windows::Foundation::IInspectable /*sender*/,
|
||||
DragEventArgs e)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -2261,7 +2256,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_DragOverHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
DragEventArgs const& e)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -2422,7 +2417,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Stop the timer and switch off the light
|
||||
_bellLightTimer.Stop();
|
||||
|
||||
if (!_closing)
|
||||
if (!_IsClosing())
|
||||
{
|
||||
VisualBellLight::SetIsTarget(RootGrid(), false);
|
||||
}
|
||||
@@ -2465,7 +2460,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
if (auto self{ weakThis.get() })
|
||||
{
|
||||
auto lastHoveredCell = _core->GetHoveredCell();
|
||||
if (lastHoveredCell.has_value())
|
||||
if (lastHoveredCell)
|
||||
{
|
||||
const auto uriText = _core->GetHoveredUriText();
|
||||
if (!uriText.empty())
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "../buffer/out/search.h"
|
||||
#include "cppwinrt_utils.h"
|
||||
#include "SearchBoxControl.h"
|
||||
#include "ThrottledFunc.h"
|
||||
|
||||
#include "ControlInteractivity.h"
|
||||
|
||||
@@ -150,9 +149,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
winrt::com_ptr<SearchBoxControl> _searchBox;
|
||||
|
||||
IControlSettings _settings;
|
||||
std::atomic<bool> _closing;
|
||||
bool _focused;
|
||||
bool _initializedTerminal;
|
||||
bool _closing{ false };
|
||||
bool _focused{ false };
|
||||
bool _initializedTerminal{ false };
|
||||
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
|
||||
@@ -184,6 +183,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// _closing isn't atomic and may only be accessed from the main thread.
|
||||
if (const auto dispatcher = Dispatcher())
|
||||
{
|
||||
assert(dispatcher.HasThreadAccess());
|
||||
}
|
||||
#endif
|
||||
return _closing;
|
||||
}
|
||||
|
||||
void _UpdateSettingsFromUIThread(IControlSettings newSettings);
|
||||
void _UpdateAppearanceFromUIThread(IControlAppearance newAppearance);
|
||||
void _ApplyUISettings(const IControlSettings&);
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
<ClInclude Include="TermControlAutomationPeer.h">
|
||||
<DependentUpon>TermControlAutomationPeer.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ThrottledFunc.h" />
|
||||
<ClInclude Include="TSFInputControl.h">
|
||||
<DependentUpon>TSFInputControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- ThrottledFunc.h
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
template<typename... Args>
|
||||
class ThrottledFuncStorage
|
||||
{
|
||||
public:
|
||||
template<typename... MakeArgs>
|
||||
bool Emplace(MakeArgs&&... args)
|
||||
{
|
||||
std::scoped_lock guard{ _lock };
|
||||
|
||||
const bool hadValue = _pendingRunArgs.has_value();
|
||||
_pendingRunArgs.emplace(std::forward<MakeArgs>(args)...);
|
||||
return hadValue;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void ModifyPending(F f)
|
||||
{
|
||||
std::scoped_lock guard{ _lock };
|
||||
|
||||
if (_pendingRunArgs.has_value())
|
||||
{
|
||||
std::apply(f, _pendingRunArgs.value());
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<Args...> Extract()
|
||||
{
|
||||
decltype(_pendingRunArgs) args;
|
||||
std::scoped_lock guard{ _lock };
|
||||
_pendingRunArgs.swap(args);
|
||||
return args.value();
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex _lock;
|
||||
std::optional<std::tuple<Args...>> _pendingRunArgs;
|
||||
};
|
||||
|
||||
template<>
|
||||
class ThrottledFuncStorage<>
|
||||
{
|
||||
public:
|
||||
bool Emplace()
|
||||
{
|
||||
return _isRunPending.test_and_set(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
std::tuple<> Extract()
|
||||
{
|
||||
Reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_isRunPending.clear(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_flag _isRunPending;
|
||||
};
|
||||
|
||||
// Class Description:
|
||||
// - Represents a function that takes arguments and whose invocation is
|
||||
// delayed by a specified duration and rate-limited such that if the code
|
||||
// tries to run the function while a call to the function is already
|
||||
// pending, then the previous call with the previous arguments will be
|
||||
// cancelled and the call will be made with the new arguments instead.
|
||||
// - The function will be run on the the specified dispatcher.
|
||||
template<bool leading, typename... Args>
|
||||
class ThrottledFunc : public std::enable_shared_from_this<ThrottledFunc<leading, Args...>>
|
||||
{
|
||||
public:
|
||||
using Func = std::function<void(Args...)>;
|
||||
|
||||
ThrottledFunc(winrt::Windows::UI::Core::CoreDispatcher dispatcher, winrt::Windows::Foundation::TimeSpan delay, Func func) :
|
||||
_dispatcher{ std::move(dispatcher) },
|
||||
_delay{ std::move(delay) },
|
||||
_func{ std::move(func) }
|
||||
{
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Runs the function later with the specified arguments, except if `Run`
|
||||
// is called again before with new arguments, in which case the new
|
||||
// arguments will be used instead.
|
||||
// - For more information, read the class' documentation.
|
||||
// - This method is always thread-safe. It can be called multiple times on
|
||||
// different threads.
|
||||
// Arguments:
|
||||
// - args: the arguments to pass to the function
|
||||
// Return Value:
|
||||
// - <none>
|
||||
template<typename... MakeArgs>
|
||||
void Run(MakeArgs&&... args)
|
||||
{
|
||||
if (!_storage.Emplace(std::forward<MakeArgs>(args)...))
|
||||
{
|
||||
_Fire();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Modifies the pending arguments for the next function invocation, if
|
||||
// there is one pending currently.
|
||||
// - Let's say that you just called the `Run` method with some arguments.
|
||||
// After the delay specified in the constructor, the function specified
|
||||
// in the constructor will be called with these arguments.
|
||||
// - By using this method, you can modify the arguments before the function
|
||||
// is called.
|
||||
// - You pass a function to this method which will take references to
|
||||
// the arguments (one argument corresponds to one reference to an
|
||||
// argument) and will modify them.
|
||||
// - When there is no pending invocation of the function, this method will
|
||||
// not do anything.
|
||||
// - This method is always thread-safe. It can be called multiple times on
|
||||
// different threads.
|
||||
// Arguments:
|
||||
// - f: the function to call with references to the arguments
|
||||
// Return Value:
|
||||
// - <none>
|
||||
template<typename F>
|
||||
void ModifyPending(F f)
|
||||
{
|
||||
_storage.ModifyPending(f);
|
||||
}
|
||||
|
||||
private:
|
||||
winrt::fire_and_forget _Fire()
|
||||
{
|
||||
const auto dispatcher = _dispatcher;
|
||||
auto weakSelf = this->weak_from_this();
|
||||
|
||||
if constexpr (leading)
|
||||
{
|
||||
co_await winrt::resume_foreground(dispatcher);
|
||||
|
||||
if (auto self{ weakSelf.lock() })
|
||||
{
|
||||
self->_func();
|
||||
}
|
||||
else
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
co_await winrt::resume_after(_delay);
|
||||
|
||||
if (auto self{ weakSelf.lock() })
|
||||
{
|
||||
self->_storage.Reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
co_await winrt::resume_after(_delay);
|
||||
co_await winrt::resume_foreground(dispatcher);
|
||||
|
||||
if (auto self{ weakSelf.lock() })
|
||||
{
|
||||
std::apply(self->_func, self->_storage.Extract());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Core::CoreDispatcher _dispatcher;
|
||||
winrt::Windows::Foundation::TimeSpan _delay;
|
||||
Func _func;
|
||||
|
||||
ThrottledFuncStorage<Args...> _storage;
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
using ThrottledFuncTrailing = ThrottledFunc<false, Args...>;
|
||||
using ThrottledFuncLeading = ThrottledFunc<true>;
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "XamlUiaTextRange.h"
|
||||
#include "../types/TermControlUiaTextRange.hpp"
|
||||
#include <UIAutomationClient.h>
|
||||
#include <UIAutomationCoreApi.h>
|
||||
|
||||
// the same as COR_E_NOTSUPPORTED
|
||||
// we don't want to import the CLR headers to get it
|
||||
@@ -89,12 +90,52 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
winrt::Windows::Foundation::IInspectable XamlUiaTextRange::GetAttributeValue(int32_t textAttributeId) const
|
||||
{
|
||||
// Copied functionality from Types::UiaTextRange.cpp
|
||||
if (textAttributeId == UIA_IsReadOnlyAttributeId)
|
||||
// Call the function off of the underlying UiaTextRange.
|
||||
VARIANT result;
|
||||
THROW_IF_FAILED(_uiaProvider->GetAttributeValue(textAttributeId, &result));
|
||||
|
||||
// Convert the resulting VARIANT into a format that is consumable by XAML.
|
||||
switch (result.vt)
|
||||
{
|
||||
return winrt::box_value(false);
|
||||
case VT_BSTR:
|
||||
{
|
||||
return box_value(result.bstrVal);
|
||||
}
|
||||
else
|
||||
case VT_I4:
|
||||
{
|
||||
// Surprisingly, `long` is _not_ a WinRT type.
|
||||
// So we have to use `int32_t` to make sure this is output properly.
|
||||
// Otherwise, you'll get "Attribute does not exist" out the other end.
|
||||
return box_value<int32_t>(result.lVal);
|
||||
}
|
||||
case VT_R8:
|
||||
{
|
||||
return box_value(result.dblVal);
|
||||
}
|
||||
case VT_BOOL:
|
||||
{
|
||||
return box_value<bool>(result.boolVal);
|
||||
}
|
||||
case VT_UNKNOWN:
|
||||
{
|
||||
// This one is particularly special.
|
||||
// We might return a special value like UiaGetReservedMixedAttributeValue
|
||||
// or UiaGetReservedNotSupportedValue.
|
||||
// Some text attributes may return a real value, however, none of those
|
||||
// are supported at this time.
|
||||
// So we need to figure out what was actually intended to be returned.
|
||||
|
||||
com_ptr<IUnknown> mixedAttributeVal;
|
||||
UiaGetReservedMixedAttributeValue(mixedAttributeVal.put());
|
||||
|
||||
if (result.punkVal == mixedAttributeVal.get())
|
||||
{
|
||||
return Windows::UI::Xaml::DependencyProperty::UnsetValue();
|
||||
}
|
||||
|
||||
[[fallthrough]];
|
||||
}
|
||||
default:
|
||||
{
|
||||
// We _need_ to return XAML_E_NOT_SUPPORTED here.
|
||||
// Returning nullptr is an improper implementation of it being unsupported.
|
||||
@@ -103,6 +144,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Magically, this doesn't affect other forms of navigation...
|
||||
winrt::throw_hresult(XAML_E_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XamlUiaTextRange::GetBoundingRectangles(com_array<double>& returnValue) const
|
||||
|
||||
@@ -58,3 +58,5 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalControlProvider);
|
||||
#include <telemetry/ProjectTelemetry.h>
|
||||
|
||||
#include "til.h"
|
||||
|
||||
#include "ThrottledFunc.h"
|
||||
|
||||
@@ -39,5 +39,6 @@ namespace Microsoft.Terminal.Core
|
||||
Microsoft.Terminal.Core.Color CursorColor;
|
||||
CursorStyle CursorShape;
|
||||
UInt32 CursorHeight;
|
||||
Boolean IntenseIsBright;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "../../terminal/parser/OutputStateMachineEngine.hpp"
|
||||
#include "TerminalDispatch.hpp"
|
||||
#include "../../inc/unicode.hpp"
|
||||
#include "../../inc/DefaultSettings.h"
|
||||
#include "../../inc/argb.h"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
#include "../../types/inc/colorTable.hpp"
|
||||
@@ -53,7 +52,8 @@ Terminal::Terminal() :
|
||||
_selection{ std::nullopt },
|
||||
_taskbarState{ 0 },
|
||||
_taskbarProgress{ 0 },
|
||||
_trimBlockSelection{ false }
|
||||
_trimBlockSelection{ false },
|
||||
_intenseIsBright{ true }
|
||||
{
|
||||
auto dispatch = std::make_unique<TerminalDispatch>(*this);
|
||||
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
|
||||
@@ -174,6 +174,7 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
|
||||
til::color newBackgroundColor{ appearance.DefaultBackground() };
|
||||
_defaultBg = newBackgroundColor.with_alpha(0);
|
||||
_defaultFg = appearance.DefaultForeground();
|
||||
_intenseIsBright = appearance.IntenseIsBright();
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
@@ -1011,6 +1012,31 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
|
||||
_buffer->IncrementCircularBuffer();
|
||||
proposedCursorPosition.Y--;
|
||||
rowsPushedOffTopOfBuffer++;
|
||||
|
||||
// Update our selection too, so it doesn't move as the buffer is cycled
|
||||
if (_selection)
|
||||
{
|
||||
// If the start of the selection is above 0, we can reduce both the start and end by 1
|
||||
if (_selection->start.Y > 0)
|
||||
{
|
||||
_selection->start.Y -= 1;
|
||||
_selection->end.Y -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The start of the selection is at 0, if the end is greater than 0, then only reduce the end
|
||||
if (_selection->end.Y > 0)
|
||||
{
|
||||
_selection->start.X = 0;
|
||||
_selection->end.Y -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Both the start and end of the selection are at 0, clear the selection
|
||||
_selection.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// manually erase our pattern intervals since the locations have changed now
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <conattrs.hpp>
|
||||
|
||||
#include "../../inc/DefaultSettings.h"
|
||||
#include "../../buffer/out/textBuffer.hpp"
|
||||
#include "../../types/inc/sgrStack.hpp"
|
||||
#include "../../renderer/inc/BlinkingState.hpp"
|
||||
@@ -68,6 +69,7 @@ public:
|
||||
|
||||
void UpdateSettings(winrt::Microsoft::Terminal::Core::ICoreSettings settings);
|
||||
void UpdateAppearance(const winrt::Microsoft::Terminal::Core::ICoreAppearance& appearance);
|
||||
void SetFontInfo(const FontInfo& fontInfo);
|
||||
|
||||
// Write goes through the parser
|
||||
void Write(std::wstring_view stringView);
|
||||
@@ -160,6 +162,7 @@ public:
|
||||
COORD GetTextBufferEndPosition() const noexcept override;
|
||||
const TextBuffer& GetTextBuffer() noexcept override;
|
||||
const FontInfo& GetFontInfo() noexcept override;
|
||||
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) const noexcept override;
|
||||
|
||||
void LockConsole() noexcept override;
|
||||
void UnlockConsole() noexcept override;
|
||||
@@ -168,7 +171,6 @@ public:
|
||||
#pragma region IRenderData
|
||||
// These methods are defined in TerminalRenderData.cpp
|
||||
const TextAttribute GetDefaultBrushColors() noexcept override;
|
||||
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) const noexcept override;
|
||||
COORD GetCursorPosition() const noexcept override;
|
||||
bool IsCursorVisible() const noexcept override;
|
||||
bool IsCursorOn() const noexcept override;
|
||||
@@ -195,6 +197,7 @@ public:
|
||||
const COORD GetSelectionEnd() const noexcept override;
|
||||
const std::wstring_view GetConsoleTitle() const noexcept override;
|
||||
void ColorSelection(const COORD coordSelectionStart, const COORD coordSelectionEnd, const TextAttribute) override;
|
||||
const bool IsUiaDataInitialized() const noexcept override;
|
||||
#pragma endregion
|
||||
|
||||
void SetWriteInputCallback(std::function<void(std::wstring&)> pfn) noexcept;
|
||||
@@ -269,6 +272,7 @@ private:
|
||||
bool _suppressApplicationTitle;
|
||||
bool _bracketedPasteMode;
|
||||
bool _trimBlockSelection;
|
||||
bool _intenseIsBright;
|
||||
|
||||
size_t _taskbarState;
|
||||
size_t _taskbarProgress;
|
||||
@@ -276,6 +280,10 @@ private:
|
||||
size_t _hyperlinkPatternId;
|
||||
|
||||
std::wstring _workingDirectory;
|
||||
|
||||
// This default fake font value is only used to check if the font is a raster font.
|
||||
// Otherwise, the font is changed to a real value with the renderer via TriggerFontChange.
|
||||
FontInfo _fontInfo{ DEFAULT_FONT_FACE, TMPF_TRUETYPE, 10, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false };
|
||||
#pragma region Text Selection
|
||||
// a selection is represented as a range between two COORDs (start and end)
|
||||
// the pivot is the COORD that remains selected when you extend a selection in any direction
|
||||
|
||||
@@ -16,7 +16,7 @@ try
|
||||
_WriteBuffer(stringView);
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::ExecuteChar(wchar_t wch) noexcept
|
||||
try
|
||||
@@ -24,7 +24,7 @@ try
|
||||
_WriteBuffer({ &wch, 1 });
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
TextAttribute Terminal::GetTextAttributes() const noexcept
|
||||
{
|
||||
@@ -54,7 +54,7 @@ try
|
||||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
COORD Terminal::GetCursorPosition() noexcept
|
||||
{
|
||||
@@ -75,7 +75,7 @@ try
|
||||
_buffer->GetCursor().SetColor(color);
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Moves the cursor down one line, and possibly also to the leftmost column.
|
||||
@@ -101,7 +101,7 @@ try
|
||||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - deletes count characters starting from the cursor's current position
|
||||
@@ -150,7 +150,7 @@ try
|
||||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Inserts count spaces starting from the cursor's current position, moving over the existing text
|
||||
@@ -205,7 +205,7 @@ try
|
||||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::EraseCharacters(const size_t numChars) noexcept
|
||||
try
|
||||
@@ -218,7 +218,7 @@ try
|
||||
_buffer->Write(eraseIter, absoluteCursorPos);
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method description:
|
||||
// - erases a line of text, either from
|
||||
@@ -264,7 +264,7 @@ try
|
||||
_buffer->Write(eraseIter, startPos, false);
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method description:
|
||||
// - erases text in the buffer in two ways depending on erase type
|
||||
@@ -348,7 +348,7 @@ try
|
||||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::WarningBell() noexcept
|
||||
try
|
||||
@@ -356,7 +356,7 @@ try
|
||||
_pfnWarningBell();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::SetWindowTitle(std::wstring_view title) noexcept
|
||||
try
|
||||
@@ -368,7 +368,7 @@ try
|
||||
}
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Updates the value in the colortable at index tableIndex to the new color
|
||||
@@ -387,7 +387,7 @@ try
|
||||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Sets the cursor style to the given style.
|
||||
@@ -457,7 +457,7 @@ try
|
||||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Updates the default background color from a COLORREF, format 0x00BBGGRR.
|
||||
@@ -475,7 +475,7 @@ try
|
||||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
til::color Terminal::GetDefaultBackground() const noexcept
|
||||
{
|
||||
@@ -509,7 +509,7 @@ try
|
||||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::EnableVT200MouseMode(const bool enabled) noexcept
|
||||
{
|
||||
@@ -591,7 +591,7 @@ try
|
||||
|
||||
return true;
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Updates the buffer's current text attributes to start a hyperlink
|
||||
|
||||
@@ -733,6 +733,10 @@ bool TerminalDispatch::HardReset() noexcept
|
||||
// Cursor to 1,1 - the Soft Reset guarantees this is absolute
|
||||
success = CursorPosition(1, 1) && success;
|
||||
|
||||
// Reset the mouse mode
|
||||
success = EnableSGRExtendedMouseMode(false) && success;
|
||||
success = EnableAnyEventMouseMode(false) && success;
|
||||
|
||||
// Delete all current tab stops and reapply
|
||||
_ResetTabStops();
|
||||
|
||||
|
||||
@@ -27,23 +27,15 @@ const TextBuffer& Terminal::GetTextBuffer() noexcept
|
||||
return *_buffer;
|
||||
}
|
||||
|
||||
// Creating a FontInfo can technically throw (on string allocation) and this is noexcept.
|
||||
// That means this will std::terminate. We could come back and make there be a default constructor
|
||||
// backup to FontInfo that throws no exceptions and allocates a default FontInfo structure.
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26447)
|
||||
const FontInfo& Terminal::GetFontInfo() noexcept
|
||||
{
|
||||
// TODO: This font value is only used to check if the font is a raster font.
|
||||
// Otherwise, the font is changed with the renderer via TriggerFontChange.
|
||||
// The renderer never uses any of the other members from the value returned
|
||||
// by this method.
|
||||
// We could very likely replace this with just an IsRasterFont method
|
||||
// (which would return false)
|
||||
static const FontInfo _fakeFontInfo(DEFAULT_FONT_FACE, TMPF_TRUETYPE, 10, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false);
|
||||
return _fakeFontInfo;
|
||||
return _fontInfo;
|
||||
}
|
||||
|
||||
void Terminal::SetFontInfo(const FontInfo& fontInfo)
|
||||
{
|
||||
_fontInfo = fontInfo;
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
const TextAttribute Terminal::GetDefaultBrushColors() noexcept
|
||||
{
|
||||
@@ -57,7 +49,8 @@ std::pair<COLORREF, COLORREF> Terminal::GetAttributeColors(const TextAttribute&
|
||||
_defaultFg,
|
||||
_defaultBg,
|
||||
_screenReversed,
|
||||
_blinkingState.IsBlinkingFaint());
|
||||
_blinkingState.IsBlinkingFaint(),
|
||||
_intenseIsBright);
|
||||
colors.first |= 0xff000000;
|
||||
// We only care about alpha for the default BG (which enables acrylic)
|
||||
// If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque.
|
||||
@@ -256,3 +249,12 @@ bool Terminal::IsScreenReversed() const noexcept
|
||||
{
|
||||
return _screenReversed;
|
||||
}
|
||||
|
||||
const bool Terminal::IsUiaDataInitialized() const noexcept
|
||||
{
|
||||
// GH#11135: Windows Terminal needs to create and return an automation peer
|
||||
// when a screen reader requests it. However, the terminal might not be fully
|
||||
// initialized yet. So we use this to check if any crucial components of
|
||||
// UiaData are not yet initialized.
|
||||
return !!_buffer;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "KeyBindingViewModel.g.cpp"
|
||||
#include "ActionsPageNavigationState.g.cpp"
|
||||
#include "LibraryResources.h"
|
||||
#include "../TerminalSettingsModel/AllShortcutActions.h"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
@@ -20,10 +21,15 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
KeyBindingViewModel::KeyBindingViewModel(const Control::KeyChord& keys, const Model::Command& cmd) :
|
||||
KeyBindingViewModel::KeyBindingViewModel(const Windows::Foundation::Collections::IObservableVector<hstring>& availableActions) :
|
||||
KeyBindingViewModel(nullptr, availableActions.First().Current(), availableActions) {}
|
||||
|
||||
KeyBindingViewModel::KeyBindingViewModel(const Control::KeyChord& keys, const hstring& actionName, const IObservableVector<hstring>& availableActions) :
|
||||
_Keys{ keys },
|
||||
_KeyChordText{ Model::KeyChordSerialization::ToString(keys) },
|
||||
_Command{ cmd }
|
||||
_CurrentAction{ actionName },
|
||||
_ProposedAction{ box_value(actionName) },
|
||||
_AvailableActions{ availableActions }
|
||||
{
|
||||
// Add a property changed handler to our own property changed event.
|
||||
// This propagates changes from the settings model to anybody listening to our
|
||||
@@ -43,6 +49,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
_NotifyChanges(L"ShowEditButton");
|
||||
}
|
||||
else if (viewModelProperty == L"CurrentAction")
|
||||
{
|
||||
_NotifyChanges(L"Name");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -63,8 +73,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (_IsInEditMode)
|
||||
{
|
||||
// if we're in edit mode,
|
||||
// pre-populate the text box with the current keys
|
||||
// - pre-populate the text box with the current keys
|
||||
// - reset the combo box with the current action
|
||||
ProposedKeys(KeyChordText());
|
||||
ProposedAction(box_value(CurrentAction()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,17 +87,25 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void KeyBindingViewModel::AttemptAcceptChanges(hstring newKeyChordText)
|
||||
{
|
||||
auto args{ make_self<RebindKeysEventArgs>(_Keys, _Keys) };
|
||||
try
|
||||
{
|
||||
// Attempt to convert the provided key chord text
|
||||
const auto newKeyChord{ KeyChordSerialization::FromString(newKeyChordText) };
|
||||
args->NewKeys(newKeyChord);
|
||||
_RebindKeysRequestedHandlers(*this, *args);
|
||||
// empty string --> don't accept changes
|
||||
if (newKeyChordText.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// ModifyKeyBindingEventArgs
|
||||
const auto args{ make_self<ModifyKeyBindingEventArgs>(_Keys, // OldKeys
|
||||
KeyChordSerialization::FromString(newKeyChordText), // NewKeys: Attempt to convert the provided key chord text
|
||||
_IsNewlyAdded ? hstring{} : _CurrentAction, // OldAction
|
||||
unbox_value<hstring>(_ProposedAction)) }; //
|
||||
_ModifyKeyBindingRequestedHandlers(*this, *args);
|
||||
}
|
||||
catch (hresult_invalid_argument)
|
||||
{
|
||||
// Converting the text into a key chord failed
|
||||
// Converting the text into a key chord failed.
|
||||
// Don't accept the changes.
|
||||
// TODO GH #6900:
|
||||
// This is tricky. I still haven't found a way to reference the
|
||||
// key chord text box. It's hidden behind the data template.
|
||||
@@ -96,9 +116,23 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void KeyBindingViewModel::CancelChanges()
|
||||
{
|
||||
if (_IsNewlyAdded)
|
||||
{
|
||||
_DeleteNewlyAddedKeyBindingHandlers(*this, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ToggleEditMode();
|
||||
}
|
||||
}
|
||||
|
||||
Actions::Actions()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Automation::AutomationProperties::SetName(AddNewButton(), RS_(L"Actions_AddNewTextBlock/Text"));
|
||||
}
|
||||
|
||||
Automation::Peers::AutomationPeer Actions::OnCreateAutomationPeer()
|
||||
@@ -118,17 +152,26 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
_State = e.Parameter().as<Editor::ActionsPageNavigationState>();
|
||||
|
||||
// Populate AvailableActionAndArgs
|
||||
_AvailableActionMap = single_threaded_map<hstring, Model::ActionAndArgs>();
|
||||
std::vector<hstring> availableActionAndArgs;
|
||||
for (const auto& [name, actionAndArgs] : _State.Settings().ActionMap().AvailableActions())
|
||||
{
|
||||
availableActionAndArgs.push_back(name);
|
||||
_AvailableActionMap.Insert(name, actionAndArgs);
|
||||
}
|
||||
std::sort(begin(availableActionAndArgs), end(availableActionAndArgs));
|
||||
_AvailableActionAndArgs = single_threaded_observable_vector(std::move(availableActionAndArgs));
|
||||
|
||||
// Convert the key bindings from our settings into a view model representation
|
||||
const auto& keyBindingMap{ _State.Settings().ActionMap().KeyBindings() };
|
||||
std::vector<Editor::KeyBindingViewModel> keyBindingList;
|
||||
keyBindingList.reserve(keyBindingMap.Size());
|
||||
for (const auto& [keys, cmd] : keyBindingMap)
|
||||
{
|
||||
auto container{ make_self<KeyBindingViewModel>(keys, cmd) };
|
||||
container->PropertyChanged({ this, &Actions::_ViewModelPropertyChangedHandler });
|
||||
container->DeleteKeyBindingRequested({ this, &Actions::_ViewModelDeleteKeyBindingHandler });
|
||||
container->RebindKeysRequested({ this, &Actions::_ViewModelRebindKeysHandler });
|
||||
container->IsAutomationPeerAttached(_AutomationPeerAttached);
|
||||
// convert the cmd into a KeyBindingViewModel
|
||||
auto container{ make_self<KeyBindingViewModel>(keys, cmd.Name(), _AvailableActionAndArgs) };
|
||||
_RegisterEvents(container);
|
||||
keyBindingList.push_back(*container);
|
||||
}
|
||||
|
||||
@@ -159,11 +202,30 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
else if (e.OriginalKey() == VirtualKey::Escape)
|
||||
{
|
||||
kbdVM.ToggleEditMode();
|
||||
kbdVM.CancelChanges();
|
||||
e.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Actions::AddNew_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*eventArgs*/)
|
||||
{
|
||||
// Create the new key binding and register all of the event handlers.
|
||||
auto kbdVM{ make_self<KeyBindingViewModel>(_AvailableActionAndArgs) };
|
||||
_RegisterEvents(kbdVM);
|
||||
kbdVM->DeleteNewlyAddedKeyBinding({ this, &Actions::_ViewModelDeleteNewlyAddedKeyBindingHandler });
|
||||
|
||||
// Manually add the editing background. This needs to be done in Actions not the view model.
|
||||
// We also have to do this manually because it hasn't been added to the list yet.
|
||||
kbdVM->IsInEditMode(true);
|
||||
const auto& containerBackground{ Resources().Lookup(box_value(L"ActionContainerBackgroundEditing")).as<Windows::UI::Xaml::Media::Brush>() };
|
||||
kbdVM->ContainerBackground(containerBackground);
|
||||
|
||||
// IMPORTANT: do this _after_ setting IsInEditMode. Otherwise, it'll get deleted immediately
|
||||
// by the PropertyChangedHandler below (where we delete any IsNewlyAdded items)
|
||||
kbdVM->IsNewlyAdded(true);
|
||||
_KeyBindingList.InsertAt(0, *kbdVM);
|
||||
}
|
||||
|
||||
void Actions::_ViewModelPropertyChangedHandler(const IInspectable& sender, const Windows::UI::Xaml::Data::PropertyChangedEventArgs& args)
|
||||
{
|
||||
const auto senderVM{ sender.as<Editor::KeyBindingViewModel>() };
|
||||
@@ -174,8 +236,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
// Ensure that...
|
||||
// 1. we move focus to the edit mode controls
|
||||
// 2. this is the only entry that is in edit mode
|
||||
for (uint32_t i = 0; i < _KeyBindingList.Size(); ++i)
|
||||
// 2. any actions that were newly added are removed
|
||||
// 3. this is the only entry that is in edit mode
|
||||
for (int32_t i = _KeyBindingList.Size() - 1; i >= 0; --i)
|
||||
{
|
||||
const auto& kbdVM{ _KeyBindingList.GetAt(i) };
|
||||
if (senderVM == kbdVM)
|
||||
@@ -186,6 +249,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
const auto& container{ KeyBindingsListView().ContainerFromIndex(i).try_as<ListViewItem>() };
|
||||
container.Focus(FocusState::Programmatic);
|
||||
}
|
||||
else if (kbdVM.IsNewlyAdded())
|
||||
{
|
||||
// Remove any actions that were newly added
|
||||
_KeyBindingList.RemoveAt(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Exit edit mode for all other containers
|
||||
@@ -228,12 +296,50 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void Actions::_ViewModelRebindKeysHandler(const Editor::KeyBindingViewModel& senderVM, const Editor::RebindKeysEventArgs& args)
|
||||
void Actions::_ViewModelModifyKeyBindingHandler(const Editor::KeyBindingViewModel& senderVM, const Editor::ModifyKeyBindingEventArgs& args)
|
||||
{
|
||||
if (args.OldKeys().Modifiers() != args.NewKeys().Modifiers() || args.OldKeys().Vkey() != args.NewKeys().Vkey())
|
||||
const auto isNewAction{ !args.OldKeys() && args.OldActionName().empty() };
|
||||
|
||||
auto applyChangesToSettingsModel = [=]() {
|
||||
// If the key chord was changed,
|
||||
// update the settings model and view model appropriately
|
||||
// NOTE: we still need to update the view model if we're working with a newly added action
|
||||
if (isNewAction || args.OldKeys().Modifiers() != args.NewKeys().Modifiers() || args.OldKeys().Vkey() != args.NewKeys().Vkey())
|
||||
{
|
||||
if (!isNewAction)
|
||||
{
|
||||
// update settings model
|
||||
_State.Settings().ActionMap().RebindKeys(args.OldKeys(), args.NewKeys());
|
||||
}
|
||||
|
||||
// update view model
|
||||
auto senderVMImpl{ get_self<KeyBindingViewModel>(senderVM) };
|
||||
senderVMImpl->Keys(args.NewKeys());
|
||||
}
|
||||
|
||||
// If the action was changed,
|
||||
// update the settings model and view model appropriately
|
||||
// NOTE: no need to check for "isNewAction" here. <empty_string> != <action name> already.
|
||||
if (args.OldActionName() != args.NewActionName())
|
||||
{
|
||||
// convert the action's name into a view model.
|
||||
const auto& newAction{ _AvailableActionMap.Lookup(args.NewActionName()) };
|
||||
|
||||
// update settings model
|
||||
_State.Settings().ActionMap().RegisterKeyBinding(args.NewKeys(), newAction);
|
||||
|
||||
// update view model
|
||||
auto senderVMImpl{ get_self<KeyBindingViewModel>(senderVM) };
|
||||
senderVMImpl->CurrentAction(args.NewActionName());
|
||||
senderVMImpl->IsNewlyAdded(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Check for this special case:
|
||||
// we're changing the key chord,
|
||||
// but the new key chord is already in use
|
||||
if (isNewAction || args.OldKeys().Modifiers() != args.NewKeys().Modifiers() || args.OldKeys().Vkey() != args.NewKeys().Vkey())
|
||||
{
|
||||
// We're actually changing the key chord
|
||||
const auto senderVMImpl{ get_self<KeyBindingViewModel>(senderVM) };
|
||||
const auto& conflictingCmd{ _State.Settings().ActionMap().GetActionByKeyChord(args.NewKeys()) };
|
||||
if (conflictingCmd)
|
||||
{
|
||||
@@ -262,8 +368,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
senderVM.AcceptChangesFlyout(nullptr);
|
||||
|
||||
// update settings model and view model
|
||||
_State.Settings().ActionMap().RebindKeys(args.OldKeys(), args.NewKeys());
|
||||
senderVMImpl->Keys(args.NewKeys());
|
||||
applyChangesToSettingsModel();
|
||||
senderVM.ToggleEditMode();
|
||||
});
|
||||
|
||||
@@ -278,20 +383,30 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
senderVM.AcceptChangesFlyout(acceptChangesFlyout);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// update settings model
|
||||
_State.Settings().ActionMap().RebindKeys(args.OldKeys(), args.NewKeys());
|
||||
|
||||
// update view model (keys)
|
||||
senderVMImpl->Keys(args.NewKeys());
|
||||
}
|
||||
}
|
||||
|
||||
// update view model (exit edit mode)
|
||||
// update settings model and view model
|
||||
applyChangesToSettingsModel();
|
||||
|
||||
// We NEED to toggle the edit mode here,
|
||||
// so that if nothing changed, we still exit
|
||||
// edit mode.
|
||||
senderVM.ToggleEditMode();
|
||||
}
|
||||
|
||||
void Actions::_ViewModelDeleteNewlyAddedKeyBindingHandler(const Editor::KeyBindingViewModel& senderVM, const IInspectable& /*args*/)
|
||||
{
|
||||
for (uint32_t i = 0; i < _KeyBindingList.Size(); ++i)
|
||||
{
|
||||
const auto& kbdVM{ _KeyBindingList.GetAt(i) };
|
||||
if (kbdVM == senderVM)
|
||||
{
|
||||
_KeyBindingList.RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - performs a search on KeyBindingList by key chord.
|
||||
// Arguments:
|
||||
@@ -315,4 +430,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// to quickly search through the sorted list.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Actions::_RegisterEvents(com_ptr<KeyBindingViewModel>& kbdVM)
|
||||
{
|
||||
kbdVM->PropertyChanged({ this, &Actions::_ViewModelPropertyChangedHandler });
|
||||
kbdVM->DeleteKeyBindingRequested({ this, &Actions::_ViewModelDeleteKeyBindingHandler });
|
||||
kbdVM->ModifyKeyBindingRequested({ this, &Actions::_ViewModelModifyKeyBindingHandler });
|
||||
kbdVM->IsAutomationPeerAttached(_AutomationPeerAttached);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "Actions.g.h"
|
||||
#include "KeyBindingViewModel.g.h"
|
||||
#include "ActionsPageNavigationState.g.h"
|
||||
#include "RebindKeysEventArgs.g.h"
|
||||
#include "ModifyKeyBindingEventArgs.g.h"
|
||||
#include "Utils.h"
|
||||
#include "ViewModelHelpers.h"
|
||||
|
||||
@@ -20,25 +20,29 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
};
|
||||
|
||||
struct RebindKeysEventArgs : RebindKeysEventArgsT<RebindKeysEventArgs>
|
||||
struct ModifyKeyBindingEventArgs : ModifyKeyBindingEventArgsT<ModifyKeyBindingEventArgs>
|
||||
{
|
||||
public:
|
||||
RebindKeysEventArgs(const Control::KeyChord& oldKeys, const Control::KeyChord& newKeys) :
|
||||
ModifyKeyBindingEventArgs(const Control::KeyChord& oldKeys, const Control::KeyChord& newKeys, const hstring oldActionName, const hstring newActionName) :
|
||||
_OldKeys{ oldKeys },
|
||||
_NewKeys{ newKeys } {}
|
||||
_NewKeys{ newKeys },
|
||||
_OldActionName{ std::move(oldActionName) },
|
||||
_NewActionName{ std::move(newActionName) } {}
|
||||
|
||||
WINRT_PROPERTY(Control::KeyChord, OldKeys, nullptr);
|
||||
WINRT_PROPERTY(Control::KeyChord, NewKeys, nullptr);
|
||||
WINRT_PROPERTY(hstring, OldActionName);
|
||||
WINRT_PROPERTY(hstring, NewActionName);
|
||||
};
|
||||
|
||||
struct KeyBindingViewModel : KeyBindingViewModelT<KeyBindingViewModel>, ViewModelHelper<KeyBindingViewModel>
|
||||
{
|
||||
public:
|
||||
KeyBindingViewModel(const Control::KeyChord& keys, const Settings::Model::Command& cmd);
|
||||
KeyBindingViewModel(const Windows::Foundation::Collections::IObservableVector<hstring>& availableActions);
|
||||
KeyBindingViewModel(const Control::KeyChord& keys, const hstring& name, const Windows::Foundation::Collections::IObservableVector<hstring>& availableActions);
|
||||
|
||||
hstring Name() const { return _Command.Name(); }
|
||||
hstring Name() const { return _CurrentAction; }
|
||||
hstring KeyChordText() const { return _KeyChordText; }
|
||||
Settings::Model::Command Command() const { return _Command; };
|
||||
|
||||
// UIA Text
|
||||
hstring EditButtonName() const noexcept;
|
||||
@@ -57,22 +61,40 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void DisableEditMode() { IsInEditMode(false); }
|
||||
void AttemptAcceptChanges();
|
||||
void AttemptAcceptChanges(hstring newKeyChordText);
|
||||
void CancelChanges();
|
||||
void DeleteKeyBinding() { _DeleteKeyBindingRequestedHandlers(*this, _Keys); }
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsInEditMode, false);
|
||||
// ProposedAction: the entry selected by the combo box; may disagree with the settings model.
|
||||
// CurrentAction: the combo box item that maps to the settings model value.
|
||||
// AvailableActions: the list of options in the combo box; both actions above must be in this list.
|
||||
// NOTE: ProposedAction and CurrentAction may disagree mainly due to the "edit mode" system in place.
|
||||
// Current Action serves as...
|
||||
// 1 - a record of what to set ProposedAction to on a cancellation
|
||||
// 2 - a form of translation between ProposedAction and the settings model
|
||||
// We would also need an ActionMap reference to remove this, but this is a better separation
|
||||
// of responsibilities.
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(IInspectable, ProposedAction);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, CurrentAction);
|
||||
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<hstring>, AvailableActions, nullptr);
|
||||
|
||||
// ProposedKeys: the text shown in the text box; may disagree with the settings model.
|
||||
// Keys: the key chord bound in the settings model.
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, ProposedKeys);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Control::KeyChord, Keys, nullptr);
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsInEditMode, false);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsNewlyAdded, false);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Controls::Flyout, AcceptChangesFlyout, nullptr);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsAutomationPeerAttached, false);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsHovered, false);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsContainerFocused, false);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsEditButtonFocused, false);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Media::Brush, ContainerBackground, nullptr);
|
||||
TYPED_EVENT(RebindKeysRequested, Editor::KeyBindingViewModel, Editor::RebindKeysEventArgs);
|
||||
TYPED_EVENT(ModifyKeyBindingRequested, Editor::KeyBindingViewModel, Editor::ModifyKeyBindingEventArgs);
|
||||
TYPED_EVENT(DeleteKeyBindingRequested, Editor::KeyBindingViewModel, Terminal::Control::KeyChord);
|
||||
TYPED_EVENT(DeleteNewlyAddedKeyBinding, Editor::KeyBindingViewModel, IInspectable);
|
||||
|
||||
private:
|
||||
Settings::Model::Command _Command{ nullptr };
|
||||
hstring _KeyChordText{};
|
||||
};
|
||||
|
||||
@@ -85,7 +107,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
WINRT_PROPERTY(Model::CascadiaSettings, Settings, nullptr)
|
||||
};
|
||||
|
||||
struct Actions : ActionsT<Actions>
|
||||
struct Actions : public HasScrollViewer<Actions>, ActionsT<Actions>
|
||||
{
|
||||
public:
|
||||
Actions();
|
||||
@@ -93,6 +115,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
|
||||
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
|
||||
void KeyChordEditor_KeyDown(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
void AddNew_Click(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_PROPERTY(Editor::ActionsPageNavigationState, State, nullptr);
|
||||
@@ -101,11 +124,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
private:
|
||||
void _ViewModelPropertyChangedHandler(const Windows::Foundation::IInspectable& senderVM, const Windows::UI::Xaml::Data::PropertyChangedEventArgs& args);
|
||||
void _ViewModelDeleteKeyBindingHandler(const Editor::KeyBindingViewModel& senderVM, const Control::KeyChord& args);
|
||||
void _ViewModelRebindKeysHandler(const Editor::KeyBindingViewModel& senderVM, const Editor::RebindKeysEventArgs& args);
|
||||
void _ViewModelModifyKeyBindingHandler(const Editor::KeyBindingViewModel& senderVM, const Editor::ModifyKeyBindingEventArgs& args);
|
||||
void _ViewModelDeleteNewlyAddedKeyBindingHandler(const Editor::KeyBindingViewModel& senderVM, const IInspectable& args);
|
||||
|
||||
std::optional<uint32_t> _GetContainerIndexByKeyChord(const Control::KeyChord& keys);
|
||||
void _RegisterEvents(com_ptr<implementation::KeyBindingViewModel>& kbdVM);
|
||||
|
||||
bool _AutomationPeerAttached{ false };
|
||||
Windows::Foundation::Collections::IObservableVector<hstring> _AvailableActionAndArgs;
|
||||
Windows::Foundation::Collections::IMap<hstring, Model::ActionAndArgs> _AvailableActionMap;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@ import "EnumEntry.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
runtimeclass RebindKeysEventArgs
|
||||
runtimeclass ModifyKeyBindingEventArgs
|
||||
{
|
||||
Microsoft.Terminal.Control.KeyChord OldKeys { get; };
|
||||
Microsoft.Terminal.Control.KeyChord NewKeys { get; };
|
||||
String OldActionName { get; };
|
||||
String NewActionName { get; };
|
||||
}
|
||||
|
||||
runtimeclass KeyBindingViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
@@ -20,7 +22,9 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
// UI side
|
||||
Boolean ShowEditButton { get; };
|
||||
Boolean IsInEditMode { get; };
|
||||
Boolean IsNewlyAdded { get; };
|
||||
String ProposedKeys;
|
||||
Object ProposedAction;
|
||||
Windows.UI.Xaml.Controls.Flyout AcceptChangesFlyout;
|
||||
String EditButtonName { get; };
|
||||
String CancelButtonName { get; };
|
||||
@@ -34,11 +38,13 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
void ActionLostFocus();
|
||||
void EditButtonGettingFocus();
|
||||
void EditButtonLosingFocus();
|
||||
IObservableVector<String> AvailableActions { get; };
|
||||
void ToggleEditMode();
|
||||
void AttemptAcceptChanges();
|
||||
void CancelChanges();
|
||||
void DeleteKeyBinding();
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<KeyBindingViewModel, RebindKeysEventArgs> RebindKeysRequested;
|
||||
event Windows.Foundation.TypedEventHandler<KeyBindingViewModel, ModifyKeyBindingEventArgs> ModifyKeyBindingRequested;
|
||||
event Windows.Foundation.TypedEventHandler<KeyBindingViewModel, Microsoft.Terminal.Control.KeyChord> DeleteKeyBindingRequested;
|
||||
}
|
||||
|
||||
|
||||
@@ -198,7 +198,15 @@
|
||||
<!-- Command Name -->
|
||||
<TextBlock Grid.Column="0"
|
||||
Style="{StaticResource KeyBindingNameTextBlockStyle}"
|
||||
Text="{x:Bind Name, Mode=OneWay}" />
|
||||
Text="{x:Bind Name, Mode=OneWay}"
|
||||
Visibility="{x:Bind IsInEditMode, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}" />
|
||||
|
||||
<!-- Edit Mode: Action Combo-box -->
|
||||
<ComboBox Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{x:Bind AvailableActions, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ProposedAction, Mode=TwoWay}"
|
||||
Visibility="{x:Bind IsInEditMode, Mode=OneWay}" />
|
||||
|
||||
<!-- Key Chord Text -->
|
||||
<Border Grid.Column="1"
|
||||
@@ -278,7 +286,7 @@
|
||||
<!-- Cancel editing the action -->
|
||||
<Button x:Uid="Actions_CancelButton"
|
||||
AutomationProperties.Name="{x:Bind CancelButtonName}"
|
||||
Click="{x:Bind ToggleEditMode}"
|
||||
Click="{x:Bind CancelChanges}"
|
||||
Style="{StaticResource EditButtonStyle}">
|
||||
<FontIcon FontSize="{StaticResource EditButtonIconSize}"
|
||||
Glyph="" />
|
||||
@@ -299,7 +307,8 @@
|
||||
<Button x:Uid="Actions_DeleteButton"
|
||||
Margin="8,0,0,0"
|
||||
AutomationProperties.Name="{x:Bind DeleteButtonName}"
|
||||
Style="{StaticResource EditButtonStyle}">
|
||||
Style="{StaticResource EditButtonStyle}"
|
||||
Visibility="{x:Bind IsNewlyAdded, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
|
||||
<Button.Content>
|
||||
<FontIcon FontSize="{StaticResource EditButtonIconSize}"
|
||||
Glyph="" />
|
||||
@@ -371,9 +380,23 @@
|
||||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
<ScrollViewer ViewChanging="ViewChanging">
|
||||
<StackPanel MaxWidth="600"
|
||||
Spacing="8"
|
||||
Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Add New Button -->
|
||||
<Button x:Name="AddNewButton"
|
||||
Click="AddNew_Click">
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="Actions_AddNewTextBlock"
|
||||
Style="{StaticResource IconButtonTextBlockStyle}" />
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<!-- Keybindings -->
|
||||
<ListView x:Name="KeyBindingsListView"
|
||||
ItemTemplate="{StaticResource KeyBindingTemplate}"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user