mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-15 18:51:00 +00:00
Compare commits
74 Commits
dev/cazamo
...
dev/lhecke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78854c8674 | ||
|
|
e7d00cab8e | ||
|
|
dbf9343320 | ||
|
|
a9c50f9bf7 | ||
|
|
8947909121 | ||
|
|
293c36d42f | ||
|
|
cf8f411b8f | ||
|
|
ee6ca81d70 | ||
|
|
b609266d29 | ||
|
|
59e2835736 | ||
|
|
3bf5436122 | ||
|
|
5ea778b2b8 | ||
|
|
cabb83db61 | ||
|
|
769e910e35 | ||
|
|
1d02f82ab7 | ||
|
|
84e30bcd3a | ||
|
|
f68324cd09 | ||
|
|
fca87b2bb5 | ||
|
|
c12835783d | ||
|
|
56bbe86f96 | ||
|
|
d13c37cd60 | ||
|
|
32fbd4cbb6 | ||
|
|
6d7723e3be | ||
|
|
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 | ||
|
|
e2005ca5d7 | ||
|
|
c8f00df170 | ||
|
|
c90de69250 | ||
|
|
448684a5f4 | ||
|
|
0d3f85de85 |
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 }}'
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
buildPlatform: ${{ parameters.platform }}
|
||||
openHelixTargetQueues: ${{ parameters.openHelixTargetQueues }}
|
||||
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}}'
|
||||
|
||||
|
||||
@@ -147,4 +147,3 @@ jobs:
|
||||
projects: build\Helix\RunTestsInHelix.proj
|
||||
custom: msbuild
|
||||
arguments: '$(helixCommonArgs) /p:IsExternal=true /p:Creator=Terminal /p:HelixTargetQueues=$(openHelixTargetQueues)'
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"/.github/",
|
||||
"/samples/",
|
||||
"/res/terminal/",
|
||||
"/res/fonts/",
|
||||
"/doc/specs/",
|
||||
"/doc/cascadia/",
|
||||
"/doc/user-docs/",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
|
||||
<XesBaseYearForStoreVersion>2021</XesBaseYearForStoreVersion>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>10</VersionMinor>
|
||||
<VersionMinor>11</VersionMinor>
|
||||
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -165,6 +165,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 +589,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 +691,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 +961,7 @@
|
||||
{ "$ref": "#/definitions/WtAction" },
|
||||
{ "$ref": "#/definitions/CloseOtherTabsAction" },
|
||||
{ "$ref": "#/definitions/CloseTabsAfterAction" },
|
||||
{ "$ref": "#/definitions/CloseTabAction" },
|
||||
{ "$ref": "#/definitions/ScrollUpAction" },
|
||||
{ "$ref": "#/definitions/ScrollDownAction" },
|
||||
{ "$ref": "#/definitions/MoveTabAction" },
|
||||
@@ -1242,6 +1307,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 +1428,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 +1464,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 (2106.17)
|
||||
* from microsoft/cascadia-code@fb0bce69c1c12f6c298b8bc1c1d181868f5daa9a
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,8 @@
|
||||
// Note: will through if unable to allocate char/attribute buffers
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26447) // small_vector's constructor says it can throw but it should not given how we use it. This suppresses this error for the AuditMode build.
|
||||
CharRow::CharRow(size_t rowWidth, ROW* const pParent) noexcept :
|
||||
_data(rowWidth, value_type()),
|
||||
CharRow::CharRow(CharRowCell* buffer, size_t rowWidth, ROW* const pParent) noexcept :
|
||||
_data(buffer, rowWidth),
|
||||
_pParent{ FAIL_FAST_IF_NULL(pParent) }
|
||||
{
|
||||
}
|
||||
@@ -53,38 +53,9 @@ void CharRow::Reset() noexcept
|
||||
// - resizes the width of the CharRowBase
|
||||
// Arguments:
|
||||
// - newSize - the new width of the character and attributes rows
|
||||
// Return Value:
|
||||
// - S_OK on success, otherwise relevant error code
|
||||
[[nodiscard]] HRESULT CharRow::Resize(const size_t newSize) noexcept
|
||||
void CharRow::Resize(CharRowCell* buffer, const size_t newSize) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
const value_type insertVals;
|
||||
_data.resize(newSize, insertVals);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
typename CharRow::iterator CharRow::begin() noexcept
|
||||
{
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
typename CharRow::const_iterator CharRow::cbegin() const noexcept
|
||||
{
|
||||
return _data.cbegin();
|
||||
}
|
||||
|
||||
typename CharRow::iterator CharRow::end() noexcept
|
||||
{
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
typename CharRow::const_iterator CharRow::cend() const noexcept
|
||||
{
|
||||
return _data.cend();
|
||||
_data = {buffer, newSize};
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -95,12 +66,16 @@ typename CharRow::const_iterator CharRow::cend() const noexcept
|
||||
// - The calculated left boundary of the internal string.
|
||||
size_t CharRow::MeasureLeft() const noexcept
|
||||
{
|
||||
const_iterator it = _data.cbegin();
|
||||
while (it != _data.cend() && it->IsSpace())
|
||||
const auto beg = _data.begin();
|
||||
const auto end = _data.end();
|
||||
|
||||
auto it = beg;
|
||||
while (it != end && it->IsSpace())
|
||||
{
|
||||
++it;
|
||||
}
|
||||
return it - _data.cbegin();
|
||||
|
||||
return it - beg;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -111,17 +86,21 @@ size_t CharRow::MeasureLeft() const noexcept
|
||||
// - The calculated right boundary of the internal string.
|
||||
size_t CharRow::MeasureRight() const
|
||||
{
|
||||
const_reverse_iterator it = _data.crbegin();
|
||||
while (it != _data.crend() && it->IsSpace())
|
||||
const auto beg = _data.rbegin();
|
||||
const auto end = _data.rend();
|
||||
|
||||
auto it = beg;
|
||||
while (it != end && it->IsSpace())
|
||||
{
|
||||
++it;
|
||||
}
|
||||
return _data.crend() - it;
|
||||
|
||||
return end - it;
|
||||
}
|
||||
|
||||
void CharRow::ClearCell(const size_t column)
|
||||
{
|
||||
_data.at(column).Reset();
|
||||
_data[column].Reset();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -132,7 +111,7 @@ void CharRow::ClearCell(const size_t column)
|
||||
// - True if there is valid text in this row. False otherwise.
|
||||
bool CharRow::ContainsText() const noexcept
|
||||
{
|
||||
for (const value_type& cell : _data)
|
||||
for (const auto& cell : _data)
|
||||
{
|
||||
if (!cell.IsSpace())
|
||||
{
|
||||
@@ -151,7 +130,7 @@ bool CharRow::ContainsText() const noexcept
|
||||
// Note: will throw exception if column is out of bounds
|
||||
const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
|
||||
{
|
||||
return _data.at(column).DbcsAttr();
|
||||
return _data[column].DbcsAttr();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -163,7 +142,7 @@ const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
|
||||
// Note: will throw exception if column is out of bounds
|
||||
DbcsAttribute& CharRow::DbcsAttrAt(const size_t column)
|
||||
{
|
||||
return _data.at(column).DbcsAttr();
|
||||
return _data[column].DbcsAttr();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -175,7 +154,7 @@ DbcsAttribute& CharRow::DbcsAttrAt(const size_t column)
|
||||
// Note: will throw exception if column is out of bounds
|
||||
void CharRow::ClearGlyph(const size_t column)
|
||||
{
|
||||
_data.at(column).EraseChars();
|
||||
_data[column].EraseChars();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -49,15 +49,12 @@ class CharRow final
|
||||
public:
|
||||
using glyph_type = typename wchar_t;
|
||||
using value_type = typename CharRowCell;
|
||||
using iterator = typename boost::container::small_vector_base<value_type>::iterator;
|
||||
using const_iterator = typename boost::container::small_vector_base<value_type>::const_iterator;
|
||||
using const_reverse_iterator = typename boost::container::small_vector_base<value_type>::const_reverse_iterator;
|
||||
using reference = typename CharRowCellReference;
|
||||
|
||||
CharRow(size_t rowWidth, ROW* const pParent) noexcept;
|
||||
CharRow(CharRowCell* buffer, size_t rowWidth, ROW* const pParent) noexcept;
|
||||
|
||||
size_t size() const noexcept;
|
||||
[[nodiscard]] HRESULT Resize(const size_t newSize) noexcept;
|
||||
void Resize(CharRowCell* buffer, const size_t newSize) noexcept;
|
||||
size_t MeasureLeft() const noexcept;
|
||||
size_t MeasureRight() const;
|
||||
bool ContainsText() const noexcept;
|
||||
@@ -71,14 +68,25 @@ public:
|
||||
const reference GlyphAt(const size_t column) const;
|
||||
reference GlyphAt(const size_t column);
|
||||
|
||||
// iterators
|
||||
iterator begin() noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
const_iterator begin() const noexcept { return cbegin(); }
|
||||
auto begin() noexcept
|
||||
{
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
iterator end() noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
const_iterator end() const noexcept { return cend(); }
|
||||
auto begin() const noexcept
|
||||
{
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
auto end() noexcept
|
||||
{
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
auto end() const noexcept
|
||||
{
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
UnicodeStorage& GetUnicodeStorage() noexcept;
|
||||
const UnicodeStorage& GetUnicodeStorage() const noexcept;
|
||||
@@ -96,20 +104,21 @@ private:
|
||||
|
||||
protected:
|
||||
// storage for glyph data and dbcs attributes
|
||||
boost::container::small_vector<value_type, 120> _data;
|
||||
gsl::span<CharRowCell> _data;
|
||||
|
||||
// ROW that this CharRow belongs to
|
||||
ROW* _pParent;
|
||||
};
|
||||
|
||||
template<typename InputIt1, typename InputIt2>
|
||||
void OverwriteColumns(InputIt1 startChars, InputIt1 endChars, InputIt2 startAttrs, CharRow::iterator outIt)
|
||||
template<typename InputIt1, typename InputIt2, typename OutputIt>
|
||||
void OverwriteColumns(InputIt1 startChars, InputIt1 endChars, InputIt2 startAttrs, OutputIt outIt)
|
||||
{
|
||||
std::transform(startChars,
|
||||
endChars,
|
||||
startAttrs,
|
||||
outIt,
|
||||
[](const wchar_t wch, const DbcsAttribute attr) {
|
||||
return CharRow::value_type{ wch, attr };
|
||||
});
|
||||
std::transform(
|
||||
startChars,
|
||||
endChars,
|
||||
startAttrs,
|
||||
outIt,
|
||||
[](const wchar_t wch, const DbcsAttribute attr) {
|
||||
return CharRow::value_type{ wch, attr };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ CharRowCellReference::operator std::wstring_view() const
|
||||
// - ref to the CharRowCell
|
||||
CharRowCell& CharRowCellReference::_cellData()
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
return _parent._data[_index];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -50,7 +50,7 @@ CharRowCell& CharRowCellReference::_cellData()
|
||||
// - ref to the CharRowCell
|
||||
const CharRowCell& CharRowCellReference::_cellData() const
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
return _parent._data[_index];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
// - pParent - the text buffer that this row belongs to
|
||||
// Return Value:
|
||||
// - constructed object
|
||||
ROW::ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent) :
|
||||
ROW::ROW(const SHORT rowId, CharRowCell* buffer, const unsigned short rowWidth, const TextAttribute& fillAttribute, TextBuffer* const pParent) :
|
||||
_id{ rowId },
|
||||
_rowWidth{ rowWidth },
|
||||
_charRow{ rowWidth, this },
|
||||
_charRow{ buffer, rowWidth, this },
|
||||
_attrRow{ rowWidth, fillAttribute },
|
||||
_lineRendition{ LineRendition::SingleWidth },
|
||||
_wrapForced{ false },
|
||||
@@ -34,7 +33,7 @@ ROW::ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute f
|
||||
// - Attr - The default attribute (color) to fill
|
||||
// Return Value:
|
||||
// - <none>
|
||||
bool ROW::Reset(const TextAttribute Attr)
|
||||
bool ROW::Reset(const TextAttribute& Attr)
|
||||
{
|
||||
_lineRendition = LineRendition::SingleWidth;
|
||||
_wrapForced = false;
|
||||
@@ -52,26 +51,6 @@ bool ROW::Reset(const TextAttribute Attr)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - resizes ROW to new width
|
||||
// Arguments:
|
||||
// - width - the new width, in cells
|
||||
// Return Value:
|
||||
// - S_OK if successful, otherwise relevant error
|
||||
[[nodiscard]] HRESULT ROW::Resize(const unsigned short width)
|
||||
{
|
||||
RETURN_IF_FAILED(_charRow.Resize(width));
|
||||
try
|
||||
{
|
||||
_attrRow.Resize(width);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
_rowWidth = width;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - clears char data in column in row
|
||||
// Arguments:
|
||||
|
||||
@@ -32,9 +32,9 @@ class TextBuffer;
|
||||
class ROW final
|
||||
{
|
||||
public:
|
||||
ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent);
|
||||
ROW(const SHORT rowId, CharRowCell* buffer, const unsigned short rowWidth, const TextAttribute& fillAttribute, TextBuffer* const pParent);
|
||||
|
||||
size_t size() const noexcept { return _rowWidth; }
|
||||
size_t size() const noexcept { return _charRow.size(); }
|
||||
|
||||
void SetWrapForced(const bool wrap) noexcept { _wrapForced = wrap; }
|
||||
bool WasWrapForced() const noexcept { return _wrapForced; }
|
||||
@@ -54,8 +54,7 @@ public:
|
||||
SHORT GetId() const noexcept { return _id; }
|
||||
void SetId(const SHORT id) noexcept { _id = id; }
|
||||
|
||||
bool Reset(const TextAttribute Attr);
|
||||
[[nodiscard]] HRESULT Resize(const unsigned short width);
|
||||
bool Reset(const TextAttribute& Attr);
|
||||
|
||||
void ClearColumn(const size_t column);
|
||||
std::wstring GetText() const { return _charRow.GetText(); }
|
||||
@@ -74,13 +73,12 @@ private:
|
||||
CharRow _charRow;
|
||||
ATTR_ROW _attrRow;
|
||||
LineRendition _lineRendition;
|
||||
TextBuffer* _pParent; // non ownership pointer
|
||||
SHORT _id;
|
||||
unsigned short _rowWidth;
|
||||
// Occurs when the user runs out of text in a given row and we're forced to wrap the cursor to the next line
|
||||
bool _wrapForced;
|
||||
// Occurs when the user runs out of text to support a double byte character and we're forced to the next line
|
||||
bool _doubleBytePadded;
|
||||
TextBuffer* _pParent; // non ownership pointer
|
||||
};
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
|
||||
@@ -212,7 +212,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
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ void UnicodeStorage::Erase(const key_type key) noexcept
|
||||
// - rowMap - A map of the old row IDs to the new row IDs.
|
||||
// - width - The width of the new row. Remove any items that are beyond the row width.
|
||||
// - Use nullopt if we're not resizing the width of the row, just renumbering the rows.
|
||||
void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width)
|
||||
void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, SHORT width)
|
||||
{
|
||||
// Make a temporary map to hold all the new row positioning
|
||||
std::unordered_map<key_type, mapped_type> newMap;
|
||||
@@ -58,18 +58,10 @@ void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const
|
||||
// Extract the old coordinate position
|
||||
const auto oldCoord = pair.first;
|
||||
|
||||
// Only try to short-circuit based on width if we were told it changed
|
||||
// by being given a new width value.
|
||||
if (width.has_value())
|
||||
// If the column index is at/beyond the row width, don't bother copying it to the new map.
|
||||
if (oldCoord.X >= width)
|
||||
{
|
||||
// Get the column ID
|
||||
const auto oldColId = oldCoord.X;
|
||||
|
||||
// If the column index is at/beyond the row width, don't bother copying it to the new map.
|
||||
if (oldColId >= width.value())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the row ID from the position as that's what we need to remap
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
|
||||
void Erase(const key_type key) noexcept;
|
||||
|
||||
void Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width);
|
||||
void Remap(const std::unordered_map<SHORT, SHORT>& rowMap, SHORT width);
|
||||
|
||||
private:
|
||||
std::unordered_map<key_type, mapped_type> _map;
|
||||
|
||||
@@ -31,26 +31,32 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
|
||||
const TextAttribute defaultAttributes,
|
||||
const UINT cursorSize,
|
||||
Microsoft::Console::Render::IRenderTarget& renderTarget) :
|
||||
_firstRow{ 0 },
|
||||
_currentAttributes{ defaultAttributes },
|
||||
_cursor{ cursorSize, *this },
|
||||
_storage{},
|
||||
_unicodeStorage{},
|
||||
_renderTarget{ renderTarget },
|
||||
_size{},
|
||||
_currentHyperlinkId{ 1 },
|
||||
_currentPatternId{ 0 }
|
||||
_renderTarget{ renderTarget }
|
||||
{
|
||||
// initialize ROWs
|
||||
const auto dx = static_cast<size_t>(screenBufferSize.X);
|
||||
const auto dy = static_cast<size_t>(screenBufferSize.Y);
|
||||
auto buffer = static_cast<CharRowCell*>(VirtualAlloc(nullptr, dx * dy * sizeof(CharRowCell), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
|
||||
THROW_IF_NULL_ALLOC(buffer);
|
||||
|
||||
_charBuffer = buffer;
|
||||
|
||||
_storage.reserve(static_cast<size_t>(screenBufferSize.Y));
|
||||
for (size_t i = 0; i < static_cast<size_t>(screenBufferSize.Y); ++i)
|
||||
for (SHORT i = 0; i < screenBufferSize.Y; ++i)
|
||||
{
|
||||
_storage.emplace_back(static_cast<SHORT>(i), screenBufferSize.X, _currentAttributes, this);
|
||||
_storage.emplace_back(i, buffer, screenBufferSize.X, _currentAttributes, this);
|
||||
buffer += dx;
|
||||
}
|
||||
|
||||
_UpdateSize();
|
||||
}
|
||||
|
||||
TextBuffer::~TextBuffer()
|
||||
{
|
||||
VirtualFree(_charBuffer, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Copies properties from another text buffer into this one.
|
||||
// - This is primarily to copy properties that would otherwise not be specified during CreateInstance
|
||||
@@ -83,11 +89,9 @@ UINT TextBuffer::TotalRowCount() const noexcept
|
||||
// - const reference to the requested row. Asserts if out of bounds.
|
||||
const ROW& TextBuffer::GetRowByOffset(const size_t index) const
|
||||
{
|
||||
const size_t totalRows = TotalRowCount();
|
||||
|
||||
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
|
||||
const size_t offsetIndex = (_firstRow + index) % totalRows;
|
||||
return _storage.at(offsetIndex);
|
||||
const size_t offsetIndex = (_firstRow + index) % _storage.size();
|
||||
return _storage[offsetIndex];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -99,11 +103,9 @@ const ROW& TextBuffer::GetRowByOffset(const size_t index) const
|
||||
// - reference to the requested row. Asserts if out of bounds.
|
||||
ROW& TextBuffer::GetRowByOffset(const size_t index)
|
||||
{
|
||||
const size_t totalRows = TotalRowCount();
|
||||
|
||||
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
|
||||
const size_t offsetIndex = (_firstRow + index) % totalRows;
|
||||
return _storage.at(offsetIndex);
|
||||
const size_t offsetIndex = (_firstRow + index) % _storage.size();
|
||||
return _storage[offsetIndex];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -400,7 +402,7 @@ OutputCellIterator TextBuffer::WriteLine(const OutputCellIterator givenIt,
|
||||
//Return Value:
|
||||
// - true if we successfully inserted the character
|
||||
// - false otherwise (out of memory)
|
||||
bool TextBuffer::InsertCharacter(const std::wstring_view chars,
|
||||
bool TextBuffer::InsertCharacter(const std::wstring_view& chars,
|
||||
const DbcsAttribute dbcsAttribute,
|
||||
const TextAttribute attr)
|
||||
{
|
||||
@@ -779,7 +781,7 @@ void TextBuffer::ScrollRows(const SHORT firstRow, const SHORT size, const SHORT
|
||||
|
||||
// Renumber the IDs now that we've rearranged where the rows sit within the buffer.
|
||||
// Refreshing should also delegate to the UnicodeStorage to re-key all the stored unicode sequences (where applicable).
|
||||
_RefreshRowIDs(std::nullopt);
|
||||
_RefreshRowIDs(_size.Width());
|
||||
}
|
||||
|
||||
Cursor& TextBuffer::GetCursor() noexcept
|
||||
@@ -897,6 +899,11 @@ void TextBuffer::Reset()
|
||||
{
|
||||
RETURN_HR_IF(E_INVALIDARG, newSize.X < 0 || newSize.Y < 0);
|
||||
|
||||
const auto dx = static_cast<size_t>(newSize.X);
|
||||
const auto dy = static_cast<size_t>(newSize.Y);
|
||||
auto buffer = static_cast<CharRowCell*>(VirtualAlloc(nullptr, dx * dy * sizeof(CharRowCell), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
|
||||
RETURN_IF_NULL_ALLOC(buffer);
|
||||
|
||||
try
|
||||
{
|
||||
const auto currentSize = GetSize().Dimensions();
|
||||
@@ -910,12 +917,7 @@ void TextBuffer::Reset()
|
||||
const SHORT TopRowIndex = (GetFirstRowIndex() + TopRow) % currentSize.Y;
|
||||
|
||||
// rotate rows until the top row is at index 0
|
||||
for (int i = 0; i < TopRowIndex; i++)
|
||||
{
|
||||
_storage.emplace_back(std::move(_storage.front()));
|
||||
_storage.erase(_storage.begin());
|
||||
}
|
||||
|
||||
std::rotate(_storage.begin(), _storage.begin() + TopRowIndex, _storage.end());
|
||||
_SetFirstRowIndex(0);
|
||||
|
||||
// realloc in the Y direction
|
||||
@@ -927,19 +929,26 @@ void TextBuffer::Reset()
|
||||
// add rows if we're growing
|
||||
while (_storage.size() < static_cast<size_t>(newSize.Y))
|
||||
{
|
||||
_storage.emplace_back(static_cast<short>(_storage.size()), newSize.X, attributes, this);
|
||||
_storage.emplace_back(static_cast<short>(_storage.size()), nullptr, newSize.X, attributes, this);
|
||||
}
|
||||
|
||||
// Now that we've tampered with the row placement, refresh all the row IDs.
|
||||
// Also take advantage of the row ID refresh loop to resize the rows in the X dimension
|
||||
// and cleanup the UnicodeStorage characters that might fall outside the resized buffer.
|
||||
_RefreshRowIDs(newSize.X);
|
||||
_RefreshRowWidth(buffer, newSize.X);
|
||||
|
||||
// Update the cached size value
|
||||
_UpdateSize();
|
||||
}
|
||||
CATCH_RETURN();
|
||||
catch (...)
|
||||
{
|
||||
VirtualFree(buffer, 0, MEM_RELEASE);
|
||||
RETURN_CAUGHT_EXCEPTION();
|
||||
};
|
||||
|
||||
VirtualFree(_charBuffer, 0, MEM_RELEASE);
|
||||
_charBuffer = buffer;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -962,7 +971,7 @@ UnicodeStorage& TextBuffer::GetUnicodeStorage() noexcept
|
||||
// any high unicode (UnicodeStorage) runs while we're already looping through the rows.
|
||||
// Arguments:
|
||||
// - newRowWidth - Optional new value for the row width.
|
||||
void TextBuffer::_RefreshRowIDs(std::optional<SHORT> newRowWidth)
|
||||
void TextBuffer::_RefreshRowIDs(SHORT width)
|
||||
{
|
||||
std::unordered_map<SHORT, SHORT> rowMap;
|
||||
SHORT i = 0;
|
||||
@@ -976,17 +985,19 @@ void TextBuffer::_RefreshRowIDs(std::optional<SHORT> newRowWidth)
|
||||
|
||||
// Also update the char row parent pointers as they can get shuffled up in the rotates.
|
||||
it.GetCharRow().UpdateParent(&it);
|
||||
|
||||
// Resize the rows in the X dimension if we have a new width
|
||||
if (newRowWidth.has_value())
|
||||
{
|
||||
// Realloc in the X direction
|
||||
THROW_IF_FAILED(it.Resize(newRowWidth.value()));
|
||||
}
|
||||
}
|
||||
|
||||
// Give the new mapping to Unicode Storage
|
||||
_unicodeStorage.Remap(rowMap, newRowWidth);
|
||||
_unicodeStorage.Remap(rowMap, width);
|
||||
}
|
||||
|
||||
void TextBuffer::_RefreshRowWidth(CharRowCell *data, size_t width) noexcept
|
||||
{
|
||||
for (auto& it : _storage)
|
||||
{
|
||||
it.GetCharRow().Resize(data, width);
|
||||
data += width;
|
||||
}
|
||||
}
|
||||
|
||||
void TextBuffer::_NotifyPaint(const Viewport& viewport) const
|
||||
@@ -1045,7 +1056,7 @@ Microsoft::Console::Render::IRenderTarget& TextBuffer::GetRenderTarget() noexcep
|
||||
// - wordDelimiters: the delimiters defined as a part of the DelimiterClass::DelimiterChar
|
||||
// Return Value:
|
||||
// - the delimiter class for the given char
|
||||
const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const
|
||||
const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
return GetRowByOffset(pos.Y).GetCharRow().DelimiterClassAt(pos.X, wordDelimiters);
|
||||
}
|
||||
@@ -1060,7 +1071,7 @@ const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std
|
||||
// (or a row boundary is encountered)
|
||||
// Return Value:
|
||||
// - The COORD for the first character on the "word" (inclusive)
|
||||
const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode) const
|
||||
const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode) const
|
||||
{
|
||||
// Consider a buffer with this text in it:
|
||||
// " word other "
|
||||
@@ -1105,7 +1116,7 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The COORD for the first character on the current/previous READABLE "word" (inclusive)
|
||||
const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const
|
||||
const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
COORD result = target;
|
||||
const auto bufferSize = GetSize();
|
||||
@@ -1150,7 +1161,7 @@ const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The COORD for the first character on the current word or delimiter run (stopped by the left margin)
|
||||
const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const
|
||||
const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
COORD result = target;
|
||||
const auto bufferSize = GetSize();
|
||||
@@ -1182,7 +1193,7 @@ const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std:
|
||||
// (or a row boundary is encountered)
|
||||
// Return Value:
|
||||
// - The COORD for the last character on the "word" (inclusive)
|
||||
const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode) const
|
||||
const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode) const
|
||||
{
|
||||
// Consider a buffer with this text in it:
|
||||
// " word other "
|
||||
@@ -1219,7 +1230,7 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w
|
||||
// - lastCharPos - the position of the last nonspace character in the text buffer (to improve performance)
|
||||
// Return Value:
|
||||
// - The COORD for the first character of the next readable "word". If no next word, return one past the end of the buffer
|
||||
const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD lastCharPos) const
|
||||
const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view& wordDelimiters, const COORD lastCharPos) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
COORD result = target;
|
||||
@@ -1267,7 +1278,7 @@ const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const st
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The COORD for the last character of the current word or delimiter run (stopped by right margin)
|
||||
const COORD TextBuffer::_GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const
|
||||
const COORD TextBuffer::_GetWordEndForSelection(const COORD target, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
|
||||
@@ -1350,7 +1361,7 @@ void TextBuffer::_PruneHyperlinks()
|
||||
// Return Value:
|
||||
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
|
||||
// - pos - The COORD for the first character on the "word" (inclusive)
|
||||
bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, COORD lastCharPos) const
|
||||
bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view& wordDelimiters, COORD lastCharPos) const
|
||||
{
|
||||
// move to the beginning of the next word
|
||||
// NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word"
|
||||
@@ -1374,7 +1385,7 @@ bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimite
|
||||
// Return Value:
|
||||
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
|
||||
// - pos - The COORD for the first character on the "word" (inclusive)
|
||||
bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters) const
|
||||
bool TextBuffer::MoveToPreviousWord(COORD& pos, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
// move to the beginning of the current word
|
||||
auto copy{ GetWordStart(pos, wordDelimiters, true) };
|
||||
@@ -1732,7 +1743,7 @@ const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
|
||||
// - string containing the generated HTML
|
||||
std::string TextBuffer::GenHTML(const TextAndColor& rows,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const std::wstring_view& fontFaceName,
|
||||
const COLORREF backgroundColor)
|
||||
{
|
||||
try
|
||||
@@ -1795,7 +1806,7 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows,
|
||||
const auto writeAccumulatedChars = [&](bool includeCurrent) {
|
||||
if (col >= startOffset)
|
||||
{
|
||||
const auto unescapedText = ConvertToA(CP_UTF8, std::wstring_view(rows.text.at(row)).substr(startOffset, col - startOffset + includeCurrent));
|
||||
const auto unescapedText = ConvertToA(CP_UTF8, rows.text.at(row).substr(startOffset, col - startOffset + includeCurrent));
|
||||
for (const auto c : unescapedText)
|
||||
{
|
||||
switch (c)
|
||||
@@ -1921,7 +1932,7 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows,
|
||||
// - htmlTitle - value used in title tag of html header. Used to name the application
|
||||
// Return Value:
|
||||
// - string containing the generated RTF
|
||||
std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoints, const std::wstring_view fontFaceName, const COLORREF backgroundColor)
|
||||
std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoints, const std::wstring_view& fontFaceName, const COLORREF backgroundColor)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1983,7 +1994,7 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
|
||||
const auto writeAccumulatedChars = [&](bool includeCurrent) {
|
||||
if (col >= startOffset)
|
||||
{
|
||||
const auto unescapedText = ConvertToA(CP_UTF8, std::wstring_view(rows.text.at(row)).substr(startOffset, col - startOffset + includeCurrent));
|
||||
const auto unescapedText = ConvertToA(CP_UTF8, rows.text.at(row).substr(startOffset, col - startOffset + includeCurrent));
|
||||
for (const auto c : unescapedText)
|
||||
{
|
||||
switch (c)
|
||||
@@ -2361,9 +2372,9 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
|
||||
// - Adds or updates a hyperlink in our hyperlink table
|
||||
// Arguments:
|
||||
// - The hyperlink URI, the hyperlink id (could be new or old)
|
||||
void TextBuffer::AddHyperlinkToMap(std::wstring_view uri, uint16_t id)
|
||||
void TextBuffer::AddHyperlinkToMap(const std::wstring_view& uri, uint16_t id)
|
||||
{
|
||||
_hyperlinkMap[id] = uri;
|
||||
_hyperlinkMap.emplace(id, uri);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -2383,28 +2394,31 @@ std::wstring TextBuffer::GetHyperlinkUriFromId(uint16_t id) const
|
||||
// - The user-defined id
|
||||
// Return value:
|
||||
// - The internal hyperlink ID
|
||||
uint16_t TextBuffer::GetHyperlinkId(std::wstring_view uri, std::wstring_view id)
|
||||
uint16_t TextBuffer::GetHyperlinkId(const std::wstring_view& uri, const std::wstring_view& id)
|
||||
{
|
||||
uint16_t numericId = 0;
|
||||
if (id.empty())
|
||||
{
|
||||
// no custom id specified, return our internal count
|
||||
numericId = _currentHyperlinkId;
|
||||
++_currentHyperlinkId;
|
||||
numericId = _currentHyperlinkId++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// assign _currentHyperlinkId if the custom id does not already exist
|
||||
std::wstring newId{ id };
|
||||
// hash the URL and add it to the custom ID - GH#7698
|
||||
newId += L"%" + std::to_wstring(std::hash<std::wstring_view>{}(uri));
|
||||
const auto result = _hyperlinkCustomIdMap.emplace(newId, _currentHyperlinkId);
|
||||
// We need to use both uri and id for hashing. See GH#7698
|
||||
std::wstring key;
|
||||
key.reserve(uri.size() + id.size());
|
||||
key.append(uri);
|
||||
key.append(id);
|
||||
|
||||
const auto result = _hyperlinkCustomIdMap.emplace(key, _currentHyperlinkId);
|
||||
numericId = result.first->second;
|
||||
|
||||
if (result.second)
|
||||
{
|
||||
// the custom id did not already exist
|
||||
_hyperlinkCustomIdMapReverse.insert_or_assign(_currentHyperlinkId, key);
|
||||
++_currentHyperlinkId;
|
||||
}
|
||||
numericId = (*(result.first)).second;
|
||||
}
|
||||
// _currentHyperlinkId could overflow, make sure its not 0
|
||||
if (_currentHyperlinkId == 0)
|
||||
@@ -2422,13 +2436,11 @@ uint16_t TextBuffer::GetHyperlinkId(std::wstring_view uri, std::wstring_view id)
|
||||
void TextBuffer::RemoveHyperlinkFromMap(uint16_t id) noexcept
|
||||
{
|
||||
_hyperlinkMap.erase(id);
|
||||
for (const auto& customIdPair : _hyperlinkCustomIdMap)
|
||||
|
||||
if (auto it = _hyperlinkCustomIdMapReverse.find(id); it != _hyperlinkCustomIdMapReverse.end())
|
||||
{
|
||||
if (customIdPair.second == id)
|
||||
{
|
||||
_hyperlinkCustomIdMap.erase(customIdPair.first);
|
||||
break;
|
||||
}
|
||||
_hyperlinkCustomIdMap.erase(it->second);
|
||||
_hyperlinkCustomIdMapReverse.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2441,12 +2453,9 @@ void TextBuffer::RemoveHyperlinkFromMap(uint16_t id) noexcept
|
||||
// - The custom ID if there was one, empty string otherwise
|
||||
std::wstring TextBuffer::GetCustomIdFromId(uint16_t id) const
|
||||
{
|
||||
for (auto customIdPair : _hyperlinkCustomIdMap)
|
||||
if (auto it = _hyperlinkCustomIdMapReverse.find(id); it != _hyperlinkCustomIdMapReverse.end())
|
||||
{
|
||||
if (customIdPair.second == id)
|
||||
{
|
||||
return customIdPair.first;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -2460,6 +2469,7 @@ void TextBuffer::CopyHyperlinkMaps(const TextBuffer& other)
|
||||
{
|
||||
_hyperlinkMap = other._hyperlinkMap;
|
||||
_hyperlinkCustomIdMap = other._hyperlinkCustomIdMap;
|
||||
_hyperlinkCustomIdMapReverse = other._hyperlinkCustomIdMapReverse;
|
||||
_currentHyperlinkId = other._currentHyperlinkId;
|
||||
}
|
||||
|
||||
@@ -2470,7 +2480,7 @@ void TextBuffer::CopyHyperlinkMaps(const TextBuffer& other)
|
||||
// - The regex pattern
|
||||
// Return value:
|
||||
// - An ID that the caller should associate with the given pattern
|
||||
const size_t TextBuffer::AddPatternRecognizer(const std::wstring_view regexString)
|
||||
const size_t TextBuffer::AddPatternRecognizer(const std::wstring_view& regexString)
|
||||
{
|
||||
++_currentPatternId;
|
||||
_idsAndPatterns.emplace(std::make_pair(_currentPatternId, regexString));
|
||||
|
||||
@@ -69,6 +69,9 @@ public:
|
||||
const TextAttribute defaultAttributes,
|
||||
const UINT cursorSize,
|
||||
Microsoft::Console::Render::IRenderTarget& renderTarget);
|
||||
|
||||
~TextBuffer();
|
||||
|
||||
TextBuffer(const TextBuffer& a) = delete;
|
||||
|
||||
// Used for duplicating properties to another text buffer
|
||||
@@ -98,7 +101,7 @@ public:
|
||||
const std::optional<size_t> limitRight = std::nullopt);
|
||||
|
||||
bool InsertCharacter(const wchar_t wch, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
bool InsertCharacter(const std::wstring_view chars, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
bool InsertCharacter(const std::wstring_view& chars, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
bool IncrementCursor();
|
||||
bool NewlineCursor();
|
||||
|
||||
@@ -141,10 +144,10 @@ public:
|
||||
|
||||
Microsoft::Console::Render::IRenderTarget& GetRenderTarget() noexcept;
|
||||
|
||||
const COORD GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false) const;
|
||||
const COORD GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false) const;
|
||||
bool MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, COORD lastCharPos) const;
|
||||
bool MoveToPreviousWord(COORD& pos, const std::wstring_view wordDelimiters) const;
|
||||
const COORD GetWordStart(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode = false) const;
|
||||
const COORD GetWordEnd(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode = false) const;
|
||||
bool MoveToNextWord(COORD& pos, const std::wstring_view& wordDelimiters, COORD lastCharPos) const;
|
||||
bool MoveToPreviousWord(COORD& pos, const std::wstring_view& wordDelimiters) const;
|
||||
|
||||
const til::point GetGlyphStart(const til::point pos) const;
|
||||
const til::point GetGlyphEnd(const til::point pos) const;
|
||||
@@ -153,9 +156,9 @@ public:
|
||||
|
||||
const std::vector<SMALL_RECT> GetTextRects(COORD start, COORD end, bool blockSelection, bool bufferCoordinates) const;
|
||||
|
||||
void AddHyperlinkToMap(std::wstring_view uri, uint16_t id);
|
||||
void AddHyperlinkToMap(const std::wstring_view& uri, uint16_t id);
|
||||
std::wstring GetHyperlinkUriFromId(uint16_t id) const;
|
||||
uint16_t GetHyperlinkId(std::wstring_view uri, std::wstring_view id);
|
||||
uint16_t GetHyperlinkId(const std::wstring_view& uri, const std::wstring_view& id);
|
||||
void RemoveHyperlinkFromMap(uint16_t id) noexcept;
|
||||
std::wstring GetCustomIdFromId(uint16_t id) const;
|
||||
void CopyHyperlinkMaps(const TextBuffer& OtherBuffer);
|
||||
@@ -176,12 +179,12 @@ public:
|
||||
|
||||
static std::string GenHTML(const TextAndColor& rows,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const std::wstring_view& fontFaceName,
|
||||
const COLORREF backgroundColor);
|
||||
|
||||
static std::string GenRTF(const TextAndColor& rows,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const std::wstring_view& fontFaceName,
|
||||
const COLORREF backgroundColor);
|
||||
|
||||
struct PositionInformation
|
||||
@@ -195,60 +198,47 @@ public:
|
||||
const std::optional<Microsoft::Console::Types::Viewport> lastCharacterViewport,
|
||||
std::optional<std::reference_wrapper<PositionInformation>> positionInfo);
|
||||
|
||||
const size_t AddPatternRecognizer(const std::wstring_view regexString);
|
||||
const size_t AddPatternRecognizer(const std::wstring_view& regexString);
|
||||
void ClearPatternRecognizers() noexcept;
|
||||
void CopyPatterns(const TextBuffer& OtherBuffer);
|
||||
interval_tree::IntervalTree<til::point, size_t> GetPatterns(const size_t firstRow, const size_t lastRow) const;
|
||||
|
||||
private:
|
||||
void _UpdateSize();
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
std::vector<ROW> _storage;
|
||||
Cursor _cursor;
|
||||
|
||||
SHORT _firstRow; // indexes top row (not necessarily 0)
|
||||
|
||||
TextAttribute _currentAttributes;
|
||||
|
||||
// storage location for glyphs that can't fit into the buffer normally
|
||||
UnicodeStorage _unicodeStorage;
|
||||
|
||||
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
|
||||
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
|
||||
uint16_t _currentHyperlinkId;
|
||||
|
||||
void _RefreshRowIDs(std::optional<SHORT> newRowWidth);
|
||||
|
||||
Microsoft::Console::Render::IRenderTarget& _renderTarget;
|
||||
|
||||
void _RefreshRowIDs(SHORT width);
|
||||
void _RefreshRowWidth(CharRowCell* data, size_t width) noexcept;
|
||||
void _SetFirstRowIndex(const SHORT FirstRowIndex) noexcept;
|
||||
|
||||
COORD _GetPreviousFromCursor() const;
|
||||
|
||||
void _SetWrapOnCurrentRow();
|
||||
void _AdjustWrapOnCurrentRow(const bool fSet);
|
||||
|
||||
void _NotifyPaint(const Microsoft::Console::Types::Viewport& viewport) const;
|
||||
|
||||
// Assist with maintaining proper buffer state for Double Byte character sequences
|
||||
bool _PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute);
|
||||
bool _AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribute);
|
||||
|
||||
ROW& _GetFirstRow();
|
||||
ROW& _GetPrevRowNoWrap(const ROW& row);
|
||||
|
||||
void _ExpandTextRow(SMALL_RECT& selectionRow) const;
|
||||
|
||||
const DelimiterClass _GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const;
|
||||
const COORD _GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const;
|
||||
const COORD _GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const;
|
||||
const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD lastCharPos) const;
|
||||
const COORD _GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const;
|
||||
|
||||
const DelimiterClass _GetDelimiterClassAt(const COORD pos, const std::wstring_view& wordDelimiters) const;
|
||||
const COORD _GetWordStartForAccessibility(const COORD target, const std::wstring_view& wordDelimiters) const;
|
||||
const COORD _GetWordStartForSelection(const COORD target, const std::wstring_view& wordDelimiters) const;
|
||||
const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view& wordDelimiters, const COORD lastCharPos) const;
|
||||
const COORD _GetWordEndForSelection(const COORD target, const std::wstring_view& wordDelimiters) const;
|
||||
void _PruneHyperlinks();
|
||||
|
||||
Microsoft::Console::Render::IRenderTarget& _renderTarget;
|
||||
std::vector<ROW> _storage;
|
||||
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
|
||||
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
|
||||
std::unordered_map<uint16_t, std::wstring> _hyperlinkCustomIdMapReverse;
|
||||
std::unordered_map<size_t, std::wstring> _idsAndPatterns;
|
||||
size_t _currentPatternId;
|
||||
TextAttribute _currentAttributes;
|
||||
UnicodeStorage _unicodeStorage;
|
||||
Cursor _cursor;
|
||||
void* _charBuffer;
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
uint16_t _currentHyperlinkId{ 1 };
|
||||
size_t _currentPatternId{ 0 };
|
||||
SHORT _firstRow{ 0 }; // indexes top row (not necessarily 0)
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TextBufferTests;
|
||||
|
||||
@@ -265,3 +265,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();
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -402,11 +405,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 +469,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ namespace SettingsModelLocalTests
|
||||
void TerminalSettingsTests::TryCreateWinRTType()
|
||||
{
|
||||
TerminalSettings settings;
|
||||
VERIFY_IS_NOT_NULL(settings);
|
||||
auto oldFontSize = settings.FontSize();
|
||||
settings.FontSize(oldFontSize + 5);
|
||||
auto newFontSize = settings.FontSize();
|
||||
@@ -60,7 +59,10 @@ namespace SettingsModelLocalTests
|
||||
|
||||
void TerminalSettingsTests::TestTerminalArgsForBinding()
|
||||
{
|
||||
const std::string settingsJson{ R"(
|
||||
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") };
|
||||
const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") };
|
||||
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -98,11 +100,6 @@ namespace SettingsModelLocalTests
|
||||
]
|
||||
})" };
|
||||
|
||||
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") };
|
||||
const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
auto actionMap = settings.GlobalSettings().ActionMap();
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
@@ -385,7 +382,7 @@ namespace SettingsModelLocalTests
|
||||
void TerminalSettingsTests::MakeSettingsForProfileThatDoesntExist()
|
||||
{
|
||||
// Test that making settings throws when the GUID doesn't exist
|
||||
const std::string settingsString{ R"(
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -401,7 +398,6 @@ namespace SettingsModelLocalTests
|
||||
}
|
||||
]
|
||||
})" };
|
||||
CascadiaSettings settings{ til::u8u16(settingsString) };
|
||||
|
||||
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
|
||||
@@ -449,7 +445,7 @@ namespace SettingsModelLocalTests
|
||||
// defaultProfile that's not in the list, we validate the settings, and
|
||||
// then call MakeSettings(nullopt). The validation should ensure that
|
||||
// the default profile is something reasonable
|
||||
const std::string settingsString{ R"(
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -465,7 +461,6 @@ namespace SettingsModelLocalTests
|
||||
}
|
||||
]
|
||||
})" };
|
||||
CascadiaSettings settings{ til::u8u16(settingsString) };
|
||||
|
||||
VERIFY_ARE_EQUAL(2u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(2u, settings.ActiveProfiles().Size());
|
||||
@@ -487,7 +482,7 @@ namespace SettingsModelLocalTests
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Ensure that setting (or not) a property in the profile that should override a property of the color scheme works correctly."));
|
||||
|
||||
const std::string settings0String{ R"(
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "profile5",
|
||||
"profiles": [
|
||||
@@ -528,8 +523,6 @@ namespace SettingsModelLocalTests
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settings0String) };
|
||||
|
||||
VERIFY_ARE_EQUAL(6u, settings.ActiveProfiles().Size());
|
||||
VERIFY_ARE_EQUAL(2u, settings.GlobalSettings().ColorSchemes().Size());
|
||||
|
||||
|
||||
@@ -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+";
|
||||
}
|
||||
|
||||
@@ -79,7 +79,10 @@ namespace TerminalAppLocalTests
|
||||
// containing a ${profile.name} to replace. When we expand it, it should
|
||||
// have created one command for each profile.
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -111,11 +114,6 @@ namespace TerminalAppLocalTests
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
})" };
|
||||
|
||||
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
@@ -207,7 +205,10 @@ namespace TerminalAppLocalTests
|
||||
// For this test, put an iterable command without a given `name` to
|
||||
// replace. When we expand it, it should still work.
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -238,11 +239,6 @@ namespace TerminalAppLocalTests
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
})" };
|
||||
|
||||
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
@@ -335,7 +331,10 @@ namespace TerminalAppLocalTests
|
||||
// cause bad json to be filled in. Something like a profile with a name
|
||||
// of "Foo\"", so the trailing '"' might break the json parsing.
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -367,11 +366,6 @@ namespace TerminalAppLocalTests
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
})" };
|
||||
|
||||
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
@@ -468,7 +462,7 @@ namespace TerminalAppLocalTests
|
||||
// ├─ first.com
|
||||
// └─ second.com
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -508,8 +502,6 @@ namespace TerminalAppLocalTests
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
@@ -558,7 +550,7 @@ namespace TerminalAppLocalTests
|
||||
// ├─ child1
|
||||
// └─ child2
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -603,8 +595,6 @@ namespace TerminalAppLocalTests
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
@@ -691,7 +681,7 @@ namespace TerminalAppLocalTests
|
||||
// ├─ Split pane, direction: vertical, profile: profile2
|
||||
// └─ Split pane, direction: horizontal, profile: profile2
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -727,8 +717,6 @@ namespace TerminalAppLocalTests
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
@@ -828,7 +816,7 @@ namespace TerminalAppLocalTests
|
||||
// ├─ Profile 2
|
||||
// └─ Profile 3
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -864,8 +852,6 @@ namespace TerminalAppLocalTests
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
@@ -926,7 +912,7 @@ namespace TerminalAppLocalTests
|
||||
// ├─ Split vertically
|
||||
// └─ Split horizontally
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -967,8 +953,6 @@ namespace TerminalAppLocalTests
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
@@ -1071,7 +1055,7 @@ namespace TerminalAppLocalTests
|
||||
// containing a ${profile.name} to replace. When we expand it, it should
|
||||
// have created one command for each profile.
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
CascadiaSettings settings{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -1107,8 +1091,6 @@ namespace TerminalAppLocalTests
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
|
||||
// Since at least one profile does not reference a color scheme,
|
||||
// we add a warning saying "the color scheme is unknown"
|
||||
VERIFY_ARE_EQUAL(1u, settings.Warnings().Size());
|
||||
|
||||
@@ -129,7 +129,6 @@ namespace TerminalAppLocalTests
|
||||
// Verify we can create a WinRT type we authored
|
||||
// Just creating it is enough to know that everything is working.
|
||||
TerminalSettings settings;
|
||||
VERIFY_IS_NOT_NULL(settings);
|
||||
auto oldFontSize = settings.FontSize();
|
||||
settings.FontSize(oldFontSize + 5);
|
||||
auto newFontSize = settings.FontSize();
|
||||
@@ -307,7 +306,7 @@ namespace TerminalAppLocalTests
|
||||
// TerminalPage and not only create them successfully, but also create a
|
||||
// tab using those settings successfully.
|
||||
|
||||
const std::string settingsJson0{ R"(
|
||||
CascadiaSettings settings0{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -324,9 +323,6 @@ namespace TerminalAppLocalTests
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
|
||||
VERIFY_IS_NOT_NULL(settings0);
|
||||
|
||||
// This is super wacky, but we can't just initialize the
|
||||
// com_ptr<impl::TerminalPage> in the lambda and assign it back out of
|
||||
// the lambda. We'll crash trying to get a weak_ref to the TerminalPage
|
||||
@@ -353,7 +349,7 @@ namespace TerminalAppLocalTests
|
||||
//
|
||||
// Created to test GH#2455
|
||||
|
||||
const std::string settingsJson0{ R"(
|
||||
CascadiaSettings settings0{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -368,9 +364,9 @@ namespace TerminalAppLocalTests
|
||||
"historySize": 2
|
||||
}
|
||||
]
|
||||
})" };
|
||||
})") };
|
||||
|
||||
const std::string settingsJson1{ R"(
|
||||
CascadiaSettings settings1{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -382,12 +378,6 @@ namespace TerminalAppLocalTests
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
|
||||
VERIFY_IS_NOT_NULL(settings0);
|
||||
|
||||
CascadiaSettings settings1{ til::u8u16(settingsJson1) };
|
||||
VERIFY_IS_NOT_NULL(settings1);
|
||||
|
||||
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid2 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid3 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}");
|
||||
@@ -440,7 +430,7 @@ namespace TerminalAppLocalTests
|
||||
//
|
||||
// Created to test GH#2455
|
||||
|
||||
const std::string settingsJson0{ R"(
|
||||
CascadiaSettings settings0{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -457,7 +447,7 @@ namespace TerminalAppLocalTests
|
||||
]
|
||||
})" };
|
||||
|
||||
const std::string settingsJson1{ R"(
|
||||
CascadiaSettings settings1{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
@@ -469,12 +459,6 @@ namespace TerminalAppLocalTests
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
|
||||
VERIFY_IS_NOT_NULL(settings0);
|
||||
|
||||
CascadiaSettings settings1{ til::u8u16(settingsJson1) };
|
||||
VERIFY_IS_NOT_NULL(settings1);
|
||||
|
||||
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid2 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid3 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}");
|
||||
@@ -554,7 +538,7 @@ namespace TerminalAppLocalTests
|
||||
// - The initialized TerminalPage, ready to use.
|
||||
winrt::com_ptr<winrt::TerminalApp::implementation::TerminalPage> TabTests::_commonSetup()
|
||||
{
|
||||
const std::string settingsJson0{ R"(
|
||||
CascadiaSettings settings0{ LR"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
"showTabsInTitlebar": false,
|
||||
@@ -655,9 +639,6 @@ namespace TerminalAppLocalTests
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
|
||||
VERIFY_IS_NOT_NULL(settings0);
|
||||
|
||||
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
|
||||
const auto guid2 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
|
||||
|
||||
|
||||
@@ -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_ -->
|
||||
|
||||
@@ -172,7 +172,6 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
|
||||
_desiredFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8 },
|
||||
_actualFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8, false },
|
||||
_uiaProvider{ nullptr },
|
||||
_uiaProviderInitialized{ false },
|
||||
_currentDpi{ USER_DEFAULT_SCREEN_DPI },
|
||||
_pfnWriteCallback{ nullptr },
|
||||
_multiClickTime{ 500 } // this will be overwritten by the windows system double-click time
|
||||
@@ -324,26 +323,22 @@ void HwndTerminal::_UpdateFont(int newDpi)
|
||||
|
||||
IRawElementProviderSimple* HwndTerminal::_GetUiaProvider() noexcept
|
||||
{
|
||||
if (nullptr == _uiaProvider && !_uiaProviderInitialized)
|
||||
// If TermControlUiaProvider throws during construction,
|
||||
// we don't want to try constructing an instance again and again.
|
||||
// _uiaProviderInitialized helps us prevent this.
|
||||
if (!_uiaProviderInitialized)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock;
|
||||
try
|
||||
{
|
||||
#pragma warning(suppress : 26441) // The lock is named, this appears to be a false positive
|
||||
lock = _terminal->LockForWriting();
|
||||
if (_uiaProviderInitialized)
|
||||
{
|
||||
return _uiaProvider.Get();
|
||||
}
|
||||
|
||||
auto lock = _terminal->LockForWriting();
|
||||
LOG_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, this->GetUiaData(), this));
|
||||
_uiaProviderInitialized = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_HR(wil::ResultFromCaughtException());
|
||||
_uiaProvider = nullptr;
|
||||
}
|
||||
_uiaProviderInitialized = true;
|
||||
}
|
||||
|
||||
return _uiaProvider.Get();
|
||||
@@ -798,7 +793,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;
|
||||
|
||||
@@ -73,7 +73,6 @@ private:
|
||||
FontInfoDesired _desiredFont;
|
||||
FontInfo _actualFont;
|
||||
int _currentDpi;
|
||||
bool _uiaProviderInitialized;
|
||||
std::function<void(wchar_t*)> _pfnWriteCallback;
|
||||
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
|
||||
|
||||
@@ -83,6 +82,7 @@ private:
|
||||
std::unique_ptr<::Microsoft::Console::Render::DxEngine> _renderEngine;
|
||||
|
||||
bool _focused{ false };
|
||||
bool _uiaProviderInitialized{ false };
|
||||
|
||||
std::chrono::milliseconds _multiClickTime;
|
||||
unsigned int _multiClickCounter{};
|
||||
|
||||
@@ -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*/,
|
||||
|
||||
@@ -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
|
||||
@@ -1360,8 +1335,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// The string they provided wasn't an int, it wasn't "new"
|
||||
// or "last", so whatever it is, that's the name they get.
|
||||
winrt::hstring winrtName{ til::u8u16(parsedTarget) };
|
||||
return winrt::make<FindTargetWindowResult>(WindowingBehaviorUseName, winrtName);
|
||||
return winrt::make<FindTargetWindowResult>(WindowingBehaviorUseName, til::u8u16(parsedTarget));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -63,23 +63,15 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void ColorPickupFlyout::ShowColorPickerButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
|
||||
{
|
||||
auto targetType = this->FlyoutPresenterStyle().TargetType();
|
||||
auto s = Windows::UI::Xaml::Style{};
|
||||
s.TargetType(targetType);
|
||||
auto visibility = customColorPanel().Visibility();
|
||||
if (visibility == winrt::Windows::UI::Xaml::Visibility::Collapsed)
|
||||
{
|
||||
customColorPanel().Visibility(winrt::Windows::UI::Xaml::Visibility::Visible);
|
||||
auto setter = Windows::UI::Xaml::Setter(Windows::UI::Xaml::FrameworkElement::MinWidthProperty(), winrt::box_value(540));
|
||||
s.Setters().Append(setter);
|
||||
}
|
||||
else
|
||||
{
|
||||
customColorPanel().Visibility(winrt::Windows::UI::Xaml::Visibility::Collapsed);
|
||||
auto setter = Windows::UI::Xaml::Setter(Windows::UI::Xaml::FrameworkElement::MinWidthProperty(), winrt::box_value(0));
|
||||
s.Setters().Append(setter);
|
||||
}
|
||||
this->FlyoutPresenterStyle(s);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -617,17 +617,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 +664,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>
|
||||
|
||||
<!--
|
||||
|
||||
@@ -41,6 +41,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
|
||||
@@ -1348,26 +1349,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 +1394,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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -456,8 +456,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// else we call convertUTF8ChunkToUTF16 with an empty string_view to convert possible remaining partials to U+FFFD
|
||||
}
|
||||
|
||||
const HRESULT result{ til::u8u16(std::string_view{ _buffer.data(), read }, _u16Str, _u8State) };
|
||||
if (FAILED(result))
|
||||
try
|
||||
{
|
||||
til::u8u16(std::string_view{ _buffer.data(), read }, _u16Str, _u8State);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
{
|
||||
|
||||
@@ -592,6 +592,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);
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "../buffer/out/search.h"
|
||||
#include "cppwinrt_utils.h"
|
||||
#include "ThrottledFunc.h"
|
||||
|
||||
namespace ControlUnitTests
|
||||
{
|
||||
|
||||
@@ -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 (_initializedTerminal && !_IsClosing()) // only set up the automation peer if we're ready to go live
|
||||
{
|
||||
// create a custom automation peer with this code pattern:
|
||||
// (https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/custom-automation-peers)
|
||||
@@ -747,7 +749,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;
|
||||
}
|
||||
@@ -845,7 +847,7 @@ 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 ||
|
||||
if (_IsClosing() ||
|
||||
e.OriginalKey() == VirtualKey::LeftWindows ||
|
||||
e.OriginalKey() == VirtualKey::RightWindows)
|
||||
|
||||
@@ -997,12 +999,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 +1029,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 +1080,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 +1153,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 +1195,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_MouseWheelHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Input::PointerRoutedEventArgs const& args)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1295,7 +1297,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 +1363,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 +1390,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 +1417,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 +1441,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 +1470,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 +1500,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 +1519,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 +1546,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 +1598,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 +1612,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 +1640,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 +1659,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 +1692,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 +1709,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 +2080,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TermControl::_CompositionCompleted(winrt::hstring text)
|
||||
{
|
||||
if (_closing)
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -2174,7 +2157,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 +2244,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 +2405,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 +2448,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,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
// _closing isn't atomic and may only be accessed from the main thread.
|
||||
assert(Dispatcher().HasThreadAccess());
|
||||
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"
|
||||
|
||||
@@ -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"
|
||||
@@ -867,9 +866,9 @@ WORD Terminal::_TakeVirtualKeyFromLastKeyEvent(const WORD scanCode) noexcept
|
||||
// Return Value:
|
||||
// - a shared_lock which can be used to unlock the terminal. The shared_lock
|
||||
// will release this lock when it's destructed.
|
||||
[[nodiscard]] std::shared_lock<std::shared_mutex> Terminal::LockForReading()
|
||||
[[nodiscard]] std::unique_lock<til::ticket_lock> Terminal::LockForReading()
|
||||
{
|
||||
return std::shared_lock<std::shared_mutex>(_readWriteLock);
|
||||
return std::unique_lock{ _readWriteLock };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -877,9 +876,9 @@ WORD Terminal::_TakeVirtualKeyFromLastKeyEvent(const WORD scanCode) noexcept
|
||||
// Return Value:
|
||||
// - a unique_lock which can be used to unlock the terminal. The unique_lock
|
||||
// will release this lock when it's destructed.
|
||||
[[nodiscard]] std::unique_lock<std::shared_mutex> Terminal::LockForWriting()
|
||||
[[nodiscard]] std::unique_lock<til::ticket_lock> Terminal::LockForWriting()
|
||||
{
|
||||
return std::unique_lock<std::shared_mutex>(_readWriteLock);
|
||||
return std::unique_lock{ _readWriteLock };
|
||||
}
|
||||
|
||||
Viewport Terminal::_GetMutableViewport() const noexcept
|
||||
|
||||
@@ -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"
|
||||
@@ -17,6 +18,8 @@
|
||||
#include "../../cascadia/terminalcore/ITerminalApi.hpp"
|
||||
#include "../../cascadia/terminalcore/ITerminalInput.hpp"
|
||||
|
||||
#include <til/ticket_lock.h>
|
||||
|
||||
static constexpr std::wstring_view linkPattern{ LR"(\b(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|$!:,.;]*[A-Za-z0-9+&@#/%=~_|$])" };
|
||||
static constexpr size_t TaskbarMinProgress{ 10 };
|
||||
|
||||
@@ -68,6 +71,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);
|
||||
@@ -75,8 +79,8 @@ public:
|
||||
// WritePastedText goes directly to the connection
|
||||
void WritePastedText(std::wstring_view stringView);
|
||||
|
||||
[[nodiscard]] std::shared_lock<std::shared_mutex> LockForReading();
|
||||
[[nodiscard]] std::unique_lock<std::shared_mutex> LockForWriting();
|
||||
[[nodiscard]] std::unique_lock<til::ticket_lock> LockForReading();
|
||||
[[nodiscard]] std::unique_lock<til::ticket_lock> LockForWriting();
|
||||
|
||||
short GetBufferHeight() const noexcept;
|
||||
|
||||
@@ -160,6 +164,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 +173,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;
|
||||
@@ -242,6 +246,15 @@ private:
|
||||
std::function<void()> _pfnWarningBell;
|
||||
std::function<void(std::wstring_view)> _pfnTitleChanged;
|
||||
std::function<void(std::wstring_view)> _pfnCopyToClipboard;
|
||||
|
||||
// I've specifically put this instance here as it requires
|
||||
// alignas(std::hardware_destructive_interference_size)
|
||||
// for best performance.
|
||||
//
|
||||
// But we can abuse the fact that the surrounding members rarely change and are huge
|
||||
// (std::function is like 64 bytes) to create some natural padding without wasting space.
|
||||
til::ticket_lock _readWriteLock;
|
||||
|
||||
std::function<void(const int, const int, const int)> _pfnScrollPositionChanged;
|
||||
std::function<void(const til::color)> _pfnBackgroundColorChanged;
|
||||
std::function<void()> _pfnCursorPositionChanged;
|
||||
@@ -276,6 +289,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
|
||||
@@ -293,8 +310,6 @@ private:
|
||||
SelectionExpansionMode _multiClickSelectionMode;
|
||||
#pragma endregion
|
||||
|
||||
std::shared_mutex _readWriteLock;
|
||||
|
||||
// TODO: These members are not shared by an alt-buffer. They should be
|
||||
// encapsulated, such that a Terminal can have both a main and alt buffer.
|
||||
std::unique_ptr<TextBuffer> _buffer;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -238,14 +230,14 @@ catch (...)
|
||||
// they're done with any querying they need to do.
|
||||
void Terminal::LockConsole() noexcept
|
||||
{
|
||||
_readWriteLock.lock_shared();
|
||||
_readWriteLock.lock();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Unlocks the terminal after a call to Terminal::LockConsole.
|
||||
void Terminal::UnlockConsole() noexcept
|
||||
{
|
||||
_readWriteLock.unlock_shared();
|
||||
_readWriteLock.unlock();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -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,19 +21,24 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
KeyBindingViewModel::KeyBindingViewModel(const Control::KeyChord& keys, const Model::Command& cmd) :
|
||||
_Keys{ keys },
|
||||
_KeyChordText{ Model::KeyChordSerialization::ToString(keys) },
|
||||
_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) :
|
||||
_CurrentKeys{ keys },
|
||||
_KeyChordText{ KeyChordSerialization::ToString(keys) },
|
||||
_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
|
||||
// unique view model members.
|
||||
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
|
||||
const auto viewModelProperty{ args.PropertyName() };
|
||||
if (viewModelProperty == L"Keys")
|
||||
if (viewModelProperty == L"CurrentKeys")
|
||||
{
|
||||
_KeyChordText = Model::KeyChordSerialization::ToString(_Keys);
|
||||
_KeyChordText = KeyChordSerialization::ToString(_CurrentKeys);
|
||||
_NotifyChanges(L"KeyChordText");
|
||||
}
|
||||
else if (viewModelProperty == L"IsContainerFocused" ||
|
||||
@@ -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
|
||||
ProposedKeys(KeyChordText());
|
||||
// - pre-populate the text box with the current keys
|
||||
// - reset the combo box with the current action
|
||||
ProposedKeys(_CurrentKeys);
|
||||
ProposedAction(box_value(_CurrentAction));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,32 +85,32 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
AttemptAcceptChanges(_ProposedKeys);
|
||||
}
|
||||
|
||||
void KeyBindingViewModel::AttemptAcceptChanges(hstring newKeyChordText)
|
||||
void KeyBindingViewModel::AttemptAcceptChanges(const Control::KeyChord newKeys)
|
||||
{
|
||||
auto args{ make_self<RebindKeysEventArgs>(_Keys, _Keys) };
|
||||
try
|
||||
const auto args{ make_self<ModifyKeyBindingEventArgs>(_CurrentKeys, // OldKeys
|
||||
newKeys, // NewKeys
|
||||
_IsNewlyAdded ? hstring{} : _CurrentAction, // OldAction
|
||||
unbox_value<hstring>(_ProposedAction)) }; // NewAction
|
||||
_ModifyKeyBindingRequestedHandlers(*this, *args);
|
||||
}
|
||||
|
||||
void KeyBindingViewModel::CancelChanges()
|
||||
{
|
||||
if (_IsNewlyAdded)
|
||||
{
|
||||
// Attempt to convert the provided key chord text
|
||||
const auto newKeyChord{ KeyChordSerialization::FromString(newKeyChordText) };
|
||||
args->NewKeys(newKeyChord);
|
||||
_RebindKeysRequestedHandlers(*this, *args);
|
||||
_DeleteNewlyAddedKeyBindingHandlers(*this, nullptr);
|
||||
}
|
||||
catch (hresult_invalid_argument)
|
||||
else
|
||||
{
|
||||
// Converting the text into a key chord failed
|
||||
// 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.
|
||||
// Ideally, some kind of notification would alert the user, but
|
||||
// to make it look nice, we need it to somehow target the text box.
|
||||
// Alternatively, we want a full key chord editor/listener.
|
||||
// If we implement that, we won't need this validation or error message.
|
||||
ToggleEditMode();
|
||||
}
|
||||
}
|
||||
|
||||
Actions::Actions()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Automation::AutomationProperties::SetName(AddNewButton(), RS_(L"Actions_AddNewTextBlock/Text"));
|
||||
}
|
||||
|
||||
Automation::Peers::AutomationPeer Actions::OnCreateAutomationPeer()
|
||||
@@ -118,17 +130,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);
|
||||
}
|
||||
|
||||
@@ -136,32 +157,23 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_KeyBindingList = single_threaded_observable_vector(std::move(keyBindingList));
|
||||
}
|
||||
|
||||
void Actions::KeyChordEditor_KeyDown(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
|
||||
void Actions::AddNew_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*eventArgs*/)
|
||||
{
|
||||
const auto& senderTB{ sender.as<TextBox>() };
|
||||
const auto& kbdVM{ senderTB.DataContext().as<Editor::KeyBindingViewModel>() };
|
||||
if (e.OriginalKey() == VirtualKey::Enter)
|
||||
{
|
||||
// Fun fact: this is happening _before_ "_ProposedKeys" gets updated
|
||||
// with the two-way data binding. So we need to directly extract the text
|
||||
// and tell the view model to update itself.
|
||||
get_self<KeyBindingViewModel>(kbdVM)->AttemptAcceptChanges(senderTB.Text());
|
||||
// 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 });
|
||||
|
||||
// For an unknown reason, when 'AcceptChangesFlyout' is set in the code above,
|
||||
// the flyout isn't shown, forcing the 'Enter' key to do nothing.
|
||||
// To get around this, detect if the flyout was set, and display it
|
||||
// on the text box.
|
||||
if (kbdVM.AcceptChangesFlyout() != nullptr)
|
||||
{
|
||||
kbdVM.AcceptChangesFlyout().ShowAt(senderTB);
|
||||
}
|
||||
e.Handled(true);
|
||||
}
|
||||
else if (e.OriginalKey() == VirtualKey::Escape)
|
||||
{
|
||||
kbdVM.ToggleEditMode();
|
||||
e.Handled(true);
|
||||
}
|
||||
// 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)
|
||||
@@ -174,8 +186,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 +199,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 +246,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->CurrentKeys(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 +318,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 +333,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:
|
||||
@@ -303,7 +368,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
for (uint32_t i = 0; i < _KeyBindingList.Size(); ++i)
|
||||
{
|
||||
const auto kbdVM{ get_self<KeyBindingViewModel>(_KeyBindingList.GetAt(i)) };
|
||||
const auto& otherKeys{ kbdVM->Keys() };
|
||||
const auto& otherKeys{ kbdVM->CurrentKeys() };
|
||||
if (keys.Modifiers() == otherKeys.Modifiers() && keys.Vkey() == otherKeys.Vkey())
|
||||
{
|
||||
return i;
|
||||
@@ -315,4 +380,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;
|
||||
@@ -56,23 +60,41 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void ToggleEditMode();
|
||||
void DisableEditMode() { IsInEditMode(false); }
|
||||
void AttemptAcceptChanges();
|
||||
void AttemptAcceptChanges(hstring newKeyChordText);
|
||||
void DeleteKeyBinding() { _DeleteKeyBindingRequestedHandlers(*this, _Keys); }
|
||||
void AttemptAcceptChanges(const Control::KeyChord newKeys);
|
||||
void CancelChanges();
|
||||
void DeleteKeyBinding() { _DeleteKeyBindingRequestedHandlers(*this, _CurrentKeys); }
|
||||
|
||||
// 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 keys proposed by the control; may disagree with the settings model.
|
||||
// CurrentKeys: the key chord bound in the settings model.
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Control::KeyChord, ProposedKeys);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Control::KeyChord, CurrentKeys, nullptr);
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsInEditMode, false);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, ProposedKeys);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Control::KeyChord, Keys, nullptr);
|
||||
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{};
|
||||
};
|
||||
|
||||
@@ -92,7 +114,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 +123,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; };
|
||||
String ProposedKeys;
|
||||
Boolean IsNewlyAdded { get; };
|
||||
Microsoft.Terminal.Control.KeyChord 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,13 +133,9 @@
|
||||
<Setter Property="TextWrapping" Value="WrapWholeWords" />
|
||||
</Style>
|
||||
<Style x:Key="KeyChordEditorStyle"
|
||||
BasedOn="{StaticResource DefaultTextBoxStyle}"
|
||||
TargetType="TextBox">
|
||||
TargetType="local:KeyChordListener">
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="TextAlignment" Value="Right" />
|
||||
<Setter Property="TextWrapping" Value="Wrap" />
|
||||
<Setter Property="IsSpellCheckEnabled" Value="False" />
|
||||
</Style>
|
||||
<x:Int32 x:Key="EditButtonSize">32</x:Int32>
|
||||
<x:Double x:Key="EditButtonIconSize">15</x:Double>
|
||||
@@ -198,7 +194,16 @@
|
||||
<!-- 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 x:Uid="Actions_ActionComboBox"
|
||||
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"
|
||||
@@ -214,13 +219,11 @@
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Border>
|
||||
|
||||
<!-- Edit Mode: Key Chord Text Box -->
|
||||
<TextBox Grid.Column="1"
|
||||
DataContext="{x:Bind Mode=OneWay}"
|
||||
KeyDown="KeyChordEditor_KeyDown"
|
||||
Style="{StaticResource KeyChordEditorStyle}"
|
||||
Text="{x:Bind ProposedKeys, Mode=TwoWay}"
|
||||
Visibility="{x:Bind IsInEditMode, Mode=OneWay}" />
|
||||
<!-- Edit Mode: Key Chord Listener -->
|
||||
<local:KeyChordListener Grid.Column="1"
|
||||
Keys="{x:Bind ProposedKeys, Mode=TwoWay}"
|
||||
Style="{StaticResource KeyChordEditorStyle}"
|
||||
Visibility="{x:Bind IsInEditMode, Mode=OneWay}" />
|
||||
|
||||
<!-- Edit Button -->
|
||||
<Button x:Uid="Actions_EditButton"
|
||||
@@ -278,7 +281,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 +302,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="" />
|
||||
@@ -373,7 +377,21 @@
|
||||
|
||||
<ScrollViewer>
|
||||
<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}"
|
||||
|
||||
374
src/cascadia/TerminalSettingsEditor/Appearances.cpp
Normal file
374
src/cascadia/TerminalSettingsEditor/Appearances.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "Appearances.h"
|
||||
#include "Appearances.g.cpp"
|
||||
#include "EnumEntry.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::UI::Xaml::Data;
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
AppearanceViewModel::AppearanceViewModel(const Model::AppearanceConfig& appearance) :
|
||||
_appearance{ appearance }
|
||||
{
|
||||
// Add a property changed handler to our own property changed event.
|
||||
// This propagates changes from the settings model to anybody listening to our
|
||||
// unique view model members.
|
||||
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
|
||||
const auto viewModelProperty{ args.PropertyName() };
|
||||
if (viewModelProperty == L"BackgroundImagePath")
|
||||
{
|
||||
// notify listener that all background image related values might have changed
|
||||
//
|
||||
// We need to do this so if someone manually types "desktopWallpaper"
|
||||
// into the path TextBox, we properly update the checkbox and stored
|
||||
// _lastBgImagePath. Without this, then we'll permanently hide the text
|
||||
// box, prevent it from ever being changed again.
|
||||
_NotifyChanges(L"UseDesktopBGImage", L"BackgroundImageSettingsVisible");
|
||||
}
|
||||
});
|
||||
|
||||
// Cache the original BG image path. If the user clicks "Use desktop
|
||||
// wallpaper", then un-checks it, this is the string we'll restore to
|
||||
// them.
|
||||
if (BackgroundImagePath() != L"desktopWallpaper")
|
||||
{
|
||||
_lastBgImagePath = BackgroundImagePath();
|
||||
}
|
||||
}
|
||||
|
||||
bool AppearanceViewModel::UseDesktopBGImage()
|
||||
{
|
||||
return BackgroundImagePath() == L"desktopWallpaper";
|
||||
}
|
||||
|
||||
void AppearanceViewModel::UseDesktopBGImage(const bool useDesktop)
|
||||
{
|
||||
if (useDesktop)
|
||||
{
|
||||
// Stash the current value of BackgroundImagePath. If the user
|
||||
// checks and un-checks the "Use desktop wallpaper" button, we want
|
||||
// the path that we display in the text box to remain unchanged.
|
||||
//
|
||||
// Only stash this value if it's not the special "desktopWallpaper"
|
||||
// value.
|
||||
if (BackgroundImagePath() != L"desktopWallpaper")
|
||||
{
|
||||
_lastBgImagePath = BackgroundImagePath();
|
||||
}
|
||||
BackgroundImagePath(L"desktopWallpaper");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restore the path we had previously cached. This might be the
|
||||
// empty string.
|
||||
BackgroundImagePath(_lastBgImagePath);
|
||||
}
|
||||
}
|
||||
|
||||
bool AppearanceViewModel::BackgroundImageSettingsVisible()
|
||||
{
|
||||
return BackgroundImagePath() != L"";
|
||||
}
|
||||
|
||||
DependencyProperty Appearances::_AppearanceProperty{ nullptr };
|
||||
|
||||
Appearances::Appearances() :
|
||||
_ShowAllFonts{ false },
|
||||
_ColorSchemeList{ single_threaded_observable_vector<ColorScheme>() }
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
INITIALIZE_BINDABLE_ENUM_SETTING(CursorShape, CursorStyle, winrt::Microsoft::Terminal::Core::CursorStyle, L"Profile_CursorShape", L"Content");
|
||||
INITIALIZE_BINDABLE_ENUM_SETTING_REVERSE_ORDER(BackgroundImageStretchMode, BackgroundImageStretchMode, winrt::Windows::UI::Xaml::Media::Stretch, L"Profile_BackgroundImageStretchMode", L"Content");
|
||||
|
||||
// manually add Custom FontWeight option. Don't add it to the Map
|
||||
INITIALIZE_BINDABLE_ENUM_SETTING(FontWeight, FontWeight, uint16_t, L"Profile_FontWeight", L"Content");
|
||||
_CustomFontWeight = winrt::make<EnumEntry>(RS_(L"Profile_FontWeightCustom/Content"), winrt::box_value<uint16_t>(0u));
|
||||
_FontWeightList.Append(_CustomFontWeight);
|
||||
|
||||
if (!_AppearanceProperty)
|
||||
{
|
||||
_AppearanceProperty =
|
||||
DependencyProperty::Register(
|
||||
L"Appearance",
|
||||
xaml_typename<Editor::AppearanceViewModel>(),
|
||||
xaml_typename<Editor::Appearances>(),
|
||||
PropertyMetadata{ nullptr, PropertyChangedCallback{ &Appearances::_ViewModelChanged } });
|
||||
}
|
||||
|
||||
// manually keep track of all the Background Image Alignment buttons
|
||||
_BIAlignmentButtons.at(0) = BIAlign_TopLeft();
|
||||
_BIAlignmentButtons.at(1) = BIAlign_Top();
|
||||
_BIAlignmentButtons.at(2) = BIAlign_TopRight();
|
||||
_BIAlignmentButtons.at(3) = BIAlign_Left();
|
||||
_BIAlignmentButtons.at(4) = BIAlign_Center();
|
||||
_BIAlignmentButtons.at(5) = BIAlign_Right();
|
||||
_BIAlignmentButtons.at(6) = BIAlign_BottomLeft();
|
||||
_BIAlignmentButtons.at(7) = BIAlign_Bottom();
|
||||
_BIAlignmentButtons.at(8) = BIAlign_BottomRight();
|
||||
|
||||
// apply automation properties to more complex setting controls
|
||||
for (const auto& biButton : _BIAlignmentButtons)
|
||||
{
|
||||
const auto tooltip{ ToolTipService::GetToolTip(biButton) };
|
||||
Automation::AutomationProperties::SetName(biButton, unbox_value<hstring>(tooltip));
|
||||
}
|
||||
|
||||
const auto showAllFontsCheckboxTooltip{ ToolTipService::GetToolTip(ShowAllFontsCheckbox()) };
|
||||
Automation::AutomationProperties::SetFullDescription(ShowAllFontsCheckbox(), unbox_value<hstring>(showAllFontsCheckboxTooltip));
|
||||
|
||||
const auto backgroundImgCheckboxTooltip{ ToolTipService::GetToolTip(UseDesktopImageCheckBox()) };
|
||||
Automation::AutomationProperties::SetFullDescription(UseDesktopImageCheckBox(), unbox_value<hstring>(backgroundImgCheckboxTooltip));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Searches through our list of monospace fonts to determine if the settings model's current font face is a monospace font
|
||||
bool Appearances::UsingMonospaceFont() const noexcept
|
||||
{
|
||||
bool result{ false };
|
||||
const auto currentFont{ Appearance().FontFace() };
|
||||
for (const auto& font : SourceProfile().MonospaceFontList())
|
||||
{
|
||||
if (font.LocalizedName() == currentFont)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Determines whether we should show the list of all the fonts, or we should just show monospace fonts
|
||||
bool Appearances::ShowAllFonts() const noexcept
|
||||
{
|
||||
// - _ShowAllFonts is directly bound to the checkbox. So this is the user set value.
|
||||
// - If we are not using a monospace font, show all of the fonts so that the ComboBox is still properly bound
|
||||
return _ShowAllFonts || !UsingMonospaceFont();
|
||||
}
|
||||
|
||||
void Appearances::ShowAllFonts(const bool& value)
|
||||
{
|
||||
if (_ShowAllFonts != value)
|
||||
{
|
||||
_ShowAllFonts = value;
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"ShowAllFonts" });
|
||||
}
|
||||
}
|
||||
|
||||
IInspectable Appearances::CurrentFontFace() const
|
||||
{
|
||||
// look for the current font in our shown list of fonts
|
||||
const auto& appearanceVM{ Appearance() };
|
||||
const auto appearanceFontFace{ appearanceVM.FontFace() };
|
||||
const auto& currentFontList{ ShowAllFonts() ? SourceProfile().CompleteFontList() : SourceProfile().MonospaceFontList() };
|
||||
IInspectable fallbackFont;
|
||||
for (const auto& font : currentFontList)
|
||||
{
|
||||
if (font.LocalizedName() == appearanceFontFace)
|
||||
{
|
||||
return box_value(font);
|
||||
}
|
||||
else if (font.LocalizedName() == L"Cascadia Mono")
|
||||
{
|
||||
fallbackFont = box_value(font);
|
||||
}
|
||||
}
|
||||
|
||||
// we couldn't find the desired font, set to "Cascadia Mono" since that ships by default
|
||||
return fallbackFont;
|
||||
}
|
||||
|
||||
void Appearances::FontFace_SelectionChanged(IInspectable const& /*sender*/, SelectionChangedEventArgs const& e)
|
||||
{
|
||||
// NOTE: We need to hook up a selection changed event handler here instead of directly binding to the appearance view model.
|
||||
// A two way binding to the view model causes an infinite loop because both combo boxes keep fighting over which one's right.
|
||||
const auto selectedItem{ e.AddedItems().GetAt(0) };
|
||||
const auto newFontFace{ unbox_value<Editor::Font>(selectedItem) };
|
||||
Appearance().FontFace(newFontFace.LocalizedName());
|
||||
}
|
||||
|
||||
void Appearances::_ViewModelChanged(DependencyObject const& d, DependencyPropertyChangedEventArgs const& /*args*/)
|
||||
{
|
||||
const auto& obj{ d.as<Editor::Appearances>() };
|
||||
get_self<Appearances>(obj)->_UpdateWithNewViewModel();
|
||||
}
|
||||
|
||||
void Appearances::_UpdateWithNewViewModel()
|
||||
{
|
||||
if (Appearance())
|
||||
{
|
||||
const auto& colorSchemeMap{ Appearance().Schemes() };
|
||||
for (const auto& pair : colorSchemeMap)
|
||||
{
|
||||
_ColorSchemeList.Append(pair.Value());
|
||||
}
|
||||
|
||||
const auto& biAlignmentVal{ static_cast<int32_t>(Appearance().BackgroundImageAlignment()) };
|
||||
for (const auto& biButton : _BIAlignmentButtons)
|
||||
{
|
||||
biButton.IsChecked(biButton.Tag().as<int32_t>() == biAlignmentVal);
|
||||
}
|
||||
|
||||
_ViewModelChangedRevoker = Appearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
|
||||
const auto settingName{ args.PropertyName() };
|
||||
if (settingName == L"CursorShape")
|
||||
{
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentCursorShape" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsVintageCursor" });
|
||||
}
|
||||
else if (settingName == L"ColorSchemeName")
|
||||
{
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentColorScheme" });
|
||||
}
|
||||
else if (settingName == L"BackgroundImageStretchMode")
|
||||
{
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentBackgroundImageStretchMode" });
|
||||
}
|
||||
else if (settingName == L"BackgroundImageAlignment")
|
||||
{
|
||||
_UpdateBIAlignmentControl(static_cast<int32_t>(Appearance().BackgroundImageAlignment()));
|
||||
}
|
||||
else if (settingName == L"FontWeight")
|
||||
{
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentFontWeight" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsCustomFontWeight" });
|
||||
}
|
||||
else if (settingName == L"FontFace" || settingName == L"CurrentFontList")
|
||||
{
|
||||
// notify listener that all font face related values might have changed
|
||||
if (!UsingMonospaceFont())
|
||||
{
|
||||
_ShowAllFonts = true;
|
||||
}
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentFontFace" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"ShowAllFonts" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"UsingMonospaceFont" });
|
||||
}
|
||||
});
|
||||
|
||||
// make sure to send all the property changed events once here
|
||||
// we do this in the case an old appearance was deleted and then a new one is created,
|
||||
// the old settings need to be updated in xaml
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentCursorShape" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsVintageCursor" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentColorScheme" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentBackgroundImageStretchMode" });
|
||||
_UpdateBIAlignmentControl(static_cast<int32_t>(Appearance().BackgroundImageAlignment()));
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentFontWeight" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsCustomFontWeight" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentFontFace" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"ShowAllFonts" });
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"UsingMonospaceFont" });
|
||||
}
|
||||
}
|
||||
|
||||
fire_and_forget Appearances::BackgroundImage_Click(IInspectable const&, RoutedEventArgs const&)
|
||||
{
|
||||
auto lifetime = get_strong();
|
||||
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(Appearance().WindowRoot().GetHostingWindow()) };
|
||||
auto file = co_await OpenImagePicker(parentHwnd);
|
||||
if (!file.empty())
|
||||
{
|
||||
Appearance().BackgroundImagePath(file);
|
||||
}
|
||||
}
|
||||
|
||||
void Appearances::BIAlignment_Click(IInspectable const& sender, RoutedEventArgs const& /*e*/)
|
||||
{
|
||||
if (const auto& button{ sender.try_as<Primitives::ToggleButton>() })
|
||||
{
|
||||
if (const auto& tag{ button.Tag().try_as<int32_t>() })
|
||||
{
|
||||
// Update the Appearance's value and the control
|
||||
Appearance().BackgroundImageAlignment(static_cast<ConvergedAlignment>(*tag));
|
||||
_UpdateBIAlignmentControl(*tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Resets all of the buttons to unchecked, and checks the one with the provided tag
|
||||
// Arguments:
|
||||
// - val - the background image alignment (ConvergedAlignment) that we want to represent in the control
|
||||
void Appearances::_UpdateBIAlignmentControl(const int32_t val)
|
||||
{
|
||||
for (const auto& biButton : _BIAlignmentButtons)
|
||||
{
|
||||
if (const auto& biButtonAlignment{ biButton.Tag().try_as<int32_t>() })
|
||||
{
|
||||
biButton.IsChecked(biButtonAlignment == val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColorScheme Appearances::CurrentColorScheme()
|
||||
{
|
||||
const auto schemeName{ Appearance().ColorSchemeName() };
|
||||
if (const auto scheme{ Appearance().Schemes().TryLookup(schemeName) })
|
||||
{
|
||||
return scheme;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This Appearance points to a color scheme that was renamed or deleted.
|
||||
// Fallback to Campbell.
|
||||
return Appearance().Schemes().TryLookup(L"Campbell");
|
||||
}
|
||||
}
|
||||
|
||||
void Appearances::CurrentColorScheme(const ColorScheme& val)
|
||||
{
|
||||
Appearance().ColorSchemeName(val.Name());
|
||||
}
|
||||
|
||||
bool Appearances::IsVintageCursor() const
|
||||
{
|
||||
return Appearance().CursorShape() == Core::CursorStyle::Vintage;
|
||||
}
|
||||
|
||||
IInspectable Appearances::CurrentFontWeight() const
|
||||
{
|
||||
// if no value was found, we have a custom value
|
||||
const auto maybeEnumEntry{ _FontWeightMap.TryLookup(Appearance().FontWeight().Weight) };
|
||||
return maybeEnumEntry ? maybeEnumEntry : _CustomFontWeight;
|
||||
}
|
||||
|
||||
void Appearances::CurrentFontWeight(const IInspectable& enumEntry)
|
||||
{
|
||||
if (auto ee = enumEntry.try_as<Editor::EnumEntry>())
|
||||
{
|
||||
if (ee != _CustomFontWeight)
|
||||
{
|
||||
const auto weight{ winrt::unbox_value<uint16_t>(ee.EnumValue()) };
|
||||
const Windows::UI::Text::FontWeight setting{ weight };
|
||||
Appearance().FontWeight(setting);
|
||||
|
||||
// Appearance does not have observable properties
|
||||
// So the TwoWay binding doesn't update on the State --> Slider direction
|
||||
FontWeightSlider().Value(weight);
|
||||
}
|
||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsCustomFontWeight" });
|
||||
}
|
||||
}
|
||||
|
||||
bool Appearances::IsCustomFontWeight()
|
||||
{
|
||||
// Use SelectedItem instead of CurrentFontWeight.
|
||||
// CurrentFontWeight converts the Appearance's value to the appropriate enum entry,
|
||||
// whereas SelectedItem identifies which one was selected by the user.
|
||||
return FontWeightComboBox().SelectedItem() == _CustomFontWeight;
|
||||
}
|
||||
}
|
||||
143
src/cascadia/TerminalSettingsEditor/Appearances.h
Normal file
143
src/cascadia/TerminalSettingsEditor/Appearances.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- Appearances
|
||||
|
||||
Abstract:
|
||||
- The classes defined in this module are responsible for encapsulating the appearance settings
|
||||
of profiles and presenting them in the settings UI
|
||||
|
||||
Author(s):
|
||||
- Pankaj Bhojwani - May 2021
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Font.g.h"
|
||||
#include "Appearances.g.h"
|
||||
#include "AppearanceViewModel.g.h"
|
||||
#include "Utils.h"
|
||||
#include "ViewModelHelpers.h"
|
||||
#include "SettingContainer.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct FontComparator
|
||||
{
|
||||
bool operator()(const Font& lhs, const Font& rhs) const
|
||||
{
|
||||
return lhs.LocalizedName() < rhs.LocalizedName();
|
||||
}
|
||||
};
|
||||
|
||||
struct Font : FontT<Font>
|
||||
{
|
||||
public:
|
||||
Font(std::wstring name, std::wstring localizedName) :
|
||||
_Name{ name },
|
||||
_LocalizedName{ localizedName } {};
|
||||
|
||||
hstring ToString() { return _LocalizedName; }
|
||||
|
||||
WINRT_PROPERTY(hstring, Name);
|
||||
WINRT_PROPERTY(hstring, LocalizedName);
|
||||
};
|
||||
|
||||
struct AppearanceViewModel : AppearanceViewModelT<AppearanceViewModel>, ViewModelHelper<AppearanceViewModel>
|
||||
{
|
||||
public:
|
||||
AppearanceViewModel(const Model::AppearanceConfig& appearance);
|
||||
|
||||
// background image
|
||||
bool UseDesktopBGImage();
|
||||
void UseDesktopBGImage(const bool useDesktop);
|
||||
bool BackgroundImageSettingsVisible();
|
||||
|
||||
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> Schemes() { return _Schemes; }
|
||||
void Schemes(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& val) { _Schemes = val; }
|
||||
|
||||
WINRT_PROPERTY(bool, IsDefault, false);
|
||||
WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
|
||||
|
||||
// These settings are not defined in AppearanceConfig, so we grab them
|
||||
// from the source profile itself. The reason we still want them in the
|
||||
// AppearanceViewModel is so we can continue to have the 'Text' grouping
|
||||
// we currently have in xaml, since that grouping has some settings that
|
||||
// are defined in AppearanceConfig and some that are not.
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), FontFace);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), FontSize);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), FontWeight);
|
||||
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, RetroTerminalEffect);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, CursorShape);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, CursorHeight);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, ColorSchemeName);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImagePath);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageOpacity);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageStretchMode);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageAlignment);
|
||||
|
||||
private:
|
||||
Model::AppearanceConfig _appearance;
|
||||
winrt::hstring _lastBgImagePath;
|
||||
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> _Schemes;
|
||||
};
|
||||
|
||||
struct Appearances : AppearancesT<Appearances>
|
||||
{
|
||||
public:
|
||||
Appearances();
|
||||
|
||||
// font face
|
||||
Windows::Foundation::IInspectable CurrentFontFace() const;
|
||||
|
||||
// CursorShape visibility logic
|
||||
bool IsVintageCursor() const;
|
||||
|
||||
Model::ColorScheme CurrentColorScheme();
|
||||
void CurrentColorScheme(const Model::ColorScheme& val);
|
||||
|
||||
bool UsingMonospaceFont() const noexcept;
|
||||
bool ShowAllFonts() const noexcept;
|
||||
void ShowAllFonts(const bool& value);
|
||||
|
||||
fire_and_forget BackgroundImage_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void BIAlignment_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void FontFace_SelectionChanged(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs const& e);
|
||||
|
||||
// manually bind FontWeight
|
||||
Windows::Foundation::IInspectable CurrentFontWeight() const;
|
||||
void CurrentFontWeight(const Windows::Foundation::IInspectable& enumEntry);
|
||||
bool IsCustomFontWeight();
|
||||
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<Microsoft::Terminal::Settings::Editor::EnumEntry>, FontWeightList);
|
||||
|
||||
GETSET_BINDABLE_ENUM_SETTING(CursorShape, Microsoft::Terminal::Core::CursorStyle, Appearance, CursorShape);
|
||||
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<Model::ColorScheme>, ColorSchemeList, nullptr);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
DEPENDENCY_PROPERTY(Editor::AppearanceViewModel, Appearance);
|
||||
WINRT_PROPERTY(Editor::ProfileViewModel, SourceProfile, nullptr);
|
||||
|
||||
GETSET_BINDABLE_ENUM_SETTING(BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch, Appearance, BackgroundImageStretchMode);
|
||||
|
||||
private:
|
||||
bool _ShowAllFonts;
|
||||
void _UpdateBIAlignmentControl(const int32_t val);
|
||||
std::array<Windows::UI::Xaml::Controls::Primitives::ToggleButton, 9> _BIAlignmentButtons;
|
||||
|
||||
Windows::Foundation::Collections::IMap<uint16_t, Microsoft::Terminal::Settings::Editor::EnumEntry> _FontWeightMap;
|
||||
Editor::EnumEntry _CustomFontWeight{ nullptr };
|
||||
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
|
||||
static void _ViewModelChanged(Windows::UI::Xaml::DependencyObject const& d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs const& e);
|
||||
void _UpdateWithNewViewModel();
|
||||
};
|
||||
};
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(Appearances);
|
||||
}
|
||||
72
src/cascadia/TerminalSettingsEditor/Appearances.idl
Normal file
72
src/cascadia/TerminalSettingsEditor/Appearances.idl
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "EnumEntry.idl";
|
||||
import "MainPage.idl";
|
||||
import "Profiles.idl";
|
||||
|
||||
#include "ViewModelHelpers.idl.h"
|
||||
|
||||
#define OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Type, Name) \
|
||||
OBSERVABLE_PROJECTED_SETTING(Type, Name); \
|
||||
Object Name##OverrideSource { get; }
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
runtimeclass Font : Windows.Foundation.IStringable
|
||||
{
|
||||
String Name { get; };
|
||||
String LocalizedName { get; };
|
||||
}
|
||||
|
||||
runtimeclass AppearanceViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
Boolean IsDefault;
|
||||
|
||||
Boolean UseDesktopBGImage;
|
||||
Boolean BackgroundImageSettingsVisible { get; };
|
||||
|
||||
Windows.Foundation.Collections.IMapView<String, Microsoft.Terminal.Settings.Model.ColorScheme> Schemes;
|
||||
IHostedInWindow WindowRoot; // necessary to send the right HWND into the file picker dialogs.
|
||||
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, FontFace);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Int32, FontSize);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Text.FontWeight, FontWeight);
|
||||
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, ColorSchemeName);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, RetroTerminalEffect);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Core.CursorStyle, CursorShape);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(UInt32, CursorHeight);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, BackgroundImagePath);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Double, BackgroundImageOpacity);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Xaml.Media.Stretch, BackgroundImageStretchMode);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.ConvergedAlignment, BackgroundImageAlignment);
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass Appearances : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
Appearances();
|
||||
AppearanceViewModel Appearance;
|
||||
ProfileViewModel SourceProfile;
|
||||
static Windows.UI.Xaml.DependencyProperty AppearanceProperty { get; };
|
||||
|
||||
Boolean UsingMonospaceFont { get; };
|
||||
Boolean ShowAllFonts;
|
||||
|
||||
IInspectable CurrentCursorShape;
|
||||
Boolean IsVintageCursor { get; };
|
||||
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> CursorShapeList { get; };
|
||||
|
||||
Microsoft.Terminal.Settings.Model.ColorScheme CurrentColorScheme;
|
||||
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Model.ColorScheme> ColorSchemeList { get; };
|
||||
|
||||
IInspectable CurrentBackgroundImageStretchMode;
|
||||
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> BackgroundImageStretchModeList { get; };
|
||||
|
||||
IInspectable CurrentFontWeight;
|
||||
Boolean IsCustomFontWeight { get; };
|
||||
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> FontWeightList { get; };
|
||||
|
||||
IInspectable CurrentFontFace { get; };
|
||||
}
|
||||
}
|
||||
442
src/cascadia/TerminalSettingsEditor/Appearances.xaml
Normal file
442
src/cascadia/TerminalSettingsEditor/Appearances.xaml
Normal file
@@ -0,0 +1,442 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="Microsoft.Terminal.Settings.Editor.Appearances"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
IsTabStop="False"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="CommonResources.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<DataTemplate x:Key="EnumRadioButtonTemplate"
|
||||
x:DataType="local:EnumEntry">
|
||||
<RadioButton Content="{x:Bind EnumName, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="EnumComboBoxItemTemplate"
|
||||
x:DataType="local:EnumEntry">
|
||||
<TextBlock Text="{x:Bind EnumName, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="FontFaceComboBoxItemTemplate"
|
||||
x:DataType="local:Font">
|
||||
<TextBlock FontFamily="{x:Bind Name}"
|
||||
Text="{x:Bind LocalizedName}" />
|
||||
</DataTemplate>
|
||||
|
||||
<local:ColorToBrushConverter x:Key="ColorToBrushConverter" />
|
||||
<local:PercentageConverter x:Key="PercentageConverter" />
|
||||
<local:PercentageSignConverter x:Key="PercentageSignConverter" />
|
||||
<local:FontWeightConverter x:Key="FontWeightConverter" />
|
||||
<local:InvertedBooleanToVisibilityConverter x:Key="InvertedBooleanToVisibilityConverter" />
|
||||
<local:StringIsEmptyConverter x:Key="StringIsEmptyConverter" />
|
||||
<local:PaddingConverter x:Key="PaddingConverter" />
|
||||
<local:StringIsNotDesktopConverter x:Key="StringIsNotDesktopConverter" />
|
||||
<local:DesktopWallpaperToEmptyStringConverter x:Key="DesktopWallpaperToEmptyStringConverter" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<StackPanel>
|
||||
<StackPanel Style="{StaticResource PivotStackStyle}">
|
||||
<!-- Grouping: Text -->
|
||||
<TextBlock x:Uid="Profile_TextHeader"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}" />
|
||||
|
||||
<!-- Color Scheme -->
|
||||
<local:SettingContainer x:Uid="Profile_ColorScheme"
|
||||
Margin="0"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearColorSchemeName}"
|
||||
HasSettingValue="{x:Bind Appearance.HasColorSchemeName, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.ColorSchemeNameOverrideSource, Mode=OneWay}">
|
||||
<ComboBox ItemsSource="{x:Bind ColorSchemeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentColorScheme, Mode=TwoWay}"
|
||||
Style="{StaticResource ComboBoxSettingStyle}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:ColorScheme">
|
||||
<TextBlock Text="{x:Bind Name, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Font Face -->
|
||||
<local:SettingContainer x:Uid="Profile_FontFace"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearFontFace}"
|
||||
HasSettingValue="{x:Bind Appearance.HasFontFace, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.FontFaceOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
|
||||
<StackPanel>
|
||||
<!--
|
||||
Binding the ItemsSource to a separate variable that switches between the
|
||||
two font lists causes a crash within the ComboBox code.
|
||||
As a workaround, introduce two ComboBox controls and only display one at a time.
|
||||
-->
|
||||
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
|
||||
ItemsSource="{x:Bind SourceProfile.MonospaceFontList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
|
||||
SelectionChanged="FontFace_SelectionChanged"
|
||||
Style="{StaticResource ComboBoxSettingStyle}"
|
||||
Visibility="{x:Bind ShowAllFonts, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}" />
|
||||
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
|
||||
ItemsSource="{x:Bind SourceProfile.CompleteFontList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
|
||||
SelectionChanged="FontFace_SelectionChanged"
|
||||
Style="{StaticResource ComboBoxSettingStyle}"
|
||||
Visibility="{x:Bind ShowAllFonts, Mode=OneWay}" />
|
||||
<CheckBox x:Name="ShowAllFontsCheckbox"
|
||||
x:Uid="Profile_FontFaceShowAllFonts"
|
||||
IsChecked="{x:Bind ShowAllFonts, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind UsingMonospaceFont, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Font Size -->
|
||||
<local:SettingContainer x:Uid="Profile_FontSize"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearFontSize}"
|
||||
HasSettingValue="{x:Bind Appearance.HasFontSize, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.FontSizeOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
|
||||
<muxc:NumberBox AcceptsExpression="False"
|
||||
LargeChange="10"
|
||||
Maximum="128"
|
||||
Minimum="1"
|
||||
SmallChange="1"
|
||||
Style="{StaticResource NumberBoxSettingStyle}"
|
||||
Value="{x:Bind Appearance.FontSize, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Font Weight -->
|
||||
<local:SettingContainer x:Name="FontWeightContainer"
|
||||
x:Uid="Profile_FontWeight"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearFontWeight}"
|
||||
HasSettingValue="{x:Bind Appearance.HasFontWeight, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.FontWeightOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
|
||||
<StackPanel>
|
||||
<ComboBox x:Name="FontWeightComboBox"
|
||||
ItemTemplate="{StaticResource EnumComboBoxItemTemplate}"
|
||||
ItemsSource="{x:Bind FontWeightList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentFontWeight, Mode=TwoWay}"
|
||||
Style="{StaticResource ComboBoxSettingStyle}" />
|
||||
|
||||
<!-- Custom Font Weight Control -->
|
||||
<Grid Margin="0,10,0,0"
|
||||
Style="{StaticResource CustomSliderControlGridStyle}"
|
||||
Visibility="{x:Bind IsCustomFontWeight, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider x:Name="FontWeightSlider"
|
||||
Grid.Column="0"
|
||||
Maximum="1000"
|
||||
Minimum="0"
|
||||
TickFrequency="50"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind Appearance.FontWeight, Converter={StaticResource FontWeightConverter}, Mode=TwoWay}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Margin="10,0,0,0"
|
||||
Style="{StaticResource SliderValueLabelStyle}"
|
||||
Text="{Binding ElementName=FontWeightSlider, Path=Value, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Retro Terminal Effect -->
|
||||
<local:SettingContainer x:Uid="Profile_RetroTerminalEffect"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearRetroTerminalEffect}"
|
||||
HasSettingValue="{x:Bind Appearance.HasRetroTerminalEffect, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.RetroTerminalEffectOverrideSource, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind Appearance.RetroTerminalEffect, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Grouping: Cursor -->
|
||||
<StackPanel Style="{StaticResource PivotStackStyle}">
|
||||
<TextBlock x:Uid="Profile_CursorHeader"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}" />
|
||||
|
||||
<!-- Cursor Shape -->
|
||||
<local:SettingContainer x:Uid="Profile_CursorShape"
|
||||
Margin="0"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearCursorShape}"
|
||||
HasSettingValue="{x:Bind Appearance.HasCursorShape, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.CursorShapeOverrideSource, Mode=OneWay}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind CursorShapeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentCursorShape, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Cursor Height -->
|
||||
<local:SettingContainer x:Uid="Profile_CursorHeight"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearCursorHeight}"
|
||||
HasSettingValue="{x:Bind Appearance.HasCursorHeight, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.CursorHeightOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind IsVintageCursor, Mode=OneWay}">
|
||||
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider x:Name="CursorHeightSlider"
|
||||
Grid.Column="0"
|
||||
Maximum="100"
|
||||
Minimum="1"
|
||||
Value="{x:Bind Appearance.CursorHeight, Mode=TwoWay}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Style="{StaticResource SliderValueLabelStyle}"
|
||||
Text="{Binding ElementName=CursorHeightSlider, Path=Value, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Grouping: Background -->
|
||||
<StackPanel Style="{StaticResource PivotStackStyle}">
|
||||
<TextBlock x:Uid="Profile_BackgroundHeader"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}" />
|
||||
|
||||
<!-- Background Image -->
|
||||
<local:SettingContainer x:Name="BackgroundImageContainer"
|
||||
x:Uid="Profile_BackgroundImage"
|
||||
Margin="0"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImagePath}"
|
||||
HasSettingValue="{x:Bind Appearance.HasBackgroundImagePath, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.BackgroundImagePathOverrideSource, Mode=OneWay}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBox IsEnabled="{x:Bind Appearance.BackgroundImagePath, Mode=OneWay, Converter={StaticResource StringIsNotDesktopConverter}}"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind Appearance.BackgroundImagePath, Mode=TwoWay, Converter={StaticResource DesktopWallpaperToEmptyStringConverter}}" />
|
||||
<Button x:Uid="Profile_BackgroundImageBrowse"
|
||||
Click="BackgroundImage_Click"
|
||||
IsEnabled="{x:Bind Appearance.BackgroundImagePath, Mode=OneWay, Converter={StaticResource StringIsNotDesktopConverter}}"
|
||||
Style="{StaticResource BrowseButtonStyle}" />
|
||||
</StackPanel>
|
||||
<CheckBox x:Name="UseDesktopImageCheckBox"
|
||||
x:Uid="Profile_UseDesktopImage"
|
||||
IsChecked="{x:Bind Appearance.UseDesktopBGImage, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Background Image Stretch Mode -->
|
||||
<local:SettingContainer x:Uid="Profile_BackgroundImageStretchMode"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImageStretchMode}"
|
||||
HasSettingValue="{x:Bind Appearance.HasBackgroundImageStretchMode, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.BackgroundImageStretchModeOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Appearance.BackgroundImageSettingsVisible, Mode=OneWay}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind BackgroundImageStretchModeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentBackgroundImageStretchMode, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Background Image Alignment -->
|
||||
<local:SettingContainer x:Uid="Profile_BackgroundImageAlignment"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImageAlignment}"
|
||||
HasSettingValue="{x:Bind Appearance.HasBackgroundImageAlignment, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.BackgroundImageAlignmentOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Appearance.BackgroundImageSettingsVisible, Mode=OneWay}">
|
||||
<Grid HorizontalAlignment="Left">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.Resources>
|
||||
<Style BasedOn="{StaticResource DefaultToggleButtonStyle}"
|
||||
TargetType="ToggleButton">
|
||||
<Setter Property="Margin" Value="2" />
|
||||
<Setter Property="Width" Value="40" />
|
||||
<Setter Property="Height" Value="40" />
|
||||
<Setter Property="ToolTipService.Placement" Value="Mouse" />
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
|
||||
<!-- Top Row -->
|
||||
<ToggleButton x:Name="BIAlign_TopLeft"
|
||||
x:Uid="Profile_BackgroundImageAlignmentTopLeft"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Click="BIAlignment_Click">
|
||||
<ToggleButton.Tag>
|
||||
<!-- ConvergedAlignment: Vertical_Top (0x10) | Horizontal_Left (0x01) -->
|
||||
<x:Int32>17</x:Int32>
|
||||
</ToggleButton.Tag>
|
||||
<ToggleButton.Content>
|
||||
<FontIcon FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<FontIcon.RenderTransform>
|
||||
<RotateTransform Angle="90" />
|
||||
</FontIcon.RenderTransform>
|
||||
</FontIcon>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<ToggleButton x:Name="BIAlign_Top"
|
||||
x:Uid="Profile_BackgroundImageAlignmentTop"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Click="BIAlignment_Click">
|
||||
<ToggleButton.Tag>
|
||||
<!-- ConvergedAlignment: Vertical_Top (0x10) | Horizontal_Center (0x00) -->
|
||||
<x:Int32>16</x:Int32>
|
||||
</ToggleButton.Tag>
|
||||
<ToggleButton.Content>
|
||||
<FontIcon FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<FontIcon.RenderTransform>
|
||||
<RotateTransform Angle="180" />
|
||||
</FontIcon.RenderTransform>
|
||||
</FontIcon>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<ToggleButton x:Name="BIAlign_TopRight"
|
||||
x:Uid="Profile_BackgroundImageAlignmentTopRight"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Click="BIAlignment_Click">
|
||||
<ToggleButton.Tag>
|
||||
<!-- ConvergedAlignment: Vertical_Top (0x10) | Horizontal_Right (0x02) -->
|
||||
<x:Int32>18</x:Int32>
|
||||
</ToggleButton.Tag>
|
||||
<ToggleButton.Content>
|
||||
<FontIcon FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<FontIcon.RenderTransform>
|
||||
<RotateTransform Angle="270" />
|
||||
</FontIcon.RenderTransform>
|
||||
</FontIcon>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
|
||||
<!-- Middle Row -->
|
||||
<ToggleButton x:Name="BIAlign_Left"
|
||||
x:Uid="Profile_BackgroundImageAlignmentLeft"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Click="BIAlignment_Click">
|
||||
<ToggleButton.Tag>
|
||||
<!-- ConvergedAlignment: Vertical_Center (0x00) | Horizontal_Left (0x01) -->
|
||||
<x:Int32>1</x:Int32>
|
||||
</ToggleButton.Tag>
|
||||
<ToggleButton.Content>
|
||||
<FontIcon FontFamily="Segoe MDL2 Assets"
|
||||
Glyph="" />
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<ToggleButton x:Name="BIAlign_Center"
|
||||
x:Uid="Profile_BackgroundImageAlignmentCenter"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Click="BIAlignment_Click">
|
||||
<ToggleButton.Tag>
|
||||
<!-- ConvergedAlignment: Vertical_Center (0x00) | Horizontal_Center (0x00) -->
|
||||
<x:Int32>0</x:Int32>
|
||||
</ToggleButton.Tag>
|
||||
<ToggleButton.Content>
|
||||
<FontIcon FontFamily="Segoe MDL2 Assets"
|
||||
Glyph="" />
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<ToggleButton x:Name="BIAlign_Right"
|
||||
x:Uid="Profile_BackgroundImageAlignmentRight"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Click="BIAlignment_Click">
|
||||
<ToggleButton.Tag>
|
||||
<!-- ConvergedAlignment: Vertical_Center (0x00) | Horizontal_Right (0x02) -->
|
||||
<x:Int32>2</x:Int32>
|
||||
</ToggleButton.Tag>
|
||||
<ToggleButton.Content>
|
||||
<FontIcon FontFamily="Segoe MDL2 Assets"
|
||||
Glyph="" />
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
|
||||
<!-- Bottom Row -->
|
||||
<ToggleButton x:Name="BIAlign_BottomLeft"
|
||||
x:Uid="Profile_BackgroundImageAlignmentBottomLeft"
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Click="BIAlignment_Click">
|
||||
<ToggleButton.Tag>
|
||||
<!-- ConvergedAlignment: Vertical_Bottom (0x20) | Horizontal_Left (0x01) -->
|
||||
<x:Int32>33</x:Int32>
|
||||
</ToggleButton.Tag>
|
||||
<ToggleButton.Content>
|
||||
<FontIcon FontFamily="Segoe MDL2 Assets"
|
||||
Glyph="" />
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<ToggleButton x:Name="BIAlign_Bottom"
|
||||
x:Uid="Profile_BackgroundImageAlignmentBottom"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Click="BIAlignment_Click">
|
||||
<ToggleButton.Tag>
|
||||
<!-- ConvergedAlignment: Vertical_Bottom (0x20) | Horizontal_Center (0x00) -->
|
||||
<x:Int32>32</x:Int32>
|
||||
</ToggleButton.Tag>
|
||||
<ToggleButton.Content>
|
||||
<FontIcon FontFamily="Segoe MDL2 Assets"
|
||||
Glyph="" />
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<ToggleButton x:Name="BIAlign_BottomRight"
|
||||
x:Uid="Profile_BackgroundImageAlignmentBottomRight"
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Click="BIAlignment_Click">
|
||||
<ToggleButton.Tag>
|
||||
<!-- ConvergedAlignment: Vertical_Top (0x20) | Horizontal_Right (0x02) -->
|
||||
<x:Int32>34</x:Int32>
|
||||
</ToggleButton.Tag>
|
||||
<ToggleButton.Content>
|
||||
<FontIcon FontFamily="Segoe MDL2 Assets"
|
||||
Glyph="" />
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
</Grid>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Background Image Opacity -->
|
||||
<local:SettingContainer x:Name="BackgroundImageOpacityContainer"
|
||||
x:Uid="Profile_BackgroundImageOpacity"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImageOpacity}"
|
||||
HasSettingValue="{x:Bind Appearance.HasBackgroundImageOpacity, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.BackgroundImageOpacityOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Appearance.BackgroundImageSettingsVisible, Mode=OneWay}">
|
||||
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider x:Name="BIOpacitySlider"
|
||||
Grid.Column="0"
|
||||
Value="{x:Bind Appearance.BackgroundImageOpacity, Converter={StaticResource PercentageConverter}, Mode=TwoWay}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Style="{StaticResource SliderValueLabelStyle}"
|
||||
Text="{Binding ElementName=BIOpacitySlider, Path=Value, Mode=OneWay, Converter={StaticResource PercentageSignConverter}}" />
|
||||
</Grid>
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
135
src/cascadia/TerminalSettingsEditor/KeyChordListener.cpp
Normal file
135
src/cascadia/TerminalSettingsEditor/KeyChordListener.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "KeyChordListener.h"
|
||||
#include "KeyChordListener.g.cpp"
|
||||
#include "LibraryResources.h"
|
||||
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::UI::Xaml::Data;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Xaml::Input;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
DependencyProperty KeyChordListener::_KeysProperty{ nullptr };
|
||||
|
||||
static constexpr std::array ModifierKeys{
|
||||
VirtualKey::Shift,
|
||||
VirtualKey::Control,
|
||||
VirtualKey::Menu,
|
||||
VirtualKey::LeftWindows,
|
||||
VirtualKey::RightWindows,
|
||||
VirtualKey::LeftShift,
|
||||
VirtualKey::LeftControl,
|
||||
VirtualKey::RightControl,
|
||||
VirtualKey::LeftMenu,
|
||||
VirtualKey::RightMenu
|
||||
};
|
||||
|
||||
static VirtualKeyModifiers _GetModifiers()
|
||||
{
|
||||
const auto window{ CoreWindow::GetForCurrentThread() };
|
||||
|
||||
VirtualKeyModifiers flags = VirtualKeyModifiers::None;
|
||||
for (const auto mod : ModifierKeys)
|
||||
{
|
||||
const auto state = window.GetKeyState(mod);
|
||||
const auto isDown = WI_IsFlagSet(state, CoreVirtualKeyStates::Down);
|
||||
|
||||
if (isDown)
|
||||
{
|
||||
switch (mod)
|
||||
{
|
||||
case VirtualKey::Control:
|
||||
case VirtualKey::LeftControl:
|
||||
case VirtualKey::RightControl:
|
||||
flags |= VirtualKeyModifiers::Control;
|
||||
break;
|
||||
case VirtualKey::Menu:
|
||||
case VirtualKey::LeftMenu:
|
||||
case VirtualKey::RightMenu:
|
||||
flags |= VirtualKeyModifiers::Menu;
|
||||
break;
|
||||
case VirtualKey::Shift:
|
||||
case VirtualKey::LeftShift:
|
||||
flags |= VirtualKeyModifiers::Shift;
|
||||
break;
|
||||
case VirtualKey::LeftWindows:
|
||||
case VirtualKey::RightWindows:
|
||||
flags |= VirtualKeyModifiers::Windows;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
KeyChordListener::KeyChordListener()
|
||||
{
|
||||
InitializeComponent();
|
||||
_InitializeProperties();
|
||||
}
|
||||
|
||||
void KeyChordListener::_InitializeProperties()
|
||||
{
|
||||
// Initialize any KeyChordListener dependency properties here.
|
||||
// This performs a lazy load on these properties, instead of
|
||||
// initializing them when the DLL loads.
|
||||
if (!_KeysProperty)
|
||||
{
|
||||
_KeysProperty =
|
||||
DependencyProperty::Register(
|
||||
L"Keys",
|
||||
xaml_typename<Control::KeyChord>(),
|
||||
xaml_typename<Editor::KeyChordListener>(),
|
||||
PropertyMetadata{ nullptr, PropertyChangedCallback{ &KeyChordListener::_OnKeysChanged } });
|
||||
}
|
||||
}
|
||||
|
||||
void KeyChordListener::_OnKeysChanged(DependencyObject const& d, DependencyPropertyChangedEventArgs const& e)
|
||||
{
|
||||
if (auto control{ d.try_as<Editor::KeyChordListener>() })
|
||||
{
|
||||
auto controlImpl{ get_self<KeyChordListener>(control) };
|
||||
TextBox tb{ controlImpl->FindName(L"KeyChordTextBox").as<TextBox>() };
|
||||
tb.Text(Model::KeyChordSerialization::ToString(unbox_value<Control::KeyChord>(e.NewValue())));
|
||||
if (auto automationPeer{ Automation::Peers::FrameworkElementAutomationPeer::FromElement(tb) })
|
||||
{
|
||||
automationPeer.RaiseNotificationEvent(
|
||||
Automation::Peers::AutomationNotificationKind::ActionCompleted,
|
||||
Automation::Peers::AutomationNotificationProcessing::MostRecent,
|
||||
tb.Text(),
|
||||
L"KeyChordListenerText");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyChordListener::KeyChordTextBox_KeyDown(IInspectable const& /*sender*/, KeyRoutedEventArgs const& e)
|
||||
{
|
||||
const auto key{ e.OriginalKey() };
|
||||
for (const auto mod : ModifierKeys)
|
||||
{
|
||||
if (key == mod)
|
||||
{
|
||||
// Ignore modifier keys
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const auto modifiers{ _GetModifiers() };
|
||||
if (key == VirtualKey::Tab && (modifiers == VirtualKeyModifiers::None || modifiers == VirtualKeyModifiers::Shift))
|
||||
{
|
||||
// [Shift]+[Tab] && [Tab] are needed for keyboard navigation
|
||||
return;
|
||||
}
|
||||
|
||||
// Permitted key events are used to update _Keys
|
||||
Keys({ modifiers, static_cast<int32_t>(key) });
|
||||
e.Handled(true);
|
||||
}
|
||||
}
|
||||
29
src/cascadia/TerminalSettingsEditor/KeyChordListener.h
Normal file
29
src/cascadia/TerminalSettingsEditor/KeyChordListener.h
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KeyChordListener.g.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct KeyChordListener : KeyChordListenerT<KeyChordListener>
|
||||
{
|
||||
public:
|
||||
KeyChordListener();
|
||||
|
||||
void KeyChordTextBox_KeyDown(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
|
||||
DEPENDENCY_PROPERTY(Control::KeyChord, Keys);
|
||||
|
||||
private:
|
||||
static void _InitializeProperties();
|
||||
static void _OnKeysChanged(Windows::UI::Xaml::DependencyObject const& d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs const& e);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(KeyChordListener);
|
||||
}
|
||||
13
src/cascadia/TerminalSettingsEditor/KeyChordListener.idl
Normal file
13
src/cascadia/TerminalSettingsEditor/KeyChordListener.idl
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
[default_interface] runtimeclass KeyChordListener : Windows.UI.Xaml.Controls.UserControl
|
||||
{
|
||||
KeyChordListener();
|
||||
|
||||
Microsoft.Terminal.Control.KeyChord Keys;
|
||||
static Windows.UI.Xaml.DependencyProperty KeysProperty { get; };
|
||||
}
|
||||
}
|
||||
17
src/cascadia/TerminalSettingsEditor/KeyChordListener.xaml
Normal file
17
src/cascadia/TerminalSettingsEditor/KeyChordListener.xaml
Normal file
@@ -0,0 +1,17 @@
|
||||
<UserControl x:Class="Microsoft.Terminal.Settings.Editor.KeyChordListener"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<!-- Use PreviewKeyDown to prevent ctrl+a from selecting -->
|
||||
<TextBox x:Name="KeyChordTextBox"
|
||||
x:Uid="KeyChordListener"
|
||||
IsReadOnly="True"
|
||||
IsSpellCheckEnabled="False"
|
||||
IsTabStop="True"
|
||||
PreviewKeyDown="KeyChordTextBox_KeyDown"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap" />
|
||||
</UserControl>
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Interaction.h"
|
||||
#include "Rendering.h"
|
||||
#include "Actions.h"
|
||||
#include "ReadOnlyActions.h"
|
||||
#include "Profiles.h"
|
||||
#include "GlobalAppearance.h"
|
||||
#include "ColorSchemes.h"
|
||||
@@ -33,6 +34,7 @@ static const std::wstring_view launchTag{ L"Launch_Nav" };
|
||||
static const std::wstring_view interactionTag{ L"Interaction_Nav" };
|
||||
static const std::wstring_view renderingTag{ L"Rendering_Nav" };
|
||||
static const std::wstring_view actionsTag{ L"Actions_Nav" };
|
||||
static const std::wstring_view globalProfileTag{ L"GlobalProfile_Nav" };
|
||||
static const std::wstring_view addProfileTag{ L"AddProfile" };
|
||||
static const std::wstring_view colorSchemesTag{ L"ColorSchemes_Nav" };
|
||||
static const std::wstring_view globalAppearanceTag{ L"GlobalAppearance_Nav" };
|
||||
@@ -130,7 +132,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// refresh the current page using the SelectedItem data we collected before the refresh
|
||||
if (selectedItemTag)
|
||||
{
|
||||
for (const auto& item : menuItemsSTL)
|
||||
for (const auto& item : menuItems)
|
||||
{
|
||||
if (const auto& menuItem{ item.try_as<MUX::Controls::NavigationViewItem>() })
|
||||
{
|
||||
@@ -167,14 +169,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// couldn't find the selected item,
|
||||
// fallback to first menu item
|
||||
const auto& firstItem{ menuItems.GetAt(0) };
|
||||
// Couldn't find the selected item, fallback to first menu item
|
||||
// This happens when the selected item was a profile which doesn't exist in the new configuration
|
||||
// We can use menuItemsSTL here because the only things they miss are profile entries.
|
||||
const auto& firstItem{ menuItemsSTL.at(0).as<MUX::Controls::NavigationViewItem>() };
|
||||
SettingsNav().SelectedItem(firstItem);
|
||||
if (const auto& tag{ SettingsNav().SelectedItem().try_as<MUX::Controls::NavigationViewItem>().Tag() })
|
||||
{
|
||||
_Navigate(unbox_value<hstring>(tag));
|
||||
}
|
||||
_Navigate(unbox_value<hstring>(firstItem.Tag()));
|
||||
}
|
||||
|
||||
void MainPage::SetHostingWindow(uint64_t hostingWindow) noexcept
|
||||
@@ -293,7 +293,32 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
else if (clickedItemTag == actionsTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Actions>(), winrt::make<ActionsPageNavigationState>(_settingsClone));
|
||||
if constexpr (Feature_EditableActionsPage::IsEnabled())
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Actions>(), winrt::make<ActionsPageNavigationState>(_settingsClone));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto actionsState{ winrt::make<ReadOnlyActionsPageNavigationState>(_settingsClone) };
|
||||
actionsState.OpenJson([weakThis = get_weak()](auto&&, auto&& arg) {
|
||||
if (auto self{ weakThis.get() })
|
||||
{
|
||||
self->_OpenJsonHandlers(nullptr, arg);
|
||||
}
|
||||
});
|
||||
contentFrame().Navigate(xaml_typename<Editor::ReadOnlyActions>(), actionsState);
|
||||
}
|
||||
}
|
||||
else if (clickedItemTag == globalProfileTag)
|
||||
{
|
||||
auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone) };
|
||||
profileVM.IsBaseLayer(true);
|
||||
_lastProfilesNavState = winrt::make<ProfilePageNavigationState>(profileVM,
|
||||
_settingsClone.GlobalSettings().ColorSchemes(),
|
||||
_lastProfilesNavState,
|
||||
*this);
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), _lastProfilesNavState);
|
||||
}
|
||||
else if (clickedItemTag == colorSchemesTag)
|
||||
{
|
||||
@@ -456,4 +481,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
SettingsNav().SelectedItem(newSelectedItem);
|
||||
_Navigate(newSelectedItem.try_as<MUX::Controls::NavigationViewItem>().Tag().try_as<Editor::ProfileViewModel>());
|
||||
}
|
||||
|
||||
bool MainPage::ShowBaseLayerMenuItem() const noexcept
|
||||
{
|
||||
return Feature_ShowProfileDefaultsInSettings::IsEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
bool TryPropagateHostingWindow(IInspectable object) noexcept;
|
||||
uint64_t GetHostingWindow() const noexcept;
|
||||
|
||||
bool ShowBaseLayerMenuItem() const noexcept;
|
||||
|
||||
TYPED_EVENT(OpenJson, Windows::Foundation::IInspectable, Model::SettingsTarget);
|
||||
|
||||
private:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user