mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-17 15:36:35 +00:00
Compare commits
31 Commits
dev/cazamo
...
v1.15.2282
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2a691863b | ||
|
|
76daf71cf9 | ||
|
|
22edbc1b37 | ||
|
|
479f625c36 | ||
|
|
f5aa18a389 | ||
|
|
6933429721 | ||
|
|
7453b159c1 | ||
|
|
dab0c3a010 | ||
|
|
8b9504b536 | ||
|
|
c4e60ad5d6 | ||
|
|
fc50edd5b4 | ||
|
|
531901505c | ||
|
|
b68de3e5c5 | ||
|
|
fff3372ed2 | ||
|
|
f3f9eba5c9 | ||
|
|
b670800460 | ||
|
|
210145a709 | ||
|
|
961925b04f | ||
|
|
b8847a3407 | ||
|
|
a4a12ef190 | ||
|
|
91a60caf41 | ||
|
|
88b527f606 | ||
|
|
976cddbe7c | ||
|
|
93c08bd459 | ||
|
|
ba8171e0a4 | ||
|
|
83e7e14978 | ||
|
|
74e3985ba8 | ||
|
|
9e05dcd4f3 | ||
|
|
81f2d3a834 | ||
|
|
0080b81149 | ||
|
|
2fdcd4e151 |
4
.github/actions/spelling/allow/apis.txt
vendored
4
.github/actions/spelling/allow/apis.txt
vendored
@@ -14,6 +14,7 @@ BYCOMMAND
|
||||
BYPOSITION
|
||||
charconv
|
||||
CLASSNOTAVAILABLE
|
||||
CLOSEAPP
|
||||
cmdletbinding
|
||||
COLORPROPERTY
|
||||
colspan
|
||||
@@ -28,9 +29,11 @@ dataobject
|
||||
dcomp
|
||||
DERR
|
||||
dlldata
|
||||
DNE
|
||||
DONTADDTORECENT
|
||||
DWORDLONG
|
||||
endfor
|
||||
ENDSESSION
|
||||
enumset
|
||||
environstrings
|
||||
EXPCMDFLAGS
|
||||
@@ -141,6 +144,7 @@ PEXPLICIT
|
||||
PICKFOLDERS
|
||||
pmr
|
||||
ptstr
|
||||
QUERYENDSESSION
|
||||
rcx
|
||||
REGCLS
|
||||
RETURNCMD
|
||||
|
||||
20
.github/actions/spelling/expect/expect.txt
vendored
20
.github/actions/spelling/expect/expect.txt
vendored
@@ -233,6 +233,7 @@ CFuzz
|
||||
cgscrn
|
||||
chafa
|
||||
changelist
|
||||
chaof
|
||||
charinfo
|
||||
charlespetzold
|
||||
charset
|
||||
@@ -438,7 +439,9 @@ ctlseqs
|
||||
Ctlv
|
||||
ctor
|
||||
CTRLEVENT
|
||||
CTRLFREQUENCY
|
||||
CTRLKEYSHORTCUTS
|
||||
CTRLVOLUME
|
||||
Ctx
|
||||
Ctxt
|
||||
ctype
|
||||
@@ -661,7 +664,14 @@ dropdown
|
||||
DROPDOWNLIST
|
||||
DROPFILES
|
||||
drv
|
||||
DSBCAPS
|
||||
DSBLOCK
|
||||
DSBPLAY
|
||||
DSBUFFERDESC
|
||||
DSBVOLUME
|
||||
dsm
|
||||
dsound
|
||||
DSSCL
|
||||
dst
|
||||
DSwap
|
||||
DTest
|
||||
@@ -682,6 +692,7 @@ dwrite
|
||||
dwriteglyphrundescriptionclustermap
|
||||
dxgi
|
||||
dxgidwm
|
||||
dxguid
|
||||
dxinterop
|
||||
dxp
|
||||
dxsm
|
||||
@@ -718,6 +729,7 @@ endptr
|
||||
endregion
|
||||
ENQ
|
||||
enqueuing
|
||||
ENTIREBUFFER
|
||||
entrypoint
|
||||
ENU
|
||||
enum
|
||||
@@ -934,6 +946,7 @@ gitfilters
|
||||
github
|
||||
gitlab
|
||||
gle
|
||||
GLOBALFOCUS
|
||||
globals
|
||||
GLYPHENTRY
|
||||
gmail
|
||||
@@ -1369,6 +1382,7 @@ lpv
|
||||
LPVOID
|
||||
LPW
|
||||
LPWCH
|
||||
lpwfx
|
||||
LPWINDOWPOS
|
||||
lpwpos
|
||||
lpwstr
|
||||
@@ -2187,8 +2201,6 @@ SETTITLE
|
||||
setw
|
||||
Setwindow
|
||||
SETWINDOWINFO
|
||||
SFGAO
|
||||
SFGAOF
|
||||
sfi
|
||||
SFINAE
|
||||
SFUI
|
||||
@@ -2678,6 +2690,7 @@ WANTARROWS
|
||||
WANTTAB
|
||||
wapproj
|
||||
wav
|
||||
WAVEFORMATEX
|
||||
wbuilder
|
||||
wch
|
||||
wchar
|
||||
@@ -2878,6 +2891,9 @@ xff
|
||||
xfg
|
||||
XFile
|
||||
XFORM
|
||||
xin
|
||||
xinchaof
|
||||
xinxinchaof
|
||||
XManifest
|
||||
XMath
|
||||
XMFLOAT
|
||||
|
||||
@@ -11,9 +11,9 @@ Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "CascadiaPackage", "src\casc
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.EXE", "src\host\exe\Host.EXE.vcxproj", "{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF} = {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
{5D23E8E1-3C64-4CC1-A8F7-6861677F7239} = {5D23E8E1-3C64-4CC1-A8F7-6861677F7239}
|
||||
{71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF} = {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropertiesLibrary", "src\propslib\propslib.vcxproj", "{345FD5A4-B32B-4F29-BD1C-B033BD2C35CC}"
|
||||
@@ -64,9 +64,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererGdi", "src\renderer
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host", "src\host\lib\hostlib.vcxproj", "{06EC74CB-9A12-429C-B551-8562EC954746}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
{18D09A24-8240-42D6-8CB6-236EEE820263} = {18D09A24-8240-42D6-8CB6-236EEE820263}
|
||||
{71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF} = {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.unittest", "src\host\ut_lib\host.unittest.vcxproj", "{06EC74CB-9A12-429C-B551-8562EC954747}"
|
||||
@@ -77,8 +77,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.unittest", "src\host\u
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.Tests.Unit", "src\host\ut_host\Host.UnitTests.vcxproj", "{531C23E7-4B76-4C08-8AAD-04164CB628C9}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
{06EC74CB-9A12-429C-B551-8562EC954747} = {06EC74CB-9A12-429C-B551-8562EC954747}
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TextBuffer.Unit.Tests", "src\buffer\out\ut_textbuffer\TextBuffer.Unit.Tests.vcxproj", "{531C23E7-4B76-4C08-8BBD-04164CB628C9}"
|
||||
@@ -89,9 +89,9 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.Tests.Feature", "src\host\ft_host\Host.FeatureTests.vcxproj", "{8CDB8850-7484-4EC7-B45B-181F85B2EE54}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{18D09A24-8240-42D6-8CB6-236EEE820263} = {18D09A24-8240-42D6-8CB6-236EEE820263}
|
||||
{FC802440-AD6A-4919-8F2C-7701F2B38D79} = {FC802440-AD6A-4919-8F2C-7701F2B38D79}
|
||||
{58A03BB2-DF5A-4B66-91A0-7EF3BA01269A} = {58A03BB2-DF5A-4B66-91A0-7EF3BA01269A}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
{FC802440-AD6A-4919-8F2C-7701F2B38D79} = {FC802440-AD6A-4919-8F2C-7701F2B38D79}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalParser.UnitTests", "src\terminal\parser\ut_parser\Parser.UnitTests.vcxproj", "{12144E07-FE63-4D33-9231-748B8D8C3792}"
|
||||
@@ -114,8 +114,8 @@ EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Host.Tests.UIA", "src\host\ft_uia\Host.Tests.UIA.csproj", "{C17E1BF3-9D34-4779-9458-A8EF98CC5662}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{099193A0-1E43-4BBC-BA7F-7B351E1342DF} = {099193A0-1E43-4BBC-BA7F-7B351E1342DF}
|
||||
{C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB} = {C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
{C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB} = {C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VTApp", "src\tools\vtapp\VTApp.csproj", "{099193A0-1E43-4BBC-BA7F-7B351E1342DF}"
|
||||
@@ -172,12 +172,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalCore", "src\cascadi
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Control.Lib", "src\cascadia\TerminalControl\TerminalControlLib.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{1CF55140-EF6A-4736-A403-957E4F7430BB} = {1CF55140-EF6A-4736-A403-957E4F7430BB}
|
||||
{48D21369-3D7B-4431-9967-24E81292CF62} = {48D21369-3D7B-4431-9967-24E81292CF62}
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63} = {48D21369-3D7B-4431-9967-24E81292CF63}
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F} = {8222900C-8B6C-452A-91AC-BE95DB04B95F}
|
||||
{AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F} = {AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Control", "src\cascadia\TerminalControl\dll\TerminalControl.vcxproj", "{CA5CAD1A-F542-4635-A069-7CAEFB930070}"
|
||||
@@ -187,21 +188,21 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Control"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminal", "src\cascadia\WindowsTerminal\WindowsTerminal.vcxproj", "{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
{27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia\TerminalApp\dll\TerminalApp.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminalShellExt", "src\cascadia\ShellExtension\WindowsTerminalShellExt.vcxproj", "{F2ED628A-DB22-446F-A081-4CC845B51A2B}"
|
||||
@@ -251,15 +252,15 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\cascadia\TerminalApp\TerminalAppLib.vcxproj", "{CA5CAD1A-9A12-429C-B551-8562EC954746}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_TerminalApp", "src\cascadia\LocalTests_TerminalApp\TerminalApp.LocalTests.vcxproj", "{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
@@ -273,9 +274,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winconpty.DLL", "src\wincon
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestHostApp", "src\cascadia\LocalTests_TerminalApp\TestHostApp\TestHostApp.vcxproj", "{A021EDFF-45C8-4DC2-BEF7-36E1B3B8CFE8}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {CA5CAD1A-9B68-456A-B13E-C8218070DC42}
|
||||
{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BDB237B6-1D1D-400F-84CC-40A58FA59C8E}"
|
||||
@@ -330,8 +331,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "src\dep\fmt\fmt.vcxp
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "src\cascadia\WpfTerminalTestNetCore\WpfTerminalTestNetCore.csproj", "{1588FD7C-241E-4E7D-9113-43735F3E6BAD}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A22EC5F6-7851-4B88-AC52-47249D437A52} = {A22EC5F6-7851-4B88-AC52-47249D437A52}
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890} = {84848BFA-931D-42CE-9ADF-01EE54DE7890}
|
||||
{A22EC5F6-7851-4B88-AC52-47249D437A52} = {A22EC5F6-7851-4B88-AC52-47249D437A52}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wt", "src\cascadia\wt\wt.vcxproj", "{506FD703-BAA7-4F6E-9361-64F550EC8FCA}"
|
||||
@@ -356,9 +357,9 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_SettingsModel", "src\cascadia\LocalTests_SettingsModel\SettingsModel.LocalTests.vcxproj", "{CA5CAD1A-9B68-456A-B13E-C8218070DC42}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MonarchPeasantSample", "src\tools\MonarchPeasantSample\MonarchPeasantSample.vcxproj", "{21B7EA5E-1EF8-49B6-AC07-11714AF0E37D}"
|
||||
@@ -377,8 +378,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Remoting
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_Remoting", "src\cascadia\UnitTests_Remoting\Remoting.UnitTests.vcxproj", "{68A10CD3-AA64-465B-AF5F-ED4E9700543C}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{43CE4CE5-0010-4B99-9569-672670D26E26} = {43CE4CE5-0010-4B99-9569-672670D26E26}
|
||||
{27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}
|
||||
{43CE4CE5-0010-4B99-9569-672670D26E26} = {43CE4CE5-0010-4B99-9569-672670D26E26}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wpf", "wpf", "{4DAF0299-495E-4CD1-A982-9BAC16A45932}"
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
<package id="Microsoft.Taef" version="10.60.210621002" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
|
||||
<!-- This cannot be included in another project that depends on XAML (as it would be a duplicate package ID) -->
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.0" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
This version should be tracked in all project packages.config files for projects that depend on Xaml.
|
||||
-->
|
||||
<TerminalMUXVersion>2.7.2-prerelease.220406002</TerminalMUXVersion>
|
||||
<TerminalMUXVersion>2.7.3-prerelease.220816001</TerminalMUXVersion>
|
||||
<!--
|
||||
For the Windows 11-specific build, we're targeting the public version of Microsoft.UI.Xaml.
|
||||
This version emits a package dependency instead of embedding the dependency in our own package.
|
||||
|
||||
This version should be tracked in build/packages.config.
|
||||
-->
|
||||
<TerminalMUXVersion Condition="'$(TerminalTargetWindowsVersion)'=='Win11'">2.7.1</TerminalMUXVersion>
|
||||
<TerminalMUXVersion Condition="'$(TerminalTargetWindowsVersion)'=='Win11'">2.7.3</TerminalMUXVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.Windows.Terminal.ThemeHelpers" version="0.6.220404001" targetFramework="native" />
|
||||
<package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="2.3.2262" targetFramework="native" developmentDependency="true" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.2-prerelease.220406002" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3-prerelease.220816001" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220201.1" targetFramework="native" developmentDependency="true" />
|
||||
|
||||
<!-- Managed packages -->
|
||||
|
||||
@@ -366,6 +366,10 @@
|
||||
"quit",
|
||||
"adjustOpacity",
|
||||
"restoreLastClosed",
|
||||
"addMark",
|
||||
"scrollToMark",
|
||||
"clearMark",
|
||||
"clearAllMarks",
|
||||
"unbound"
|
||||
],
|
||||
"type": "string"
|
||||
@@ -385,6 +389,15 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ScrollToMarkDirection": {
|
||||
"enum": [
|
||||
"previous",
|
||||
"next",
|
||||
"first",
|
||||
"last"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ResizeDirection": {
|
||||
"enum": [
|
||||
"left",
|
||||
@@ -734,6 +747,30 @@
|
||||
"direction"
|
||||
]
|
||||
},
|
||||
"ScrollToMarkAction": {
|
||||
"description": "Arguments corresponding to a Scroll to Mark Action",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "scrollToMark"
|
||||
},
|
||||
"direction": {
|
||||
"$ref": "#/$defs/ScrollToMarkDirection",
|
||||
"default": "previous",
|
||||
"description": "The direction to scroll to a mark."
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [
|
||||
"direction"
|
||||
]
|
||||
},
|
||||
"SendInputAction": {
|
||||
"description": "Arguments corresponding to a Send Input Action",
|
||||
"allOf": [
|
||||
@@ -841,6 +878,27 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"AddMarkAction": {
|
||||
"description": "Arguments corresponding to an Add Mark Action",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "addMark"
|
||||
},
|
||||
"color": {
|
||||
"$ref": "#/$defs/Color",
|
||||
"default": null,
|
||||
"description": "If provided, will set the mark's color to the given value."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"SetColorSchemeAction": {
|
||||
"description": "Arguments corresponding to a Set Color Scheme Action",
|
||||
"allOf": [
|
||||
@@ -1669,6 +1727,16 @@
|
||||
"description": "When set to true, URLs will be detected by the Terminal. This will cause URLs to underline on hover and be clickable by pressing Ctrl.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.autoMarkPrompts": {
|
||||
"default": false,
|
||||
"description": "When set to true, prompts will automatically be marked.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.showMarksOnScrollbar": {
|
||||
"default": false,
|
||||
"description": "When set to true, marks added to the buffer via the addMark action will appear on the scrollbar.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableAnimations": {
|
||||
"default": false,
|
||||
"description": "When set to `true`, visual animations will be disabled across the application.",
|
||||
@@ -2013,15 +2081,20 @@
|
||||
"description": "Controls what happens when the application emits a BEL character. When set to \"all\", the Terminal will play a sound, flash the taskbar icon (if the terminal window is not in focus) and flash the window. An array of specific behaviors can also be used. Supported array values include `audible`, `window` and `taskbar`. When set to \"none\", nothing will happen.",
|
||||
"$ref": "#/$defs/BellStyle"
|
||||
},
|
||||
"bellSound": {
|
||||
"description": "Sets the sound played when the application emits a BEL. When set to an array, the terminal will pick one of those sounds at random.",
|
||||
"$ref": "#/$defs/BellSound"
|
||||
},
|
||||
"closeOnExit": {
|
||||
"default": "graceful",
|
||||
"description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.",
|
||||
"default": "automatic",
|
||||
"description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"automatic\" (behave as \"graceful\" only for processes launched by terminal, behave as \"always\" otherwise)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": [
|
||||
"never",
|
||||
"graceful",
|
||||
"always"
|
||||
"always",
|
||||
"automatic"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -5,55 +5,30 @@
|
||||
#include "MidiAudio.hpp"
|
||||
#include "../terminal/parser/stateMachine.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class MidiOut
|
||||
{
|
||||
public:
|
||||
static constexpr auto NOTE_OFF = 0x80;
|
||||
static constexpr auto NOTE_ON = 0x90;
|
||||
static constexpr auto PROGRAM_CHANGE = 0xC0;
|
||||
#include <dsound.h>
|
||||
|
||||
// We're using a square wave as an approximation of the sound that the
|
||||
// original VT525 terminals might have produced. This is probably not
|
||||
// quite right, but it works reasonably well.
|
||||
static constexpr auto SQUARE_WAVE_SYNTH = 80;
|
||||
|
||||
MidiOut() noexcept
|
||||
{
|
||||
if constexpr (Feature_DECPSViaMidiPlayer::IsEnabled())
|
||||
{
|
||||
midiOutOpen(&handle, MIDI_MAPPER, NULL, NULL, CALLBACK_NULL);
|
||||
OutputMessage(PROGRAM_CHANGE, SQUARE_WAVE_SYNTH);
|
||||
}
|
||||
}
|
||||
~MidiOut() noexcept
|
||||
{
|
||||
if constexpr (Feature_DECPSViaMidiPlayer::IsEnabled())
|
||||
{
|
||||
midiOutClose(handle);
|
||||
}
|
||||
}
|
||||
void OutputMessage(const int b1, const int b2, const int b3 = 0, const int b4 = 0) noexcept
|
||||
{
|
||||
if constexpr (Feature_DECPSViaMidiPlayer::IsEnabled())
|
||||
{
|
||||
midiOutShortMsg(handle, MAKELONG(MAKEWORD(b1, b2), MAKEWORD(b3, b4)));
|
||||
}
|
||||
}
|
||||
|
||||
MidiOut(const MidiOut&) = delete;
|
||||
MidiOut(MidiOut&&) = delete;
|
||||
MidiOut& operator=(const MidiOut&) = delete;
|
||||
MidiOut& operator=(MidiOut&&) = delete;
|
||||
|
||||
private:
|
||||
HMIDIOUT handle = nullptr;
|
||||
};
|
||||
}
|
||||
#pragma comment(lib, "dxguid.lib")
|
||||
#pragma comment(lib, "dsound.lib")
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
// The WAVE_DATA below is an 8-bit PCM encoding of a triangle wave form.
|
||||
// We just play this on repeat at varying frequencies to produce our notes.
|
||||
constexpr auto WAVE_SIZE = 16u;
|
||||
constexpr auto WAVE_DATA = std::array<byte, WAVE_SIZE>{ 128, 159, 191, 223, 255, 223, 191, 159, 128, 96, 64, 32, 0, 32, 64, 96 };
|
||||
|
||||
MidiAudio::MidiAudio(HWND windowHandle)
|
||||
{
|
||||
if (SUCCEEDED(DirectSoundCreate8(nullptr, &_directSound, nullptr)))
|
||||
{
|
||||
if (SUCCEEDED(_directSound->SetCooperativeLevel(windowHandle, DSSCL_NORMAL)))
|
||||
{
|
||||
_createBuffers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MidiAudio::~MidiAudio() noexcept
|
||||
{
|
||||
try
|
||||
@@ -61,7 +36,7 @@ MidiAudio::~MidiAudio() noexcept
|
||||
#pragma warning(suppress : 26447)
|
||||
// We acquire the lock here so the class isn't destroyed while in use.
|
||||
// If this throws, we'll catch it, so the C26447 warning is bogus.
|
||||
_inUseMutex.lock();
|
||||
const auto lock = std::unique_lock{ _inUseMutex };
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -103,13 +78,26 @@ void MidiAudio::Unlock()
|
||||
void MidiAudio::PlayNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) noexcept
|
||||
try
|
||||
{
|
||||
// The MidiOut is a local static because we can only have one instance,
|
||||
// and we only want to construct it when it's actually needed.
|
||||
static MidiOut midiOut;
|
||||
|
||||
if (velocity)
|
||||
const auto& buffer = _buffers.at(_activeBufferIndex);
|
||||
if (velocity && buffer)
|
||||
{
|
||||
midiOut.OutputMessage(MidiOut::NOTE_ON, noteNumber, velocity);
|
||||
// The formula for frequency is 2^(n/12) * 440Hz, where n is zero for
|
||||
// the A above middle C (A4). In MIDI terms, A4 is note number 69,
|
||||
// which is why we subtract 69. We also need to multiply by the size
|
||||
// of the wave form to determine the frequency that the sound buffer
|
||||
// has to be played to achieve the equivalent note frequency.
|
||||
const auto frequency = std::pow(2.0, (noteNumber - 69.0) / 12.0) * 440.0 * WAVE_SIZE;
|
||||
buffer->SetFrequency(gsl::narrow_cast<DWORD>(frequency));
|
||||
// For the volume, we're using the formula defined in the the General
|
||||
// MIDI Level 2 specification: Gain in dB = 40 * log10(v/127). We need
|
||||
// to multiply by 4000, though, because the SetVolume method expects
|
||||
// the volume to be in hundredths of a decibel.
|
||||
const auto volume = 4000.0 * std::log10(velocity / 127.0);
|
||||
buffer->SetVolume(gsl::narrow_cast<LONG>(volume));
|
||||
// Resetting the buffer to a position that is slightly off from the
|
||||
// last position will help to produce a clearer separation between
|
||||
// tones when repeating sequences of the same note.
|
||||
buffer->SetCurrentPosition((_lastBufferPosition + 12) % WAVE_SIZE);
|
||||
}
|
||||
|
||||
// By waiting on the shutdown future with the duration of the note, we'll
|
||||
@@ -117,9 +105,48 @@ try
|
||||
// of the wait early if we've been shutdown.
|
||||
_shutdownFuture.wait_for(duration);
|
||||
|
||||
if (velocity)
|
||||
if (velocity && buffer)
|
||||
{
|
||||
midiOut.OutputMessage(MidiOut::NOTE_OFF, noteNumber, velocity);
|
||||
// When the note ends, we just turn the volume down instead of stopping
|
||||
// the sound buffer. This helps reduce unwanted static between notes.
|
||||
buffer->SetVolume(DSBVOLUME_MIN);
|
||||
buffer->GetCurrentPosition(&_lastBufferPosition, nullptr);
|
||||
}
|
||||
|
||||
// Cycling between multiple buffers can also help reduce the static.
|
||||
_activeBufferIndex = (_activeBufferIndex + 1) % _buffers.size();
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
void MidiAudio::_createBuffers() noexcept
|
||||
{
|
||||
auto waveFormat = WAVEFORMATEX{};
|
||||
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||
waveFormat.nChannels = 1;
|
||||
waveFormat.nSamplesPerSec = 8000;
|
||||
waveFormat.wBitsPerSample = 8;
|
||||
waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
|
||||
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
|
||||
|
||||
auto bufferDescription = DSBUFFERDESC{};
|
||||
bufferDescription.dwSize = sizeof(DSBUFFERDESC);
|
||||
bufferDescription.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS;
|
||||
bufferDescription.dwBufferBytes = WAVE_SIZE;
|
||||
bufferDescription.lpwfxFormat = &waveFormat;
|
||||
|
||||
for (auto& buffer : _buffers)
|
||||
{
|
||||
if (SUCCEEDED(_directSound->CreateSoundBuffer(&bufferDescription, &buffer, nullptr)))
|
||||
{
|
||||
LPVOID bufferPtr;
|
||||
DWORD bufferSize;
|
||||
if (SUCCEEDED(buffer->Lock(0, 0, &bufferPtr, &bufferSize, nullptr, nullptr, DSBLOCK_ENTIREBUFFER)))
|
||||
{
|
||||
std::memcpy(bufferPtr, WAVE_DATA.data(), WAVE_DATA.size());
|
||||
buffer->Unlock(bufferPtr, bufferSize, nullptr, 0);
|
||||
}
|
||||
buffer->SetVolume(DSBVOLUME_MIN);
|
||||
buffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,17 @@ Abstract:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
|
||||
struct IDirectSound8;
|
||||
struct IDirectSoundBuffer;
|
||||
|
||||
class MidiAudio
|
||||
{
|
||||
public:
|
||||
MidiAudio() = default;
|
||||
MidiAudio(HWND windowHandle);
|
||||
MidiAudio(const MidiAudio&) = delete;
|
||||
MidiAudio(MidiAudio&&) = delete;
|
||||
MidiAudio& operator=(const MidiAudio&) = delete;
|
||||
@@ -30,6 +34,12 @@ public:
|
||||
void PlayNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) noexcept;
|
||||
|
||||
private:
|
||||
void _createBuffers() noexcept;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDirectSound8> _directSound;
|
||||
std::array<Microsoft::WRL::ComPtr<IDirectSoundBuffer>, 2> _buffers;
|
||||
size_t _activeBufferIndex = 0;
|
||||
DWORD _lastBufferPosition = 0;
|
||||
std::promise<void> _shutdownPromise;
|
||||
std::future<void> _shutdownFuture;
|
||||
std::mutex _inUseMutex;
|
||||
|
||||
@@ -357,11 +357,6 @@ void TextAttribute::SetReverseVideo(bool isReversed) noexcept
|
||||
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO, isReversed);
|
||||
}
|
||||
|
||||
ExtendedAttributes TextAttribute::GetExtendedAttributes() const noexcept
|
||||
{
|
||||
return _extendedAttrs;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - swaps foreground and background color
|
||||
void TextAttribute::Invert() noexcept
|
||||
|
||||
@@ -109,7 +109,10 @@ public:
|
||||
void SetOverlined(bool isOverlined) noexcept;
|
||||
void SetReverseVideo(bool isReversed) noexcept;
|
||||
|
||||
ExtendedAttributes GetExtendedAttributes() const noexcept;
|
||||
constexpr ExtendedAttributes GetExtendedAttributes() const noexcept
|
||||
{
|
||||
return _extendedAttrs;
|
||||
}
|
||||
|
||||
bool IsHyperlink() const noexcept;
|
||||
|
||||
@@ -161,6 +164,13 @@ public:
|
||||
{
|
||||
return WI_IsAnyFlagSet(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL | COMMON_LVB_GRID_LVERTICAL | COMMON_LVB_GRID_RVERTICAL | COMMON_LVB_UNDERSCORE);
|
||||
}
|
||||
constexpr bool HasAnyExtendedAttributes() const noexcept
|
||||
{
|
||||
return GetExtendedAttributes() != ExtendedAttributes::Normal ||
|
||||
IsAnyGridLineEnabled() ||
|
||||
GetHyperlinkId() != 0 ||
|
||||
IsReverseVideo();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::array<TextColor, 16> s_legacyForegroundColorMap;
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(OpenConsoleDir)src\wap-common.build.pre.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<!--
|
||||
These two properties are very important!
|
||||
@@ -164,13 +169,7 @@
|
||||
</Target>
|
||||
|
||||
<!-- This is required to get the package dependency in the AppXManifest. -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
</Project>
|
||||
|
||||
@@ -103,6 +103,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
auto proposedCommandline = false;
|
||||
Remoting::ProposeCommandlineResult result{ nullptr };
|
||||
auto attempts = 0;
|
||||
while (!proposedCommandline)
|
||||
{
|
||||
try
|
||||
@@ -118,78 +119,78 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
proposedCommandline = true;
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
catch (...)
|
||||
{
|
||||
// We did not successfully ask the king what to do. They
|
||||
// hopefully just died here. That's okay, let's just go ask the
|
||||
// next in the line of succession. At the very worst, we'll find
|
||||
// _us_, (likely last in the line).
|
||||
// We did not successfully ask the king what to do. This could
|
||||
// be for many reasons. Most commonly, the monarch died as we
|
||||
// were talking to it. That could be a RPC_SERVER_UNAVAILABLE_HR
|
||||
// or RPC_CALL_FAILED_HR (GH#12666). We also saw a
|
||||
// RPC_S_CALL_FAILED_DNE in GH#11790. Ultimately, if this is
|
||||
// gonna fail, we want to just try again, regardless of the
|
||||
// cause. That's why we're no longer checking what the exception
|
||||
// was, we're just always gonna try again regardless.
|
||||
//
|
||||
// If the king returned some _other_ error here, than lets
|
||||
// bubble that up because that's a real issue.
|
||||
//
|
||||
// I'm checking both these here. I had previously got a
|
||||
// RPC_S_CALL_FAILED about here once.
|
||||
if (e.code() == RPC_SERVER_UNAVAILABLE_HR || e.code() == RPC_CALL_FAILED_HR)
|
||||
// They hopefully just died here. That's okay, let's just go
|
||||
// ask the next in the line of succession. At the very worst,
|
||||
// we'll find _us_, (likely last in the line).
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_unexpectedExceptionFromKing",
|
||||
TraceLoggingInt32(attempts, "attempts", "How many times we've tried"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
attempts++;
|
||||
|
||||
if (attempts >= 10)
|
||||
{
|
||||
// We've tried 10 times to find the monarch, failing each
|
||||
// time. Since we have no idea why, we're guessing that in
|
||||
// this case, there's just a Monarch registered that's
|
||||
// misbehaving. In this case, just fall back to
|
||||
// "IsolatedMonarchMode" - we can't trust the currently
|
||||
// registered one.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_kingDied",
|
||||
"WindowManager_TooManyAttempts_NullMonarchIsolateMode",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
_monarch = winrt::make<winrt::Microsoft::Terminal::Remoting::implementation::Monarch>();
|
||||
_createCallbacks();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We failed to ask the monarch. It must have died. Try and
|
||||
// find the real monarch. Don't perform an election, that
|
||||
// assumes we have a peasant, which we don't yet.
|
||||
_createMonarchAndCallbacks();
|
||||
// _createMonarchAndCallbacks will initialize _isKing
|
||||
if (_isKing)
|
||||
{
|
||||
// We became the king. We don't need to ProposeCommandline to ourself, we're just
|
||||
// going to do it.
|
||||
//
|
||||
// Return early, because there's nothing else for us to do here.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_becameKing",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
// In WindowManager::ProposeCommandline, had we been the
|
||||
// king originally, we would have started by setting
|
||||
// this to true. We became the monarch here, so set it
|
||||
// here as well.
|
||||
_shouldCreateWindow = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Here, we created the new monarch, it wasn't us, so we're
|
||||
// gonna go through the while loop again and ask the new
|
||||
// king.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_tryAgain",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
if (_isKing)
|
||||
{
|
||||
// We became the king. We don't need to ProposeCommandline to ourself, we're just
|
||||
// going to do it.
|
||||
//
|
||||
// Return early, because there's nothing else for us to do here.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_unexpectedResultFromKing",
|
||||
"WindowManager_proposeToMonarch_becameKing",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
throw;
|
||||
|
||||
// In WindowManager::ProposeCommandline, had we been the
|
||||
// king originally, we would have started by setting
|
||||
// this to true. We became the monarch here, so set it
|
||||
// here as well.
|
||||
_shouldCreateWindow = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// If the monarch (maybe us) failed for _any other reason_ than
|
||||
// them dying. This IS quite unexpected. Let this bubble out.
|
||||
|
||||
// Here, we created the new monarch, it wasn't us, so we're
|
||||
// gonna go through the while loop again and ask the new
|
||||
// king.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_unexpectedExceptionFromKing",
|
||||
"WindowManager_proposeToMonarch_tryAgain",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,15 +346,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
CLSCTX_LOCAL_SERVER);
|
||||
}
|
||||
|
||||
// NOTE: This can throw! Callers include:
|
||||
// - the constructor, who performs this in a loop until it successfully
|
||||
// find a a monarch
|
||||
// - the performElection method, which is called in the waitOnMonarch
|
||||
// thread. All the calls in that thread are wrapped in try/catch's
|
||||
// already.
|
||||
// - _createOurPeasant, who might do this in a loop to establish us with the
|
||||
// monarch.
|
||||
void WindowManager::_createMonarchAndCallbacks()
|
||||
// Tries to instantiate a monarch, tries again, and eventually either throws
|
||||
// (so that the caller will try again) or falls back to the isolated
|
||||
// monarch.
|
||||
void WindowManager::_redundantCreateMonarch()
|
||||
{
|
||||
_createMonarch();
|
||||
|
||||
@@ -399,9 +395,26 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
winrt::hresult_error(E_UNEXPECTED, L"Did not expect the Monarch to ever be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This can throw! Callers include:
|
||||
// - the constructor, who performs this in a loop until it successfully
|
||||
// find a a monarch
|
||||
// - the performElection method, which is called in the waitOnMonarch
|
||||
// thread. All the calls in that thread are wrapped in try/catch's
|
||||
// already.
|
||||
// - _createOurPeasant, who might do this in a loop to establish us with the
|
||||
// monarch.
|
||||
void WindowManager::_createMonarchAndCallbacks()
|
||||
{
|
||||
_redundantCreateMonarch();
|
||||
// We're pretty confident that we have a Monarch here.
|
||||
_createCallbacks();
|
||||
}
|
||||
|
||||
// Check if we became the king, and if we are, wire up callbacks.
|
||||
void WindowManager::_createCallbacks()
|
||||
{
|
||||
// Save the result of checking if we're the king. We want to avoid
|
||||
// unnecessary calls back and forth if we can.
|
||||
_isKing = _areWeTheKing();
|
||||
|
||||
@@ -72,7 +72,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
void _registerAsMonarch();
|
||||
void _createMonarch();
|
||||
void _redundantCreateMonarch();
|
||||
void _createMonarchAndCallbacks();
|
||||
void _createCallbacks();
|
||||
bool _areWeTheKing();
|
||||
winrt::Microsoft::Terminal::Remoting::IPeasant _createOurPeasant(std::optional<uint64_t> givenID,
|
||||
const winrt::hstring& givenName);
|
||||
|
||||
@@ -97,7 +97,7 @@ HRESULT OpenTerminalHere::GetTitle(IShellItemArray* /*psiItemArray*/,
|
||||
return SHStrDup(resource.data(), ppszName);
|
||||
}
|
||||
|
||||
HRESULT OpenTerminalHere::GetState(IShellItemArray* psiItemArray,
|
||||
HRESULT OpenTerminalHere::GetState(IShellItemArray* /*psiItemArray*/,
|
||||
BOOL /*fOkToBeSlow*/,
|
||||
EXPCMDSTATE* pCmdState)
|
||||
{
|
||||
@@ -106,25 +106,10 @@ HRESULT OpenTerminalHere::GetState(IShellItemArray* psiItemArray,
|
||||
// E_PENDING and this object will be called back on a background thread with
|
||||
// fOkToBeSlow == TRUE
|
||||
|
||||
// We however don't need to bother with any of that.
|
||||
|
||||
// If no item was selected when the context menu was opened and Explorer
|
||||
// is not at a valid path (e.g. This PC or Quick Access), we should hide
|
||||
// the verb from the context menu.
|
||||
if (psiItemArray == nullptr)
|
||||
{
|
||||
const auto path = this->_GetPathFromExplorer();
|
||||
*pCmdState = path.empty() ? ECS_HIDDEN : ECS_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
winrt::com_ptr<IShellItem> psi;
|
||||
psiItemArray->GetItemAt(0, psi.put());
|
||||
SFGAOF attributes;
|
||||
const bool isFileSystemItem = (psi->GetAttributes(SFGAO_FILESYSTEM, &attributes) == S_OK);
|
||||
*pCmdState = isFileSystemItem ? ECS_ENABLED : ECS_HIDDEN;
|
||||
}
|
||||
// We however don't need to bother with any of that, so we'll just return
|
||||
// ECS_ENABLED.
|
||||
|
||||
*pCmdState = ECS_ENABLED;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -606,7 +606,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
activeTab->ActivateColorPicker();
|
||||
activeTab->RequestColorPicker();
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_root->Maximized(true);
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode))
|
||||
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode) && !IsQuakeWindow())
|
||||
{
|
||||
_root->SetFullscreen(true);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,15 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
|
||||
void DebugTapConnection::_OutputHandler(const hstring str)
|
||||
{
|
||||
_TerminalOutputHandlers(til::visualize_control_codes(str));
|
||||
auto output = til::visualize_control_codes(str);
|
||||
// To make the output easier to read, we introduce a line break whenever
|
||||
// an LF control is encountered. But at this point, the LF would have
|
||||
// been converted to U+240A (␊), so that's what we need to search for.
|
||||
for (size_t lfPos = 0; (lfPos = output.find(L'\u240A', lfPos)) != std::wstring::npos;)
|
||||
{
|
||||
output.insert(++lfPos, L"\r\n");
|
||||
}
|
||||
_TerminalOutputHandlers(output);
|
||||
}
|
||||
|
||||
// Called by the DebugInputTapConnection to print user input
|
||||
|
||||
@@ -89,12 +89,8 @@ winrt::fire_and_forget Jumplist::UpdateJumplist(const CascadiaSettings& settings
|
||||
winrt::com_ptr<IObjectCollection> jumplistItems;
|
||||
jumplistItems.capture(jumplistInstance, &ICustomDestinationList::BeginList, &slots);
|
||||
|
||||
// It's easier to clear the list and re-add everything. The settings aren't
|
||||
// updated often, and there likely isn't a huge amount of items to add.
|
||||
THROW_IF_FAILED(jumplistItems->Clear());
|
||||
|
||||
// Update the list of profiles.
|
||||
THROW_IF_FAILED(_updateProfiles(jumplistItems.get(), strongSettings.ActiveProfiles().GetView()));
|
||||
_updateProfiles(jumplistItems.get(), strongSettings.ActiveProfiles().GetView());
|
||||
|
||||
// TODO GH#1571: Add items from the future customizable new tab dropdown as well.
|
||||
// This could either replace the default profiles, or be added alongside them.
|
||||
@@ -116,26 +112,22 @@ winrt::fire_and_forget Jumplist::UpdateJumplist(const CascadiaSettings& settings
|
||||
// - profiles - The profiles to add to the jumplist
|
||||
// Return Value:
|
||||
// - S_OK or HRESULT failure code.
|
||||
[[nodiscard]] HRESULT Jumplist::_updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView<Profile> profiles) noexcept
|
||||
void Jumplist::_updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView<Profile> profiles)
|
||||
{
|
||||
try
|
||||
// It's easier to clear the list and re-add everything. The settings aren't
|
||||
// updated often, and there likely isn't a huge amount of items to add.
|
||||
THROW_IF_FAILED(jumplistItems->Clear());
|
||||
|
||||
for (const auto& profile : profiles)
|
||||
{
|
||||
for (const auto& profile : profiles)
|
||||
{
|
||||
// Craft the arguments following "wt.exe"
|
||||
auto args = fmt::format(L"-p {}", to_hstring(profile.Guid()));
|
||||
// Craft the arguments following "wt.exe"
|
||||
auto args = fmt::format(L"-p {}", to_hstring(profile.Guid()));
|
||||
|
||||
// Create the shell link object for the profile
|
||||
winrt::com_ptr<IShellLinkW> shLink;
|
||||
const auto normalizedIconPath{ _normalizeIconPath(profile.Icon()) };
|
||||
RETURN_IF_FAILED(_createShellLink(profile.Name(), normalizedIconPath, args, shLink.put()));
|
||||
|
||||
RETURN_IF_FAILED(jumplistItems->AddObject(shLink.get()));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
// Create the shell link object for the profile
|
||||
const auto normalizedIconPath{ _normalizeIconPath(profile.Icon()) };
|
||||
const auto shLink = _createShellLink(profile.Name(), normalizedIconPath, args);
|
||||
THROW_IF_FAILED(jumplistItems->AddObject(shLink.get()));
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -150,36 +142,27 @@ winrt::fire_and_forget Jumplist::UpdateJumplist(const CascadiaSettings& settings
|
||||
// - shLink: The shell link object to return.
|
||||
// Return Value:
|
||||
// - S_OK or HRESULT failure code.
|
||||
[[nodiscard]] HRESULT Jumplist::_createShellLink(const std::wstring_view name,
|
||||
const std::wstring_view path,
|
||||
const std::wstring_view args,
|
||||
IShellLinkW** shLink) noexcept
|
||||
winrt::com_ptr<IShellLinkW> Jumplist::_createShellLink(const std::wstring_view name, const std::wstring_view path, const std::wstring_view args)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto sh = winrt::create_instance<IShellLinkW>(CLSID_ShellLink, CLSCTX_ALL);
|
||||
auto sh = winrt::create_instance<IShellLinkW>(CLSID_ShellLink, CLSCTX_ALL);
|
||||
|
||||
const auto module{ GetWtExePath() };
|
||||
RETURN_IF_FAILED(sh->SetPath(module.data()));
|
||||
RETURN_IF_FAILED(sh->SetArguments(args.data()));
|
||||
const auto module{ GetWtExePath() };
|
||||
THROW_IF_FAILED(sh->SetPath(module.data()));
|
||||
THROW_IF_FAILED(sh->SetArguments(args.data()));
|
||||
|
||||
PROPVARIANT titleProp;
|
||||
titleProp.vt = VT_LPWSTR;
|
||||
titleProp.pwszVal = const_cast<wchar_t*>(name.data());
|
||||
PROPVARIANT titleProp;
|
||||
titleProp.vt = VT_LPWSTR;
|
||||
titleProp.pwszVal = const_cast<wchar_t*>(name.data());
|
||||
|
||||
PROPVARIANT iconProp;
|
||||
iconProp.vt = VT_LPWSTR;
|
||||
iconProp.pwszVal = const_cast<wchar_t*>(path.data());
|
||||
PROPVARIANT iconProp;
|
||||
iconProp.vt = VT_LPWSTR;
|
||||
iconProp.pwszVal = const_cast<wchar_t*>(path.data());
|
||||
|
||||
auto propStore{ sh.as<IPropertyStore>() };
|
||||
RETURN_IF_FAILED(propStore->SetValue(PKEY_Title, titleProp));
|
||||
RETURN_IF_FAILED(propStore->SetValue(PKEY_AppUserModel_DestListLogoUri, iconProp));
|
||||
auto propStore{ sh.as<IPropertyStore>() };
|
||||
THROW_IF_FAILED(propStore->SetValue(PKEY_Title, titleProp));
|
||||
THROW_IF_FAILED(propStore->SetValue(PKEY_AppUserModel_DestListLogoUri, iconProp));
|
||||
|
||||
RETURN_IF_FAILED(propStore->Commit());
|
||||
THROW_IF_FAILED(propStore->Commit());
|
||||
|
||||
*shLink = sh.detach();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
return sh;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@ public:
|
||||
static winrt::fire_and_forget UpdateJumplist(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) noexcept;
|
||||
|
||||
private:
|
||||
[[nodiscard]] static HRESULT _updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Settings::Model::Profile> profiles) noexcept;
|
||||
[[nodiscard]] static HRESULT _createShellLink(const std::wstring_view name, const std::wstring_view path, const std::wstring_view args, IShellLinkW** shLink) noexcept;
|
||||
static void _updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Settings::Model::Profile> profiles);
|
||||
static winrt::com_ptr<IShellLinkW> _createShellLink(const std::wstring_view name, const std::wstring_view path, const std::wstring_view args);
|
||||
};
|
||||
|
||||
@@ -1019,9 +1019,17 @@ void Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundatio
|
||||
|
||||
if (_profile)
|
||||
{
|
||||
if (_isDefTermSession && _profile.CloseOnExit() == CloseOnExitMode::Automatic)
|
||||
{
|
||||
// For 'automatic', we only care about the connection state if we were launched by Terminal
|
||||
// Since we were launched via defterm, ignore the connection state (i.e. we treat the
|
||||
// close on exit mode as 'always', see GH #13325 for discussion)
|
||||
Close();
|
||||
}
|
||||
|
||||
const auto mode = _profile.CloseOnExit();
|
||||
if ((mode == CloseOnExitMode::Always) ||
|
||||
(mode == CloseOnExitMode::Graceful && newConnectionState == ConnectionState::Closed))
|
||||
((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
@@ -1568,11 +1576,12 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||
// Find what borders need to persist after we close the child
|
||||
_borders = _GetCommonBorders();
|
||||
|
||||
// take the control, profile and id of the pane that _wasn't_ closed.
|
||||
// take the control, profile, id and isDefTermSession of the pane that _wasn't_ closed.
|
||||
_control = remainingChild->_control;
|
||||
_connectionState = remainingChild->_connectionState;
|
||||
_profile = remainingChild->_profile;
|
||||
_id = remainingChild->Id();
|
||||
_isDefTermSession = remainingChild->_isDefTermSession;
|
||||
|
||||
// Add our new event handler before revoking the old one.
|
||||
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
|
||||
@@ -2464,11 +2473,12 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move our control, guid into the first one.
|
||||
// Move our control, guid, isDefTermSession into the first one.
|
||||
_firstChild = std::make_shared<Pane>(_profile, _control);
|
||||
_firstChild->_connectionState = std::exchange(_connectionState, ConnectionState::NotConnected);
|
||||
_profile = nullptr;
|
||||
_control = { nullptr };
|
||||
_firstChild->_isDefTermSession = _isDefTermSession;
|
||||
}
|
||||
|
||||
_splitState = actualSplitType;
|
||||
@@ -3108,6 +3118,15 @@ int Pane::GetLeafPaneCount() const noexcept
|
||||
return _IsLeaf() ? 1 : (_firstChild->GetLeafPaneCount() + _secondChild->GetLeafPaneCount());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Should be called when this pane is created via a default terminal handoff
|
||||
// - Finalizes our configuration given the information that we have been
|
||||
// created via default handoff
|
||||
void Pane::FinalizeConfigurationGivenDefault()
|
||||
{
|
||||
_isDefTermSession = true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if the pane or one of its descendants is read-only
|
||||
bool Pane::ContainsReadOnly() const
|
||||
|
||||
@@ -132,6 +132,8 @@ public:
|
||||
bool FocusPane(const std::shared_ptr<Pane> pane);
|
||||
std::shared_ptr<Pane> FindPane(const uint32_t id);
|
||||
|
||||
void FinalizeConfigurationGivenDefault();
|
||||
|
||||
bool ContainsReadOnly() const;
|
||||
|
||||
// Method Description:
|
||||
@@ -212,21 +214,24 @@ private:
|
||||
winrt::Windows::UI::Xaml::Controls::Grid _root{};
|
||||
winrt::Windows::UI::Xaml::Controls::Border _borderFirst{};
|
||||
winrt::Windows::UI::Xaml::Controls::Border _borderSecond{};
|
||||
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
|
||||
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_focusedBorderBrush;
|
||||
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_unfocusedBorderBrush;
|
||||
|
||||
#pragma region Properties that need to be transferred between child / parent panes upon splitting / closing
|
||||
std::shared_ptr<Pane> _firstChild{ nullptr };
|
||||
std::shared_ptr<Pane> _secondChild{ nullptr };
|
||||
SplitState _splitState{ SplitState::None };
|
||||
float _desiredSplitPosition;
|
||||
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
|
||||
bool _isDefTermSession{ false };
|
||||
#pragma endregion
|
||||
|
||||
std::optional<uint32_t> _id;
|
||||
std::weak_ptr<Pane> _parentChildPath{};
|
||||
|
||||
bool _lastActive{ false };
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
|
||||
winrt::event_token _connectionStateChangedToken{ 0 };
|
||||
winrt::event_token _firstClosedToken{ 0 };
|
||||
winrt::event_token _secondClosedToken{ 0 };
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
</resheader>
|
||||
<data name="AppName" xml:space="preserve">
|
||||
<value>Terminal</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppNameDev" xml:space="preserve">
|
||||
<value>Terminal Dev</value>
|
||||
@@ -126,9 +127,11 @@
|
||||
</data>
|
||||
<data name="AppNamePre" xml:space="preserve">
|
||||
<value>Terminal Preview</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppStoreName" xml:space="preserve">
|
||||
<value>Windows Terminal</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppStoreNameDev" xml:space="preserve">
|
||||
<value>Windows Terminal Dev</value>
|
||||
@@ -136,9 +139,11 @@
|
||||
</data>
|
||||
<data name="AppStoreNamePre" xml:space="preserve">
|
||||
<value>Windows Terminal Preview</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppShortName" xml:space="preserve">
|
||||
<value>Terminal</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppShortNameDev" xml:space="preserve">
|
||||
<value>Terminal Dev</value>
|
||||
@@ -146,6 +151,7 @@
|
||||
</data>
|
||||
<data name="AppShortNamePre" xml:space="preserve">
|
||||
<value>Terminal Preview</value>
|
||||
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
|
||||
</data>
|
||||
<data name="AppDescription" xml:space="preserve">
|
||||
<value>The New Windows Terminal</value>
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
FontSize="12">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip Placement="Mouse">
|
||||
<TextBlock IsTextSelectionEnabled="False">
|
||||
<TextBlock IsTextSelectionEnabled="False"
|
||||
TextWrapping="Wrap">
|
||||
<Run x:Uid="NewTabRun" /> <LineBreak />
|
||||
<Run x:Uid="NewPaneRun"
|
||||
FontStyle="Italic" /> <LineBreak />
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
@@ -407,13 +408,6 @@
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<!--
|
||||
By default, the PRI file will contain resource paths beginning with the
|
||||
project name. Since we enabled XBF embedding, this *also* includes App.xbf.
|
||||
|
||||
@@ -1531,6 +1531,20 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
hostingTab.ColorPickerRequested([weakTab, weakThis]() {
|
||||
auto page{ weakThis.get() };
|
||||
auto tab{ weakTab.get() };
|
||||
if (page && tab)
|
||||
{
|
||||
if (!page->_tabColorPicker)
|
||||
{
|
||||
page->_tabColorPicker = winrt::make<ColorPickupFlyout>();
|
||||
}
|
||||
|
||||
tab->AttachColorPicker(page->_tabColorPicker);
|
||||
}
|
||||
});
|
||||
|
||||
// Add an event handler for when the terminal or tab wants to set a
|
||||
// progress indicator on the taskbar
|
||||
hostingTab.TaskbarProgressChanged({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
|
||||
@@ -3270,7 +3284,11 @@ namespace winrt::TerminalApp::implementation
|
||||
// elevated version of the Terminal with that profile... that's a
|
||||
// recipe for disaster. We won't ever open up a tab in this window.
|
||||
newTerminalArgs.Elevate(false);
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, connection));
|
||||
const auto newPane = _MakePane(newTerminalArgs, false, connection);
|
||||
newPane->WalkTree([](auto pane) {
|
||||
pane->FinalizeConfigurationGivenDefault();
|
||||
});
|
||||
_CreateNewTabFromPane(newPane);
|
||||
|
||||
// Request a summon of this window to the foreground
|
||||
_SummonWindowRequestedHandlers(*this, nullptr);
|
||||
|
||||
@@ -171,6 +171,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TerminalApp::TabRowControl _tabRow{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Grid _tabContent{ nullptr };
|
||||
Microsoft::UI::Xaml::Controls::SplitButton _newTabButton{ nullptr };
|
||||
winrt::TerminalApp::ColorPickupFlyout _tabColorPicker{ nullptr };
|
||||
|
||||
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
|
||||
|
||||
|
||||
@@ -648,6 +648,46 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attaches the given color picker to ourselves
|
||||
// - Typically will be called after we have sent a request for the color picker
|
||||
// Arguments:
|
||||
// - colorPicker: The color picker that we should attach to ourselves
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::AttachColorPicker(TerminalApp::ColorPickupFlyout& colorPicker)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
_tabColorPickup = colorPicker;
|
||||
|
||||
_colorSelectedToken = _tabColorPickup.ColorSelected([weakThis](auto newTabColor) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->SetRuntimeTabColor(newTabColor);
|
||||
}
|
||||
});
|
||||
|
||||
_colorClearedToken = _tabColorPickup.ColorCleared([weakThis]() {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->ResetRuntimeTabColor();
|
||||
}
|
||||
});
|
||||
|
||||
_pickerClosedToken = _tabColorPickup.Closed([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_tabColorPickup.ColorSelected(tab->_colorSelectedToken);
|
||||
tab->_tabColorPickup.ColorCleared(tab->_colorClearedToken);
|
||||
tab->_tabColorPickup.Closed(tab->_pickerClosedToken);
|
||||
tab->_tabColorPickup = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
_tabColorPickup.ShowAt(TabViewItem());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Find the currently active pane, and then switch the split direction of
|
||||
// its parent. E.g. switch from Horizontal to Vertical.
|
||||
@@ -1184,27 +1224,12 @@ namespace winrt::TerminalApp::implementation
|
||||
chooseColorMenuItem.Click([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->ActivateColorPicker();
|
||||
tab->RequestColorPicker();
|
||||
}
|
||||
});
|
||||
chooseColorMenuItem.Text(RS_(L"TabColorChoose"));
|
||||
chooseColorMenuItem.Icon(colorPickSymbol);
|
||||
|
||||
// Color Picker (it's convenient to have it here)
|
||||
_tabColorPickup.ColorSelected([weakThis](auto newTabColor) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->SetRuntimeTabColor(newTabColor);
|
||||
}
|
||||
});
|
||||
|
||||
_tabColorPickup.ColorCleared([weakThis]() {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->ResetRuntimeTabColor();
|
||||
}
|
||||
});
|
||||
|
||||
Controls::MenuFlyoutItem renameTabMenuItem;
|
||||
{
|
||||
// "Rename Tab"
|
||||
@@ -1452,18 +1477,16 @@ namespace winrt::TerminalApp::implementation
|
||||
subtleFillColorTertiaryBrush.Color(subtleFillColorTertiary);
|
||||
}
|
||||
|
||||
hoverTabBrush.Color(TerminalApp::ColorHelper::GetAccentColor(color));
|
||||
selectedTabBrush.Color(color);
|
||||
|
||||
// currently if a tab has a custom color, a deselected state is
|
||||
// signified by using the same color with a bit of transparency
|
||||
auto deselectedTabColor = color;
|
||||
deselectedTabColor.A = 64;
|
||||
deselectedTabBrush.Color(deselectedTabColor);
|
||||
deselectedTabBrush.Color(color);
|
||||
deselectedTabBrush.Opacity(0.3);
|
||||
|
||||
hoverTabBrush.Color(color);
|
||||
hoverTabBrush.Opacity(0.6);
|
||||
|
||||
// currently if a tab has a custom color, a deselected state is
|
||||
// signified by using the same color with a bit of transparency
|
||||
//
|
||||
// Prior to MUX 2.7, we set TabViewItemHeaderBackground, but now we can
|
||||
// use TabViewItem().Background() for that. HOWEVER,
|
||||
// TabViewItem().Background() only sets the color of the tab background
|
||||
@@ -1568,14 +1591,15 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Display the tab color picker at the location of the TabViewItem for this tab.
|
||||
// - Send an event to request for the color picker
|
||||
// - The listener should attach the color picker via AttachColorPicker()
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalTab::ActivateColorPicker()
|
||||
void TerminalTab::RequestColorPicker()
|
||||
{
|
||||
_tabColorPickup.ShowAt(TabViewItem());
|
||||
_ColorPickerRequestedHandlers();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace winrt::TerminalApp::implementation
|
||||
std::shared_ptr<Pane> DetachPane();
|
||||
void AttachPane(std::shared_ptr<Pane> pane);
|
||||
|
||||
void AttachColorPicker(winrt::TerminalApp::ColorPickupFlyout& colorPicker);
|
||||
|
||||
void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
|
||||
const float splitSize,
|
||||
std::shared_ptr<Pane> newPane);
|
||||
@@ -73,7 +75,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void SetRuntimeTabColor(const winrt::Windows::UI::Color& color);
|
||||
void ResetRuntimeTabColor();
|
||||
void ActivateColorPicker();
|
||||
void RequestColorPicker();
|
||||
|
||||
void UpdateZoom(std::shared_ptr<Pane> newFocus);
|
||||
void ToggleZoom();
|
||||
@@ -104,6 +106,7 @@ namespace winrt::TerminalApp::implementation
|
||||
WINRT_CALLBACK(SplitTabRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(FindRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(ExportTabRequested, winrt::delegate<>);
|
||||
WINRT_CALLBACK(ColorPickerRequested, winrt::delegate<>);
|
||||
TYPED_EVENT(TaskbarProgressChanged, IInspectable, IInspectable);
|
||||
|
||||
private:
|
||||
@@ -112,12 +115,16 @@ namespace winrt::TerminalApp::implementation
|
||||
std::shared_ptr<Pane> _zoomedPane{ nullptr };
|
||||
|
||||
winrt::hstring _lastIconPath{};
|
||||
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{};
|
||||
std::optional<winrt::Windows::UI::Color> _themeTabColor{};
|
||||
std::optional<winrt::Windows::UI::Color> _runtimeTabColor{};
|
||||
winrt::TerminalApp::TabHeaderControl _headerControl{};
|
||||
winrt::TerminalApp::TerminalTabStatus _tabStatus{};
|
||||
|
||||
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{ nullptr };
|
||||
winrt::event_token _colorSelectedToken;
|
||||
winrt::event_token _colorClearedToken;
|
||||
winrt::event_token _pickerClosedToken;
|
||||
|
||||
struct ControlEventTokens
|
||||
{
|
||||
winrt::event_token titleToken;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
@@ -92,14 +93,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
|
||||
@@ -53,7 +53,12 @@ CATCH_RETURN()
|
||||
HRESULT CTerminalHandoff::s_StopListening()
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
return s_StopListeningLocked();
|
||||
}
|
||||
|
||||
// See s_StopListening()
|
||||
HRESULT CTerminalHandoff::s_StopListeningLocked()
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
|
||||
_pfnHandoff = nullptr;
|
||||
@@ -101,14 +106,16 @@ HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE sign
|
||||
{
|
||||
try
|
||||
{
|
||||
// Stash a local copy of _pfnHandoff before we stop listening.
|
||||
std::unique_lock lock{ _mtx };
|
||||
|
||||
// s_StopListeningLocked sets _pfnHandoff to nullptr.
|
||||
// localPfnHandoff is tested for nullness below.
|
||||
#pragma warning(suppress : 26429) // Symbol '...' is never tested for nullness, it can be marked as not_null (f.23).
|
||||
auto localPfnHandoff = _pfnHandoff;
|
||||
|
||||
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
|
||||
// COM does not automatically clean that up for us. We must do it.
|
||||
s_StopListening();
|
||||
|
||||
std::unique_lock lock{ _mtx };
|
||||
LOG_IF_FAILED(s_StopListeningLocked());
|
||||
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
THROW_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
|
||||
|
||||
@@ -43,6 +43,9 @@ struct __declspec(uuid(__CLSID_CTerminalHandoff))
|
||||
|
||||
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff);
|
||||
static HRESULT s_StopListening();
|
||||
|
||||
private:
|
||||
static HRESULT s_StopListeningLocked();
|
||||
};
|
||||
|
||||
// Disable warnings from the CoCreatableClass macro as the value it provides for
|
||||
|
||||
@@ -195,11 +195,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
});
|
||||
|
||||
_updatePatternLocations = std::make_shared<ThrottledFuncTrailing<>>(
|
||||
_dispatcher,
|
||||
// NOTE: Calling UpdatePatternLocations from a background
|
||||
// thread is a workaround for us to hit GH#12607 less often.
|
||||
_updatePatternLocations = std::make_unique<til::throttled_func_trailing<>>(
|
||||
UpdatePatternLocationsInterval,
|
||||
[weakThis = get_weak()]() {
|
||||
if (auto core{ weakThis.get() }; !core->_IsClosing())
|
||||
if (auto core{ weakThis.get() })
|
||||
{
|
||||
core->UpdatePatternLocations();
|
||||
}
|
||||
@@ -479,7 +480,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// itself - it was initiated by the mouse wheel, or the scrollbar.
|
||||
_terminal->UserScrollViewport(viewTop);
|
||||
|
||||
_updatePatternLocations->Run();
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
|
||||
void ControlCore::AdjustOpacity(const double adjustment)
|
||||
@@ -1094,6 +1095,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
if (_terminal->IsSelectionActive())
|
||||
{
|
||||
_terminal->SwitchSelectionEndpoint();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1280,7 +1282,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
// Additionally, start the throttled update of where our links are.
|
||||
_updatePatternLocations->Run();
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
|
||||
void ControlCore::_terminalCursorPositionChanged()
|
||||
@@ -1341,7 +1343,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
if (!_midiAudio)
|
||||
{
|
||||
_midiAudio = std::make_unique<MidiAudio>();
|
||||
const auto windowHandle = reinterpret_cast<HWND>(_owningHwnd);
|
||||
_midiAudio = std::make_unique<MidiAudio>(windowHandle);
|
||||
_midiAudio->Initialize();
|
||||
}
|
||||
return *_midiAudio;
|
||||
@@ -1673,7 +1676,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_terminal->Write(hstr);
|
||||
|
||||
// Start the throttled update of where our hyperlinks are.
|
||||
_updatePatternLocations->Run();
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -1911,13 +1914,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - This is related to work done for GH#2988.
|
||||
void ControlCore::GotFocus()
|
||||
{
|
||||
_terminal->FocusChanged(true);
|
||||
_focusChanged(true);
|
||||
}
|
||||
|
||||
// See GotFocus.
|
||||
void ControlCore::LostFocus()
|
||||
{
|
||||
_terminal->FocusChanged(false);
|
||||
_focusChanged(false);
|
||||
}
|
||||
|
||||
void ControlCore::_focusChanged(bool focused)
|
||||
{
|
||||
// GH#13461 - temporarily turn off read-only mode, send the focus event,
|
||||
// then turn it back on. Even in focus mode, focus events are fine to
|
||||
// send. We don't want to pop a warning every time the control is
|
||||
// focused.
|
||||
const auto previous = std::exchange(_isReadOnly, false);
|
||||
const auto restore = wil::scope_exit([&]() { _isReadOnly = previous; });
|
||||
_terminal->FocusChanged(focused);
|
||||
}
|
||||
|
||||
bool ControlCore::_isBackgroundTransparent()
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
winrt::Windows::System::DispatcherQueue _dispatcher{ nullptr };
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
|
||||
std::unique_ptr<til::throttled_func_trailing<>> _updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
|
||||
|
||||
winrt::fire_and_forget _asyncCloseConnection();
|
||||
@@ -311,6 +311,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _setOpacity(const double opacity);
|
||||
|
||||
bool _isBackgroundTransparent();
|
||||
void _focusChanged(bool focused);
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "TSFInputControl.h"
|
||||
#include "TSFInputControl.g.cpp"
|
||||
|
||||
#include <Utils.h>
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Graphics::Display;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
@@ -16,17 +14,7 @@ using namespace winrt::Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
TSFInputControl::TSFInputControl() :
|
||||
_editContext{ nullptr },
|
||||
_inComposition{ false },
|
||||
_activeTextStart{ 0 },
|
||||
_focused{ false },
|
||||
_currentTerminalCursorPos{ 0, 0 },
|
||||
_currentCanvasWidth{ 0.0 },
|
||||
_currentTextBlockHeight{ 0.0 },
|
||||
_currentTextBounds{ 0, 0, 0, 0 },
|
||||
_currentControlBounds{ 0, 0, 0, 0 },
|
||||
_currentWindowBounds{ 0, 0, 0, 0 }
|
||||
TSFInputControl::TSFInputControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
@@ -83,11 +71,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TSFInputControl::NotifyFocusEnter()
|
||||
{
|
||||
if (_editContext != nullptr)
|
||||
{
|
||||
_editContext.NotifyFocusEnter();
|
||||
_focused = true;
|
||||
}
|
||||
_editContext.NotifyFocusEnter();
|
||||
_focused = true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -99,11 +84,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TSFInputControl::NotifyFocusLeave()
|
||||
{
|
||||
if (_editContext != nullptr)
|
||||
{
|
||||
_editContext.NotifyFocusLeave();
|
||||
_focused = false;
|
||||
}
|
||||
_editContext.NotifyFocusLeave();
|
||||
_focused = false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -117,14 +99,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
if (!_inputBuffer.empty())
|
||||
{
|
||||
TextBlock().Text(L"");
|
||||
const auto bufLen = ::base::ClampedNumeric<int32_t>(_inputBuffer.length());
|
||||
_inputBuffer.clear();
|
||||
_editContext.NotifyFocusLeave();
|
||||
_editContext.NotifyTextChanged({ 0, bufLen }, 0, { 0, 0 });
|
||||
_editContext.NotifyFocusEnter();
|
||||
_selection = {};
|
||||
_activeTextStart = 0;
|
||||
_inComposition = false;
|
||||
_editContext.NotifyTextChanged({ 0, INT32_MAX }, 0, _selection);
|
||||
TextBlock().Text({});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,12 +282,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TSFInputControl::_compositionCompletedHandler(CoreTextEditContext sender, const CoreTextCompositionCompletedEventArgs& /*args*/)
|
||||
{
|
||||
_inComposition = false;
|
||||
|
||||
// only need to do work if the current buffer has text
|
||||
if (!_inputBuffer.empty())
|
||||
{
|
||||
_SendAndClearText();
|
||||
}
|
||||
_SendAndClearText();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -336,16 +310,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TSFInputControl::_textRequestedHandler(CoreTextEditContext sender, const CoreTextTextRequestedEventArgs& args)
|
||||
{
|
||||
// the range the TSF wants to know about
|
||||
const auto range = args.Request().Range();
|
||||
|
||||
try
|
||||
{
|
||||
const auto textEnd = ::base::ClampMin<size_t>(range.EndCaretPosition, _inputBuffer.length());
|
||||
const auto length = ::base::ClampSub<size_t>(textEnd, range.StartCaretPosition);
|
||||
const auto textRequested = _inputBuffer.substr(range.StartCaretPosition, length);
|
||||
|
||||
args.Request().Text(textRequested);
|
||||
const auto range = args.Request().Range();
|
||||
const auto text = _inputBuffer.substr(
|
||||
range.StartCaretPosition,
|
||||
range.EndCaretPosition - range.StartCaretPosition);
|
||||
args.Request().Text(text);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -360,8 +331,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - args: CoreTextSelectionRequestedEventArgs for providing data for the SelectionRequested event. Not used in method.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TSFInputControl::_selectionRequestedHandler(CoreTextEditContext sender, const CoreTextSelectionRequestedEventArgs& /*args*/)
|
||||
void TSFInputControl::_selectionRequestedHandler(CoreTextEditContext sender, const CoreTextSelectionRequestedEventArgs& args)
|
||||
{
|
||||
args.Request().Selection(_selection);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -374,8 +346,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - args: CoreTextSelectionUpdatingEventArgs for providing data for the SelectionUpdating event. Not used in method.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TSFInputControl::_selectionUpdatingHandler(CoreTextEditContext sender, const CoreTextSelectionUpdatingEventArgs& /*args*/)
|
||||
void TSFInputControl::_selectionUpdatingHandler(CoreTextEditContext sender, const CoreTextSelectionUpdatingEventArgs& args)
|
||||
{
|
||||
_selection = args.Selection();
|
||||
args.Result(CoreTextSelectionUpdatingResult::Succeeded);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -388,24 +362,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TSFInputControl::_textUpdatingHandler(CoreTextEditContext sender, const CoreTextTextUpdatingEventArgs& args)
|
||||
{
|
||||
const auto incomingText = args.Text();
|
||||
const auto range = args.Range();
|
||||
|
||||
try
|
||||
{
|
||||
// When a user deletes the last character in their current composition, some machines
|
||||
// will fire a CompositionCompleted before firing a TextUpdating event that deletes the last character.
|
||||
// The TextUpdating will have a lower StartCaretPosition, so in this scenario, _activeTextStart
|
||||
// needs to update to be the StartCaretPosition.
|
||||
// A known issue related to this behavior is that the last character that's deleted from a composition
|
||||
// will get sent to the terminal before we receive the TextUpdate to delete the character.
|
||||
// See GH #5054.
|
||||
_activeTextStart = ::base::ClampMin(_activeTextStart, ::base::ClampedNumeric<size_t>(range.StartCaretPosition));
|
||||
const auto incomingText = args.Text();
|
||||
const auto range = args.Range();
|
||||
|
||||
_inputBuffer = _inputBuffer.replace(
|
||||
range.StartCaretPosition,
|
||||
::base::ClampSub<size_t>(range.EndCaretPosition, range.StartCaretPosition),
|
||||
range.EndCaretPosition - range.StartCaretPosition,
|
||||
incomingText);
|
||||
_selection = args.NewSelection();
|
||||
// GH#5054: Pressing backspace might move the caret before the _activeTextStart.
|
||||
_activeTextStart = std::min(_activeTextStart, _inputBuffer.size());
|
||||
|
||||
// Emojis/Kaomojis/Symbols chosen through the IME without starting composition
|
||||
// will be sent straight through to the terminal.
|
||||
@@ -432,22 +400,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Send the portion of the textBuffer starting at _activeTextStart to the end of the buffer.
|
||||
// Then clear the TextBlock and hide it until the next time text is received.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TSFInputControl::_SendAndClearText()
|
||||
{
|
||||
const auto text = _inputBuffer.substr(_activeTextStart);
|
||||
if (text.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_CompositionCompletedHandlers(text);
|
||||
|
||||
_activeTextStart = _inputBuffer.length();
|
||||
_activeTextStart = _inputBuffer.size();
|
||||
|
||||
TextBlock().Text(L"");
|
||||
TextBlock().Text({});
|
||||
|
||||
// After we reset the TextBlock to empty string, we want to make sure
|
||||
// ActualHeight reflects the respective height. It seems that ActualHeight
|
||||
|
||||
@@ -58,6 +58,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _textUpdatingHandler(winrt::Windows::UI::Text::Core::CoreTextEditContext sender, const winrt::Windows::UI::Text::Core::CoreTextTextUpdatingEventArgs& args);
|
||||
void _formatUpdatingHandler(winrt::Windows::UI::Text::Core::CoreTextEditContext sender, const winrt::Windows::UI::Text::Core::CoreTextFormatUpdatingEventArgs& args);
|
||||
|
||||
void _SendAndClearText();
|
||||
void _RedrawCanvas();
|
||||
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::TextRequested_revoker _textRequestedRevoker;
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::SelectionRequested_revoker _selectionRequestedRevoker;
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::FocusRemoved_revoker _focusRemovedRevoker;
|
||||
@@ -68,22 +71,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::CompositionStarted_revoker _compositionStartedRevoker;
|
||||
winrt::Windows::UI::Text::Core::CoreTextEditContext::CompositionCompleted_revoker _compositionCompletedRevoker;
|
||||
|
||||
Windows::UI::Text::Core::CoreTextEditContext _editContext;
|
||||
|
||||
Windows::UI::Text::Core::CoreTextEditContext _editContext{ nullptr };
|
||||
std::wstring _inputBuffer;
|
||||
winrt::Windows::UI::Text::Core::CoreTextRange _selection{};
|
||||
size_t _activeTextStart = 0;
|
||||
bool _inComposition = false;
|
||||
bool _focused = false;
|
||||
|
||||
bool _inComposition;
|
||||
size_t _activeTextStart;
|
||||
void _SendAndClearText();
|
||||
void _RedrawCanvas();
|
||||
bool _focused;
|
||||
|
||||
til::point _currentTerminalCursorPos;
|
||||
double _currentCanvasWidth;
|
||||
double _currentTextBlockHeight;
|
||||
winrt::Windows::Foundation::Rect _currentControlBounds;
|
||||
winrt::Windows::Foundation::Rect _currentTextBounds;
|
||||
winrt::Windows::Foundation::Rect _currentWindowBounds;
|
||||
til::point _currentTerminalCursorPos{};
|
||||
double _currentCanvasWidth = 0.0;
|
||||
double _currentTextBlockHeight = 0.0;
|
||||
winrt::Windows::Foundation::Rect _currentControlBounds{};
|
||||
winrt::Windows::Foundation::Rect _currentTextBounds{};
|
||||
winrt::Windows::Foundation::Rect _currentWindowBounds{};
|
||||
};
|
||||
}
|
||||
namespace winrt::Microsoft::Terminal::Control::factory_implementation
|
||||
|
||||
@@ -432,12 +432,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// achieve the intended effect.
|
||||
ScrollBar().IndicatorMode(Controls::Primitives::ScrollingIndicatorMode::None);
|
||||
ScrollBar().Visibility(Visibility::Collapsed);
|
||||
ScrollMarksGrid().Visibility(Visibility::Collapsed);
|
||||
}
|
||||
else // (default or Visible)
|
||||
{
|
||||
// Default behavior
|
||||
ScrollBar().IndicatorMode(Controls::Primitives::ScrollingIndicatorMode::MouseIndicator);
|
||||
ScrollBar().Visibility(Visibility::Visible);
|
||||
ScrollMarksGrid().Visibility(Visibility::Visible);
|
||||
}
|
||||
|
||||
_interactivity.UpdateSettings();
|
||||
@@ -902,6 +904,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
// GH#11479: TSF wants to be notified of any character input via ICoreTextEditContext::NotifyTextChanged().
|
||||
// TSF is built and tested around the idea that you inform it of any text changes that happen
|
||||
// when it doesn't currently compose characters. For instance writing "xin chaof" with the
|
||||
// Vietnamese IME should produce "xin chào". After writing "xin" it'll emit a composition
|
||||
// completion event and we'll write "xin" to the shell. It now has no input focus and won't know
|
||||
// about the whitespace. If you then write "chaof", it'll emit another composition completion
|
||||
// event for "xinchaof" and the resulting output in the shell will finally read "xinxinchaof".
|
||||
// A composition completion event technically doesn't mean that the completed text is now
|
||||
// immutable after all. We could (and probably should) inform TSF of any input changes,
|
||||
// but we technically aren't a text input field. The immediate solution was
|
||||
// to simply force TSF to clear its text whenever we have input focus.
|
||||
TSFInputControl().ClearBuffer();
|
||||
|
||||
_HidePointerCursorHandlers(*this, nullptr);
|
||||
|
||||
const auto ch = e.Character();
|
||||
@@ -1163,12 +1178,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
const auto window = CoreWindow::GetForCurrentThread();
|
||||
|
||||
if (vkey == VK_ESCAPE ||
|
||||
vkey == VK_RETURN)
|
||||
{
|
||||
TSFInputControl().ClearBuffer();
|
||||
}
|
||||
|
||||
// If the terminal translated the key, mark the event as handled.
|
||||
// This will prevent the system from trying to get the character out
|
||||
// of it and sending us a CharacterReceived event.
|
||||
|
||||
@@ -147,10 +147,6 @@
|
||||
<PRIResource Include="Resources\en-US\Resources.resw" />
|
||||
<OCResourceDirectory Include="Resources" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(WindowsTerminalBranding)'=='' or '$(WindowsTerminalBranding)'=='Dev' or '$(WindowsTerminalBranding)'=='Preview'">
|
||||
<!-- GH#13252 Only vend this dependency for Dev and Preview builds. -->
|
||||
<SDKReference Include="Microsoft.Midi.GmDls, Version=10.0.22000.0" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\types\lib\types.vcxproj" />
|
||||
|
||||
@@ -424,6 +424,7 @@ private:
|
||||
std::pair<til::point, til::point> _PivotSelection(const til::point targetPos, bool& targetStart) const;
|
||||
std::pair<til::point, til::point> _ExpandSelectionAnchors(std::pair<til::point, til::point> anchors) const;
|
||||
til::point _ConvertToBufferCell(const til::point viewportPos) const;
|
||||
void _ScrollToPoint(const til::point pos);
|
||||
void _MoveByChar(SelectionDirection direction, til::point& pos);
|
||||
void _MoveByWord(SelectionDirection direction, til::point& pos);
|
||||
void _MoveByViewport(SelectionDirection direction, til::point& pos);
|
||||
|
||||
@@ -303,6 +303,7 @@ void Terminal::ToggleMarkMode()
|
||||
_selection->start = cursorPos;
|
||||
_selection->end = cursorPos;
|
||||
_selection->pivot = cursorPos;
|
||||
_ScrollToPoint(cursorPos);
|
||||
_selectionMode = SelectionInteractionMode::Mark;
|
||||
_blockSelection = false;
|
||||
WI_SetAllFlags(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End);
|
||||
@@ -459,22 +460,7 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion
|
||||
}
|
||||
|
||||
// 4. Scroll (if necessary)
|
||||
if (const auto visibleViewport = _GetVisibleViewport(); !visibleViewport.IsInBounds(targetPos))
|
||||
{
|
||||
if (const auto amtAboveView = visibleViewport.Top() - targetPos.Y; amtAboveView > 0)
|
||||
{
|
||||
// anchor is above visible viewport, scroll by that amount
|
||||
_scrollOffset += amtAboveView;
|
||||
}
|
||||
else
|
||||
{
|
||||
// anchor is below visible viewport, scroll by that amount
|
||||
const auto amtBelowView = targetPos.Y - visibleViewport.BottomInclusive();
|
||||
_scrollOffset -= amtBelowView;
|
||||
}
|
||||
_NotifyScrollEvent();
|
||||
_activeBuffer().TriggerScroll();
|
||||
}
|
||||
_ScrollToPoint(targetPos);
|
||||
}
|
||||
|
||||
void Terminal::SelectAll()
|
||||
@@ -485,6 +471,7 @@ void Terminal::SelectAll()
|
||||
_selection->end = { bufferSize.RightInclusive(), _GetMutableViewport().BottomInclusive() };
|
||||
_selection->pivot = _selection->end;
|
||||
_selectionMode = SelectionInteractionMode::Keyboard;
|
||||
_ScrollToPoint(_selection->start);
|
||||
}
|
||||
|
||||
void Terminal::_MoveByChar(SelectionDirection direction, til::point& pos)
|
||||
@@ -685,3 +672,27 @@ void Terminal::ColorSelection(const til::point, const til::point, const TextAttr
|
||||
{
|
||||
THROW_HR(E_NOTIMPL);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - if necessary, scroll the viewport such that the given point is visible
|
||||
// Arguments:
|
||||
// - pos: a coordinate relative to the buffer (not viewport)
|
||||
void Terminal::_ScrollToPoint(const til::point pos)
|
||||
{
|
||||
if (const auto visibleViewport = _GetVisibleViewport(); !visibleViewport.IsInBounds(pos))
|
||||
{
|
||||
if (const auto amtAboveView = visibleViewport.Top() - pos.Y; amtAboveView > 0)
|
||||
{
|
||||
// anchor is above visible viewport, scroll by that amount
|
||||
_scrollOffset += amtAboveView;
|
||||
}
|
||||
else
|
||||
{
|
||||
// anchor is below visible viewport, scroll by that amount
|
||||
const auto amtBelowView = pos.Y - visibleViewport.BottomInclusive();
|
||||
_scrollOffset -= amtBelowView;
|
||||
}
|
||||
_NotifyScrollEvent();
|
||||
_activeBuffer().TriggerScroll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,22 +36,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
static constexpr std::wstring_view SelectionBackgroundColorTag{ L"SelectionBackground" };
|
||||
|
||||
static const std::array<hstring, 16> TableColorNames = {
|
||||
RS_(L"ColorScheme_Black/Header"),
|
||||
RS_(L"ColorScheme_Red/Header"),
|
||||
RS_(L"ColorScheme_Green/Header"),
|
||||
RS_(L"ColorScheme_Yellow/Header"),
|
||||
RS_(L"ColorScheme_Blue/Header"),
|
||||
RS_(L"ColorScheme_Purple/Header"),
|
||||
RS_(L"ColorScheme_Cyan/Header"),
|
||||
RS_(L"ColorScheme_White/Header"),
|
||||
RS_(L"ColorScheme_BrightBlack/Header"),
|
||||
RS_(L"ColorScheme_BrightRed/Header"),
|
||||
RS_(L"ColorScheme_BrightGreen/Header"),
|
||||
RS_(L"ColorScheme_BrightYellow/Header"),
|
||||
RS_(L"ColorScheme_BrightBlue/Header"),
|
||||
RS_(L"ColorScheme_BrightPurple/Header"),
|
||||
RS_(L"ColorScheme_BrightCyan/Header"),
|
||||
RS_(L"ColorScheme_BrightWhite/Header")
|
||||
RS_(L"ColorScheme_Black/Text"),
|
||||
RS_(L"ColorScheme_Red/Text"),
|
||||
RS_(L"ColorScheme_Green/Text"),
|
||||
RS_(L"ColorScheme_Yellow/Text"),
|
||||
RS_(L"ColorScheme_Blue/Text"),
|
||||
RS_(L"ColorScheme_Purple/Text"),
|
||||
RS_(L"ColorScheme_Cyan/Text"),
|
||||
RS_(L"ColorScheme_White/Text"),
|
||||
RS_(L"ColorScheme_BrightBlack/Text"),
|
||||
RS_(L"ColorScheme_BrightRed/Text"),
|
||||
RS_(L"ColorScheme_BrightGreen/Text"),
|
||||
RS_(L"ColorScheme_BrightYellow/Text"),
|
||||
RS_(L"ColorScheme_BrightBlue/Text"),
|
||||
RS_(L"ColorScheme_BrightPurple/Text"),
|
||||
RS_(L"ColorScheme_BrightCyan/Text"),
|
||||
RS_(L"ColorScheme_BrightWhite/Text")
|
||||
};
|
||||
|
||||
static const std::array<std::wstring, 9> InBoxSchemes = {
|
||||
@@ -187,7 +187,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (std::find(std::begin(InBoxSchemes), std::end(InBoxSchemes), schemeName) != std::end(InBoxSchemes))
|
||||
{
|
||||
// load disclaimer for in-box profiles
|
||||
disclaimer = RS_(L"ColorScheme_DeleteButtonDisclaimerInBox");
|
||||
disclaimer = RS_(L"ColorScheme_DeleteButtonDisclaimerInBox/Text");
|
||||
}
|
||||
DeleteButtonDisclaimer().Text(disclaimer);
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
@@ -353,12 +354,5 @@
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
</Project>
|
||||
|
||||
@@ -139,43 +139,43 @@
|
||||
<value>Background</value>
|
||||
<comment>This is the header for a control that lets the user select the background color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_Black.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_Black.Text" xml:space="preserve">
|
||||
<value>Black</value>
|
||||
<comment>This is the header for a control that lets the user select the black color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_Blue.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_Blue.Text" xml:space="preserve">
|
||||
<value>Blue</value>
|
||||
<comment>This is the header for a control that lets the user select the blue color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_BrightBlack.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_BrightBlack.Text" xml:space="preserve">
|
||||
<value>Bright black</value>
|
||||
<comment>This is the header for a control that lets the user select the bright black color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_BrightBlue.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_BrightBlue.Text" xml:space="preserve">
|
||||
<value>Bright blue</value>
|
||||
<comment>This is the header for a control that lets the user select the bright blue color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_BrightCyan.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_BrightCyan.Text" xml:space="preserve">
|
||||
<value>Bright cyan</value>
|
||||
<comment>This is the header for a control that lets the user select the bright cyan color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_BrightGreen.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_BrightGreen.Text" xml:space="preserve">
|
||||
<value>Bright green</value>
|
||||
<comment>This is the header for a control that lets the user select the bright green color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_BrightPurple.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_BrightPurple.Text" xml:space="preserve">
|
||||
<value>Bright purple</value>
|
||||
<comment>This is the header for a control that lets the user select the bright purple color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_BrightRed.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_BrightRed.Text" xml:space="preserve">
|
||||
<value>Bright red</value>
|
||||
<comment>This is the header for a control that lets the user select the bright red color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_BrightWhite.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_BrightWhite.Text" xml:space="preserve">
|
||||
<value>Bright white</value>
|
||||
<comment>This is the header for a control that lets the user select the bright white color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_BrightYellow.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_BrightYellow.Text" xml:space="preserve">
|
||||
<value>Bright yellow</value>
|
||||
<comment>This is the header for a control that lets the user select the bright yellow color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
@@ -183,7 +183,7 @@
|
||||
<value>Cursor color</value>
|
||||
<comment>This is the header for a control that lets the user select the text cursor's color displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_Cyan.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_Cyan.Text" xml:space="preserve">
|
||||
<value>Cyan</value>
|
||||
<comment>This is the header for a control that lets the user select the cyan color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
@@ -191,11 +191,11 @@
|
||||
<value>Foreground</value>
|
||||
<comment>This is the header for a control that lets the user select the foreground color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_Green.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_Green.Text" xml:space="preserve">
|
||||
<value>Green</value>
|
||||
<comment>This is the header for a control that lets the user select the green color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_Purple.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_Purple.Text" xml:space="preserve">
|
||||
<value>Purple</value>
|
||||
<comment>This is the header for a control that lets the user select the purple color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
@@ -203,15 +203,15 @@
|
||||
<value>Selection background</value>
|
||||
<comment>This is the header for a control that lets the user select the background color for selected text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_Red.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_Red.Text" xml:space="preserve">
|
||||
<value>Red</value>
|
||||
<comment>This is the header for a control that lets the user select the red color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_White.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_White.Text" xml:space="preserve">
|
||||
<value>White</value>
|
||||
<comment>This is the header for a control that lets the user select the white color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_Yellow.Header" xml:space="preserve">
|
||||
<data name="ColorScheme_Yellow.Text" xml:space="preserve">
|
||||
<value>Yellow</value>
|
||||
<comment>This is the header for a control that lets the user select the yellow color for text displayed on the screen.</comment>
|
||||
</data>
|
||||
@@ -699,6 +699,10 @@
|
||||
<value>Never close automatically</value>
|
||||
<comment>An option to choose from for the "profile termination behavior" (or "close on exit") setting. When selected, the terminal never closes, even if the process exits in a controlled or uncontrolled scenario. The user would have to manually close the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_CloseOnExitAutomatic.Content" xml:space="preserve">
|
||||
<value>Automatic</value>
|
||||
<comment>An option to choose from for the "profile termination behavior" (or "close on exit") setting. When selected, the terminal closes if the process exits in a controlled scenario successfully and the process was launched by Windows Terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_ColorScheme.Header" xml:space="preserve">
|
||||
<value>Color scheme</value>
|
||||
<comment>Header for a control to select the scheme (or set) of colors used in the session. This is selected from a list of options managed by the user.</comment>
|
||||
@@ -1194,7 +1198,7 @@
|
||||
<value>Rename</value>
|
||||
<comment>Text label for a button that can be used to begin the renaming process.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_DeleteButtonDisclaimerInBox" xml:space="preserve">
|
||||
<data name="ColorScheme_DeleteButtonDisclaimerInBox.Text" xml:space="preserve">
|
||||
<value>This color scheme cannot be deleted or renamed because it is included by default.</value>
|
||||
<comment>Disclaimer presented next to the delete button when it is disabled.</comment>
|
||||
</data>
|
||||
|
||||
@@ -72,7 +72,7 @@ Author(s):
|
||||
X(bool, SuppressApplicationTitle, "suppressApplicationTitle", false) \
|
||||
X(guid, ConnectionType, "connectionType") \
|
||||
X(hstring, Icon, "icon", L"\uE756") \
|
||||
X(CloseOnExitMode, CloseOnExit, "closeOnExit", CloseOnExitMode::Graceful) \
|
||||
X(CloseOnExitMode, CloseOnExit, "closeOnExit", CloseOnExitMode::Automatic) \
|
||||
X(hstring, TabTitle, "tabTitle") \
|
||||
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
|
||||
X(bool, UseAtlasEngine, "experimental.useAtlasEngine", false) \
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalVisualStudioSetup>true</TerminalVisualStudioSetup>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
@@ -274,13 +275,6 @@
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<!-- This target will take our defaults.json and stamp it into a .h file that
|
||||
we can include in the code directly. This way, we don't need to worry about
|
||||
failing to load the default settings at runtime. -->
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
{
|
||||
Never = 0,
|
||||
Graceful,
|
||||
Always
|
||||
Always,
|
||||
Automatic
|
||||
};
|
||||
|
||||
[flags]
|
||||
|
||||
@@ -108,10 +108,11 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Control::TextAntialiasingMode)
|
||||
// - Helper for converting a user-specified closeOnExit value to its corresponding enum
|
||||
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::CloseOnExitMode)
|
||||
{
|
||||
JSON_MAPPINGS(3) = {
|
||||
JSON_MAPPINGS(4) = {
|
||||
pair_type{ "always", ValueType::Always },
|
||||
pair_type{ "graceful", ValueType::Graceful },
|
||||
pair_type{ "never", ValueType::Never },
|
||||
pair_type{ "automatic", ValueType::Automatic },
|
||||
};
|
||||
|
||||
// Override mapping parser to add boolean parsing
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include "LegacyProfileGeneratorNamespaces.h"
|
||||
#include "../../inc/DefaultSettings.h"
|
||||
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include "DynamicProfileUtils.h"
|
||||
|
||||
static constexpr std::wstring_view WslHomeDirectory{ L"~" };
|
||||
@@ -68,105 +66,6 @@ static winrt::com_ptr<implementation::Profile> makeProfile(const std::wstring& d
|
||||
return WSLDistro;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Enumerates all the installed WSL distros to create profiles for them.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - a vector with all distros for all the installed WSL distros
|
||||
static void legacyGenerate(std::vector<winrt::com_ptr<implementation::Profile>>& profiles)
|
||||
{
|
||||
wil::unique_handle readPipe;
|
||||
wil::unique_handle writePipe;
|
||||
SECURITY_ATTRIBUTES sa{ sizeof(sa), nullptr, true };
|
||||
THROW_IF_WIN32_BOOL_FALSE(CreatePipe(&readPipe, &writePipe, &sa, 0));
|
||||
STARTUPINFO si{ 0 };
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.hStdOutput = writePipe.get();
|
||||
si.hStdError = writePipe.get();
|
||||
wil::unique_process_information pi;
|
||||
wil::unique_cotaskmem_string systemPath;
|
||||
THROW_IF_FAILED(wil::GetSystemDirectoryW(systemPath));
|
||||
std::wstring command(systemPath.get());
|
||||
command += L"\\wsl.exe --list";
|
||||
|
||||
THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(nullptr,
|
||||
const_cast<LPWSTR>(command.c_str()),
|
||||
nullptr,
|
||||
nullptr,
|
||||
TRUE,
|
||||
CREATE_NO_WINDOW,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&si,
|
||||
&pi));
|
||||
switch (WaitForSingleObject(pi.hProcess, 2000))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
break;
|
||||
case WAIT_ABANDONED:
|
||||
case WAIT_TIMEOUT:
|
||||
return;
|
||||
case WAIT_FAILED:
|
||||
THROW_LAST_ERROR();
|
||||
default:
|
||||
THROW_HR(ERROR_UNHANDLED_EXCEPTION);
|
||||
}
|
||||
DWORD exitCode;
|
||||
if (!GetExitCodeProcess(pi.hProcess, &exitCode))
|
||||
{
|
||||
THROW_HR(E_INVALIDARG);
|
||||
}
|
||||
else if (exitCode != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
DWORD bytesAvailable;
|
||||
THROW_IF_WIN32_BOOL_FALSE(PeekNamedPipe(readPipe.get(), nullptr, NULL, nullptr, &bytesAvailable, nullptr));
|
||||
// "The _open_osfhandle call transfers ownership of the Win32 file handle to the file descriptor."
|
||||
// (https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/open-osfhandle?view=vs-2019)
|
||||
// so, we detach_from_smart_pointer it -- but...
|
||||
// "File descriptors passed into _fdopen are owned by the returned FILE * stream.
|
||||
// If _fdopen is successful, do not call _close on the file descriptor.
|
||||
// Calling fclose on the returned FILE * also closes the file descriptor."
|
||||
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fdopen-wfdopen?view=vs-2019
|
||||
auto stdioPipeHandle = _wfdopen(_open_osfhandle((intptr_t)wil::detach_from_smart_pointer(readPipe), _O_WTEXT | _O_RDONLY), L"r");
|
||||
auto closeFile = wil::scope_exit([&]() { fclose(stdioPipeHandle); });
|
||||
|
||||
std::wfstream pipe{ stdioPipeHandle };
|
||||
|
||||
std::wstring wline;
|
||||
std::getline(pipe, wline); // remove the header from the output.
|
||||
while (pipe.tellp() < bytesAvailable)
|
||||
{
|
||||
std::getline(pipe, wline);
|
||||
std::wstringstream wlinestream(wline);
|
||||
if (wlinestream)
|
||||
{
|
||||
std::wstring distName;
|
||||
std::getline(wlinestream, distName, L'\r');
|
||||
|
||||
if (til::starts_with(distName, DockerDistributionPrefix))
|
||||
{
|
||||
// Docker for Windows creates some utility distributions to handle Docker commands.
|
||||
// Pursuant to GH#3556, because they are _not_ user-facing we want to hide them.
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto firstChar = distName.find_first_of(L"( ");
|
||||
// Some localizations don't have a space between the name and "(Default)"
|
||||
// https://github.com/microsoft/terminal/issues/1168#issuecomment-500187109
|
||||
if (firstChar < distName.size())
|
||||
{
|
||||
distName.resize(firstChar);
|
||||
}
|
||||
|
||||
profiles.emplace_back(makeProfile(distName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Create a list of Profiles for each distro listed in names.
|
||||
// - Skips distros that are utility distros for docker (see GH#3556)
|
||||
@@ -310,9 +209,9 @@ static bool getWslNames(const wil::unique_hkey& wslRootKey,
|
||||
// Method Description:
|
||||
// - Generate a list of profiles for each on the installed WSL distros. This
|
||||
// will first try to read the installed distros from the registry. If that
|
||||
// fails, we'll fall back to the legacy way of launching WSL.exe to read the
|
||||
// distros from the commandline. Reading the registry is slightly more stable
|
||||
// (see GH#7199, GH#9905), but it is certainly BODGY
|
||||
// fails, we'll assume there are no WSL distributions installed.
|
||||
// Reading the registry is slightly more stable (see GH#7199, GH#9905),
|
||||
// but it is certainly BODGY
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
@@ -333,6 +232,4 @@ void WslDistroGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
legacyGenerate(profiles);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"icon": "ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png",
|
||||
"colorScheme": "Campbell",
|
||||
"antialiasingMode": "grayscale",
|
||||
"closeOnExit": "graceful",
|
||||
"closeOnExit": "automatic",
|
||||
"cursorShape": "bar",
|
||||
"fontFace": "Cascadia Mono",
|
||||
"fontSize": 12,
|
||||
@@ -62,7 +62,7 @@
|
||||
"icon": "ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png",
|
||||
"colorScheme": "Campbell",
|
||||
"antialiasingMode": "grayscale",
|
||||
"closeOnExit": "graceful",
|
||||
"closeOnExit": "automatic",
|
||||
"cursorShape": "bar",
|
||||
"fontFace": "Cascadia Mono",
|
||||
"fontSize": 12,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
@@ -105,14 +106,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
|
||||
@@ -227,8 +227,13 @@ class TerminalCoreUnitTests::ConptyRoundtripTests final
|
||||
TEST_METHOD(SimpleAltBufferTest);
|
||||
TEST_METHOD(AltBufferToAltBufferTest);
|
||||
|
||||
TEST_METHOD(TestPowerLineFirstFrame);
|
||||
|
||||
TEST_METHOD(AltBufferResizeCrash);
|
||||
|
||||
TEST_METHOD(TestNoExtendedAttrsOptimization);
|
||||
TEST_METHOD(TestNoBackgroundAttrsOptimization);
|
||||
|
||||
private:
|
||||
bool _writeCallback(const char* const pch, const size_t cch);
|
||||
void _flushFirstFrame();
|
||||
@@ -4108,12 +4113,88 @@ void ConptyRoundtripTests::AltBufferToAltBufferTest()
|
||||
verifyBuffer(*termAltTb, term->_GetMutableViewport().ToExclusive(), Frame::StillInAltBuffer);
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::TestPowerLineFirstFrame()
|
||||
{
|
||||
Log::Comment(L"This is a test for GH#8341. If we received colored spaces "
|
||||
L"BEFORE the first frame, we should still emit them!");
|
||||
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& renderer = *g.pRender;
|
||||
auto& gci = g.getConsoleInformation();
|
||||
auto& si = gci.GetActiveOutputBuffer();
|
||||
auto& sm = si.GetStateMachine();
|
||||
|
||||
auto* hostTb = &si.GetTextBuffer();
|
||||
auto* termTb = term->_mainBuffer.get();
|
||||
|
||||
_checkConptyOutput = false;
|
||||
|
||||
TextAttribute whiteOnGreen{};
|
||||
whiteOnGreen.SetIndexedForeground(TextColor::DARK_WHITE);
|
||||
whiteOnGreen.SetIndexedBackground(TextColor::BRIGHT_GREEN);
|
||||
|
||||
TextAttribute greenOnBlack{};
|
||||
greenOnBlack.SetIndexedForeground(TextColor::BRIGHT_GREEN);
|
||||
greenOnBlack.SetIndexedBackground(TextColor::BRIGHT_BLACK);
|
||||
|
||||
TextAttribute whiteOnBlack{};
|
||||
whiteOnBlack.SetIndexedForeground(TextColor::DARK_WHITE);
|
||||
whiteOnBlack.SetIndexedBackground(TextColor::BRIGHT_BLACK);
|
||||
|
||||
TextAttribute blackOnDefault{};
|
||||
blackOnDefault.SetIndexedForeground(TextColor::BRIGHT_BLACK);
|
||||
|
||||
TextAttribute defaultOnDefault{};
|
||||
|
||||
Log::Comment(L"========== Fill test content ==========");
|
||||
|
||||
// As a pwsh one-liner:
|
||||
//
|
||||
// "`e[37m`e[102m foo\bar `e[92m`e[100m▶ `e[37mBar `e[90m`e[49m▶ `e[m"
|
||||
//
|
||||
// Generally taken from
|
||||
// https://github.com/microsoft/terminal/issues/8341#issuecomment-731310022,
|
||||
// but minimized for easier testing.
|
||||
|
||||
sm.ProcessString(L"\x1b[37m\x1b[102m" // dark white on bright green
|
||||
L" foo\\bar ");
|
||||
sm.ProcessString(L"\x1b[92m\x1b[100m" // bright green on bright black
|
||||
L"▶ ");
|
||||
sm.ProcessString(L"\x1b[37m" // dark white on bright black
|
||||
L"Bar ");
|
||||
sm.ProcessString(L"\x1b[90m\x1b[49m" // bright black on default
|
||||
L"▶ ");
|
||||
sm.ProcessString(L"\x1b[m\n"); // default on default
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb) {
|
||||
// If this test fails on character 8, then it's because we didn't emit the space, we just moved ahead.
|
||||
auto iter0 = TestUtils::VerifyLineContains(tb, { 0, 0 }, whiteOnGreen, 9u);
|
||||
TestUtils::VerifyLineContains(iter0, OutputCellIterator{ greenOnBlack, 2u });
|
||||
TestUtils::VerifyLineContains(iter0, OutputCellIterator{ whiteOnBlack, 4u });
|
||||
TestUtils::VerifyLineContains(iter0, OutputCellIterator{ blackOnDefault, 2u });
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Check host buffer ==========");
|
||||
verifyBuffer(*hostTb);
|
||||
|
||||
Log::Comment(L"========== Paint first frame ==========");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Check terminal buffer ==========");
|
||||
verifyBuffer(*termTb);
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::AltBufferResizeCrash()
|
||||
{
|
||||
Log::Comment(L"During the review for GH#12719, it was noticed that this "
|
||||
L"particular combination of resizing could crash the terminal."
|
||||
L" This test makes sure we don't.");
|
||||
|
||||
// Anything that resizes the buffer needs IsolationLevel:Method
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
|
||||
END_TEST_METHOD_PROPERTIES()
|
||||
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& renderer = *g.pRender;
|
||||
auto& gci = g.getConsoleInformation();
|
||||
@@ -4154,3 +4235,99 @@ void ConptyRoundtripTests::AltBufferResizeCrash()
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::TestNoExtendedAttrsOptimization()
|
||||
{
|
||||
Log::Comment(L"We don't want conpty to optimize out runs of spaces that DO "
|
||||
L"have extended attrs, because EL / ECH don't fill space with "
|
||||
L"those attributes");
|
||||
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& renderer = *g.pRender;
|
||||
auto& gci = g.getConsoleInformation();
|
||||
auto& si = gci.GetActiveOutputBuffer();
|
||||
auto& sm = si.GetStateMachine();
|
||||
|
||||
auto* hostTb = &si.GetTextBuffer();
|
||||
auto* termTb = term->_mainBuffer.get();
|
||||
|
||||
gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
|
||||
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
|
||||
|
||||
_flushFirstFrame();
|
||||
|
||||
_checkConptyOutput = false;
|
||||
|
||||
TextAttribute reverseAttrs{};
|
||||
reverseAttrs.SetReverseVideo(true);
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb) {
|
||||
auto iter0 = TestUtils::VerifyLineContains(tb, { 0, 0 }, L' ', reverseAttrs, 9u);
|
||||
TestUtils::VerifyExpectedString(L"test", iter0);
|
||||
TestUtils::VerifyLineContains(iter0, L' ', reverseAttrs, 9u);
|
||||
|
||||
TestUtils::VerifyLineContains(tb, { 0, 1 }, L' ', reverseAttrs, static_cast<uint32_t>(TerminalViewWidth));
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Fill test content ==========");
|
||||
sm.ProcessString(L"\x1b[7m test \x1b[m\n");
|
||||
sm.ProcessString(L"\x1b[7m");
|
||||
sm.ProcessString(std::wstring(TerminalViewWidth, L' '));
|
||||
sm.ProcessString(L"\x1b[m\n");
|
||||
|
||||
Log::Comment(L"========== Check host buffer ==========");
|
||||
verifyBuffer(*hostTb);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Check terminal buffer ==========");
|
||||
verifyBuffer(*termTb);
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::TestNoBackgroundAttrsOptimization()
|
||||
{
|
||||
Log::Comment(L"Same as above, with BG attrs");
|
||||
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& renderer = *g.pRender;
|
||||
auto& gci = g.getConsoleInformation();
|
||||
auto& si = gci.GetActiveOutputBuffer();
|
||||
auto& sm = si.GetStateMachine();
|
||||
|
||||
auto* hostTb = &si.GetTextBuffer();
|
||||
auto* termTb = term->_mainBuffer.get();
|
||||
|
||||
gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
|
||||
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
|
||||
|
||||
_flushFirstFrame();
|
||||
|
||||
_checkConptyOutput = false;
|
||||
|
||||
TextAttribute bgAttrs{};
|
||||
bgAttrs.SetIndexedBackground(TextColor::DARK_WHITE);
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb) {
|
||||
auto iter0 = TestUtils::VerifyLineContains(tb, { 0, 0 }, L' ', bgAttrs, 9u);
|
||||
TestUtils::VerifyExpectedString(L"test", iter0);
|
||||
TestUtils::VerifyLineContains(iter0, L' ', bgAttrs, 9u);
|
||||
|
||||
TestUtils::VerifyLineContains(tb, { 0, 1 }, L' ', bgAttrs, static_cast<uint32_t>(TerminalViewWidth));
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Fill test content ==========");
|
||||
sm.ProcessString(L"\x1b[47m test \x1b[m\n");
|
||||
sm.ProcessString(L"\x1b[47m");
|
||||
sm.ProcessString(std::wstring(TerminalViewWidth, L' '));
|
||||
sm.ProcessString(L"\x1b[m\n");
|
||||
|
||||
Log::Comment(L"========== Check host buffer ==========");
|
||||
verifyBuffer(*hostTb);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Check terminal buffer ==========");
|
||||
verifyBuffer(*termTb);
|
||||
}
|
||||
|
||||
@@ -405,6 +405,12 @@ void AppHost::Initialize()
|
||||
}
|
||||
});
|
||||
|
||||
_window->AutomaticShutdownRequested([this]() {
|
||||
// Raised when the OS is beginning an update of the app. We will quit,
|
||||
// to save our state, before the OS manually kills us.
|
||||
_windowManager.RequestQuitAll();
|
||||
});
|
||||
|
||||
_logic.Create();
|
||||
|
||||
_revokers.TitleChanged = _logic.TitleChanged(winrt::auto_revoke, { this, &AppHost::AppTitleChanged });
|
||||
|
||||
@@ -648,6 +648,43 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_ENDSESSION:
|
||||
{
|
||||
// For WM_QUERYENDSESSION and WM_ENDSESSION, refer to:
|
||||
//
|
||||
// https://docs.microsoft.com/en-us/windows/win32/rstmgr/guidelines-for-applications
|
||||
//
|
||||
// The OS will send us a WM_QUERYENDSESSION when it's preparing an
|
||||
// update for our app. It will then send us a WM_ENDSESSION, which gives
|
||||
// us a small timeout (~30s) to actually shut down gracefully. After
|
||||
// that timeout, it will send us a WM_CLOSE. If we still don't close
|
||||
// after the WM_CLOSE, it'll force-kill us (causing a crash which will be
|
||||
// bucketed to MoAppHang).
|
||||
//
|
||||
// If we need to do anything to prepare for being told to shutdown,
|
||||
// start it in WM_QUERYENDSESSION. If (in the future) we need to prevent
|
||||
// logoff, we can return false there. (DefWindowProc returns true)
|
||||
//
|
||||
// The OS is going to shut us down here. We will manually start a quit,
|
||||
// so that we can persist the state. If we refuse to gracefully shut
|
||||
// down here, the OS will crash us to forcefully terminate us. We choose
|
||||
// to quit here, rather than just close, to skip over any warning
|
||||
// dialogs (e.g. "Are you sure you want to close all tabs?") which might
|
||||
// prevent a WM_CLOSE from cleanly closing the window.
|
||||
//
|
||||
// This will cause a appHost._RequestQuitAll, which will notify the
|
||||
// monarch to collect up all the window state and save it.
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hWindowsTerminalProvider,
|
||||
"EndSession",
|
||||
TraceLoggingDescription("Emitted when the OS has sent a WM_ENDSESSION"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
_AutomaticShutdownRequestedHandlers();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
// We'll want to receive this message when explorer.exe restarts
|
||||
// so that we can re-add our icon to the notification area.
|
||||
@@ -834,10 +871,20 @@ void IslandWindow::SetAlwaysOnTop(const bool alwaysOnTop)
|
||||
// - <none>
|
||||
void IslandWindow::ShowWindowChanged(const bool showOrHide)
|
||||
{
|
||||
const auto hwnd = GetHandle();
|
||||
if (hwnd)
|
||||
if (const auto hwnd = GetHandle())
|
||||
{
|
||||
PostMessage(hwnd, WM_SYSCOMMAND, showOrHide ? SC_RESTORE : SC_MINIMIZE, 0);
|
||||
// IMPORTANT!
|
||||
//
|
||||
// ONLY "restore" if already minimized. If the window is maximized or
|
||||
// snapped, a restore will restore-down the window instead.
|
||||
if (showOrHide == true && ::IsIconic(hwnd))
|
||||
{
|
||||
::PostMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
|
||||
}
|
||||
else if (showOrHide == false)
|
||||
{
|
||||
::PostMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ public:
|
||||
WINRT_CALLBACK(NotifyReAddNotificationIcon, winrt::delegate<void()>);
|
||||
WINRT_CALLBACK(ShouldExitFullscreen, winrt::delegate<void()>);
|
||||
WINRT_CALLBACK(MaximizeChanged, winrt::delegate<void(bool)>);
|
||||
WINRT_CALLBACK(AutomaticShutdownRequested, winrt::delegate<void(void)>);
|
||||
|
||||
WINRT_CALLBACK(WindowMoved, winrt::delegate<void()>);
|
||||
WINRT_CALLBACK(WindowVisibilityChanged, winrt::delegate<void(bool)>);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
|
||||
<TerminalVCRTForwarders>true</TerminalVCRTForwarders>
|
||||
<TerminalThemeHelpers>true</TerminalThemeHelpers>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
@@ -141,14 +142,6 @@
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
<!-- Override GetPackagingOutputs to roll up all our dependencies.
|
||||
This ensures that when the WAP packaging project asks what files go into
|
||||
the package, we tell it.
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
<!-- VisualStudioSetup -->
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="'$(TerminalVisualStudioSetup)' == 'true' and Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" />
|
||||
|
||||
<!-- WinUI (which depends on WebView2 as of 2.8.0) -->
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="'$(TerminalMUX)' == 'true' and Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
|
||||
<!-- WIL (so widely used that this one does not have a TerminalWIL opt-in property; it is automatic) -->
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220201.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220201.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
|
||||
@@ -95,6 +98,9 @@
|
||||
<!-- VisualStudioSetup -->
|
||||
<Error Condition="'$(TerminalVisualStudioSetup)' == 'true' AND !Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets'))" />
|
||||
|
||||
<!-- WinUI (which depends on WebView2 as of 2.8.0) -->
|
||||
<Error Condition="'$(TerminalMUX)' == 'true' AND !Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
|
||||
<!-- WIL (so widely used that this one does not have a TerminalWIL opt-in property; it is automatic) -->
|
||||
<Error Condition="!Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220201.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220201.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
|
||||
|
||||
@@ -117,18 +117,6 @@
|
||||
</alwaysDisabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_DECPSViaMidiPlayer</name>
|
||||
<description>Enables playing sound via DECPS using the MIDI player.</description>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<!-- We're disabling this for WindowsInbox and Stable because it requires an additional
|
||||
package dependency or library dependency. -->
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>Dev</brandingToken>
|
||||
<brandingToken>Preview</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_ScrollbarMarks</name>
|
||||
<description>Enables the experimental scrollbar marks feature.</description>
|
||||
|
||||
@@ -817,18 +817,6 @@ void Alias::s_ClearCmdExeAliases()
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Trims leading spaces off of a string
|
||||
// Arguments:
|
||||
// - str - String to trim
|
||||
void Alias::s_TrimLeadingSpaces(std::wstring& str)
|
||||
{
|
||||
// Erase from the beginning of the string up until the first
|
||||
// character found that is not a space.
|
||||
str.erase(str.begin(),
|
||||
std::find_if(str.begin(), str.end(), [](wchar_t ch) { return !std::iswspace(ch); }));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Trims trailing \r\n off of a string
|
||||
// Arguments:
|
||||
@@ -1148,9 +1136,6 @@ std::wstring Alias::s_MatchAndCopyAlias(const std::wstring& sourceText,
|
||||
// Trim trailing \r\n off of sourceCopy if it has one.
|
||||
s_TrimTrailingCrLf(sourceCopy);
|
||||
|
||||
// Trim leading spaces off of sourceCopy if it has any.
|
||||
s_TrimLeadingSpaces(sourceCopy);
|
||||
|
||||
// Check if we have an EXE in the list that matches the request first.
|
||||
auto exeIter = g_aliasData.find(exeName);
|
||||
if (exeIter == g_aliasData.end())
|
||||
|
||||
@@ -29,7 +29,6 @@ public:
|
||||
size_t& lineCount);
|
||||
|
||||
private:
|
||||
static void s_TrimLeadingSpaces(std::wstring& str);
|
||||
static void s_TrimTrailingCrLf(std::wstring& str);
|
||||
static std::deque<std::wstring> s_Tokenize(const std::wstring& str);
|
||||
static std::wstring s_GetArgString(const std::wstring& str);
|
||||
|
||||
@@ -382,7 +382,8 @@ MidiAudio& CONSOLE_INFORMATION::GetMidiAudio()
|
||||
{
|
||||
if (!_midiAudio)
|
||||
{
|
||||
_midiAudio = std::make_unique<MidiAudio>();
|
||||
const auto windowHandle = ServiceLocator::LocateConsoleWindow()->GetWindowHandle();
|
||||
_midiAudio = std::make_unique<MidiAudio>(windowHandle);
|
||||
_midiAudio->Initialize();
|
||||
}
|
||||
return *_midiAudio;
|
||||
|
||||
@@ -340,10 +340,10 @@ class AliasTests
|
||||
auto rgwchTargetBefore = std::make_unique<wchar_t[]>(cchTarget);
|
||||
wcscpy_s(rgwchTargetBefore.get(), cchTarget, rgwchTarget.get());
|
||||
size_t cbTargetUsed = 0;
|
||||
const auto cbTargetUsedExpected = cbTarget;
|
||||
const auto cbTargetUsedBefore = cbTargetUsed;
|
||||
|
||||
DWORD dwLines = 0;
|
||||
const auto dwLinesExpected = dwLines + 1;
|
||||
const auto dwLinesBefore = dwLines;
|
||||
|
||||
// Register the correct alias name before we try.
|
||||
std::wstring exe(L"exe.exe");
|
||||
@@ -351,9 +351,7 @@ class AliasTests
|
||||
std::wstring target(L"someTarget");
|
||||
Alias::s_TestAddAlias(exe, source, target);
|
||||
|
||||
auto targetExpected = target + L"\r\n";
|
||||
|
||||
// We should be able to match through the leading spaces. They should be stripped.
|
||||
// Leading spaces should bypass the alias. This should not match anything.
|
||||
Alias::s_MatchAndCopyAliasLegacy(pwszSource,
|
||||
cbSource,
|
||||
rgwchTarget.get(),
|
||||
@@ -362,9 +360,9 @@ class AliasTests
|
||||
exe,
|
||||
dwLines);
|
||||
|
||||
VERIFY_ARE_EQUAL(cbTargetUsedExpected, cbTargetUsed, L"No target bytes should be used.");
|
||||
VERIFY_ARE_EQUAL(String(targetExpected.data(), gsl::narrow<int>(targetExpected.size())), String(rgwchTarget.get(), cchTarget), L"Target string should match expected.");
|
||||
VERIFY_ARE_EQUAL(dwLinesExpected, dwLines, L"Line count be updated to 1.");
|
||||
VERIFY_ARE_EQUAL(cbTargetUsedBefore, cbTargetUsed, L"No bytes should be used if nothing was found.");
|
||||
VERIFY_ARE_EQUAL(String(rgwchTargetBefore.get(), cchTarget), String(rgwchTarget.get(), cchTarget), L"Target string should be unmodified.");
|
||||
VERIFY_ARE_EQUAL(dwLinesBefore, dwLines, L"Line count should pass through.");
|
||||
}
|
||||
|
||||
TEST_METHOD(TrimTrailing)
|
||||
|
||||
@@ -121,6 +121,7 @@ class ConptyOutputTests
|
||||
TEST_METHOD(WriteAFewSimpleLines);
|
||||
TEST_METHOD(InvalidateUntilOneBeforeEnd);
|
||||
TEST_METHOD(SetConsoleTitleWithControlChars);
|
||||
TEST_METHOD(IncludeBackgroundColorChangesInFirstFrame);
|
||||
|
||||
private:
|
||||
bool _writeCallback(const char* const pch, const size_t cch);
|
||||
@@ -371,6 +372,7 @@ void ConptyOutputTests::SetConsoleTitleWithControlChars()
|
||||
{
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
TEST_METHOD_PROPERTY(L"Data:control", L"{0x00, 0x0A, 0x1B, 0x80, 0x9B, 0x9C}")
|
||||
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
|
||||
END_TEST_METHOD_PROPERTIES()
|
||||
|
||||
int control;
|
||||
@@ -400,3 +402,29 @@ void ConptyOutputTests::SetConsoleTitleWithControlChars()
|
||||
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
}
|
||||
|
||||
void ConptyOutputTests::IncludeBackgroundColorChangesInFirstFrame()
|
||||
{
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& renderer = *g.pRender;
|
||||
auto& gci = g.getConsoleInformation();
|
||||
auto& si = gci.GetActiveOutputBuffer();
|
||||
auto& sm = si.GetStateMachine();
|
||||
|
||||
sm.ProcessString(L"\x1b[41mRun 1 \x1b[42mRun 2 \x1b[43mRun 3 \x1b[m");
|
||||
|
||||
expectedOutput.push_back("\x1b[2J"); // standard init sequence for the first frame
|
||||
expectedOutput.push_back("\x1b[m"); // standard init sequence for the first frame
|
||||
expectedOutput.push_back("\x1b[41m");
|
||||
expectedOutput.push_back("\x1b[H"); // standard init sequence for the first frame
|
||||
expectedOutput.push_back("Run 1 ");
|
||||
expectedOutput.push_back("\x1b[42m");
|
||||
expectedOutput.push_back("Run 2 ");
|
||||
expectedOutput.push_back("\x1b[43m");
|
||||
expectedOutput.push_back("Run 3 ");
|
||||
|
||||
// This is also part of the standard init sequence.
|
||||
expectedOutput.push_back("\x1b[?25h");
|
||||
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
}
|
||||
|
||||
@@ -168,15 +168,19 @@ public:
|
||||
auto actualAttrs = actual->TextAttr();
|
||||
auto expectedAttrs = expected->TextAttr();
|
||||
|
||||
auto mismatched = (actualChars != expectedChars || actualAttrs != expectedAttrs);
|
||||
auto mismatched = ((!expectedChars.empty() && actualChars != expectedChars) || actualAttrs != expectedAttrs);
|
||||
if (mismatched)
|
||||
{
|
||||
WEX::Logging::Log::Comment(WEX::Common::NoThrowString().Format(
|
||||
L"Character or attribute at index %d was mismatched", charsProcessed));
|
||||
}
|
||||
|
||||
VERIFY_ARE_EQUAL(expectedChars, actualChars);
|
||||
if (!expectedChars.empty())
|
||||
{
|
||||
VERIFY_ARE_EQUAL(expectedChars, actualChars);
|
||||
}
|
||||
VERIFY_ARE_EQUAL(expectedAttrs, actualAttrs);
|
||||
|
||||
if (mismatched)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -436,6 +436,15 @@ void InteractivityFactory::SetPseudoWindowCallback(std::function<void(bool)> fun
|
||||
// It can be fun to toggle WM_QUERYOPEN but DefWindowProc returns TRUE.
|
||||
case WM_SIZE:
|
||||
{
|
||||
// Curiously, at least on Windows 10 (and rarely on Windows 11), if you
|
||||
// minimize the Terminal by clicking on the taskbar, then alt-tab to try
|
||||
// and restore the window, the Taskbar will decide to call
|
||||
// SwitchToWindow on us, the invisible, owned window of the main window.
|
||||
// When that happens, we'll get a WM_SIZE(SIZE_RESTORED, lParam=0). The
|
||||
// main window will NOT get a SwitchToWindow called. If we don't
|
||||
// actually inform the hosting process about this, then the main HWND
|
||||
// might stay hidden. Refer to GH#13589
|
||||
|
||||
if (wParam == SIZE_RESTORED)
|
||||
{
|
||||
_WritePseudoWindowCallback(true);
|
||||
@@ -447,23 +456,23 @@ void InteractivityFactory::SetPseudoWindowCallback(std::function<void(bool)> fun
|
||||
}
|
||||
break;
|
||||
}
|
||||
// case WM_WINDOWPOSCHANGING:
|
||||
// As long as user32 didn't eat the `ShowWindow` call because the window state requested
|
||||
// matches the existing WS_VISIBLE state of the HWND... we should hear from it in WM_WINDOWPOSCHANGING.
|
||||
// WM_WINDOWPOSCHANGING can tell us a bunch through the flags fields.
|
||||
// We can also check IsIconic/IsZoomed on the HWND during the message
|
||||
// and we could suppress the change to prevent things from happening.
|
||||
// case WM_WINDOWPOSCHANGING:
|
||||
// As long as user32 didn't eat the `ShowWindow` call because the window state requested
|
||||
// matches the existing WS_VISIBLE state of the HWND... we should hear from it in WM_WINDOWPOSCHANGING.
|
||||
// WM_WINDOWPOSCHANGING can tell us a bunch through the flags fields.
|
||||
// We can also check IsIconic/IsZoomed on the HWND during the message
|
||||
// and we could suppress the change to prevent things from happening.
|
||||
// case WM_SYSCOMMAND:
|
||||
// WM_SYSCOMMAND will not come through. Don't try.
|
||||
// WM_SYSCOMMAND will not come through. Don't try.
|
||||
// WM_SHOWWINDOW does come through on some of the messages.
|
||||
case WM_SHOWWINDOW:
|
||||
// WM_SHOWWINDOW comes through on some of the messages.
|
||||
{
|
||||
if (0 == lParam) // Someone explicitly called ShowWindow on us.
|
||||
{
|
||||
if (0 == lParam) // Someone explicitly called ShowWindow on us.
|
||||
{
|
||||
_WritePseudoWindowCallback((bool)wParam);
|
||||
}
|
||||
_WritePseudoWindowCallback((bool)wParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we get this far, call the default window proc
|
||||
return DefWindowProcW(hWnd, Message, wParam, lParam);
|
||||
}
|
||||
@@ -478,18 +487,12 @@ void InteractivityFactory::SetPseudoWindowCallback(std::function<void(bool)> fun
|
||||
// - <none>
|
||||
void InteractivityFactory::_WritePseudoWindowCallback(bool showOrHide)
|
||||
{
|
||||
// BODGY
|
||||
// IMPORTANT!
|
||||
//
|
||||
// GH#13158 - At least temporarily, only allow the PTY to HIDE the terminal
|
||||
// window. There seem to be many issues with this so far, and the quickest
|
||||
// route to mitigate them seems to be limiting the interaction here to
|
||||
// allowing ConPTY to minimize the terminal only. This will still allow
|
||||
// applications to hide the Terminal via GetConsoleWindow(), but should
|
||||
// broadly prevent any other impact of this feature.
|
||||
//
|
||||
// Should we need to restore this functionality in the future, we should
|
||||
// only do so with great caution.
|
||||
if (_pseudoWindowMessageCallback && showOrHide == false)
|
||||
// A hosting terminal window should only "restore" itself in response to
|
||||
// this message, if it's already minimized. If the window is maximized a
|
||||
// restore will restore-down the window instead.
|
||||
if (_pseudoWindowMessageCallback)
|
||||
{
|
||||
_pseudoWindowMessageCallback(showOrHide);
|
||||
}
|
||||
|
||||
@@ -424,10 +424,15 @@ using namespace Microsoft::Console::Types;
|
||||
// the inbox telnet client doesn't understand the Erase Character sequence,
|
||||
// and it uses xterm-ascii. This ensures that xterm and -256color consumers
|
||||
// get the enhancements, and telnet isn't broken.
|
||||
//
|
||||
// GH#13229: ECH and EL don't fill the space with "meta" attributes like
|
||||
// underline, reverse video, hyperlinks, etc. If these spaces had those
|
||||
// attrs, then don't try and optimize them out.
|
||||
const auto optimalToUseECH = numSpaces > ERASE_CHARACTER_STRING_LENGTH;
|
||||
const auto useEraseChar = (optimalToUseECH) &&
|
||||
(!_newBottomLine) &&
|
||||
(!_clearedAllThisFrame);
|
||||
(!_clearedAllThisFrame) &&
|
||||
(!_lastTextAttributes.HasAnyExtendedAttributes());
|
||||
const auto printingBottomLine = coord.Y == _lastViewport.BottomInclusive();
|
||||
|
||||
// GH#5502 - If the background color of the "new bottom line" is different
|
||||
@@ -448,10 +453,13 @@ using namespace Microsoft::Console::Types;
|
||||
// the lines _wrapped_. It doesn't care to manually break the lines, but if
|
||||
// we trimmed the spaces off here, we'd print all the "~"s one after another
|
||||
// on the same line.
|
||||
const auto removeSpaces = !lineWrapped && (useEraseChar ||
|
||||
_clearedAllThisFrame ||
|
||||
(_newBottomLine && printingBottomLine && bgMatched));
|
||||
const auto cchActual = removeSpaces ? nonSpaceLength : cchLine;
|
||||
static const TextAttribute defaultAttrs{};
|
||||
const bool removeSpaces = !lineWrapped && (useEraseChar // we determined earlier that ECH is optimal
|
||||
|| (_clearedAllThisFrame && _lastTextAttributes == defaultAttrs) // OR we cleared the last frame to the default attributes (specifically)
|
||||
|| (_newBottomLine && printingBottomLine && bgMatched)); // OR we just scrolled a new line onto the bottom of the screen with the correct attributes
|
||||
const size_t cchActual = removeSpaces ?
|
||||
(cchLine - numSpaces) :
|
||||
cchLine;
|
||||
|
||||
const auto columnsActual = removeSpaces ?
|
||||
(totalWidth - numSpaces) :
|
||||
|
||||
@@ -2014,7 +2014,6 @@ void StateMachine::ResetState() noexcept
|
||||
// into the given size_t. All existing value is moved up by 10.
|
||||
// - For example, if your value had 437 and you put in the printable number 2,
|
||||
// this function will update value to 4372.
|
||||
// - Clamps to 32767 if it gets too big.
|
||||
// Arguments:
|
||||
// - wch - Printable character to accumulate into the value (after conversion to number, of course)
|
||||
// - value - The value to update with the printable character. See example above.
|
||||
|
||||
@@ -21,11 +21,11 @@ Abstract:
|
||||
|
||||
namespace Microsoft::Console::VirtualTerminal
|
||||
{
|
||||
// The DEC STD 070 reference recommends supporting up to at least 16384 for
|
||||
// parameter values, so 32767 should be more than enough. At most we might
|
||||
// want to increase this to 65535, since that is what XTerm and VTE support,
|
||||
// but for now 32767 is the safest limit for our existing code base.
|
||||
constexpr VTInt MAX_PARAMETER_VALUE = 32767;
|
||||
// The DEC STD 070 reference recommends supporting up to at least 16384
|
||||
// for parameter values. 65535 is what XTerm and VTE support.
|
||||
// GH#12977: We must use 65535 to properly parse win32-input-mode
|
||||
// sequences, which transmit the UTF-16 character value as a parameter.
|
||||
constexpr VTInt MAX_PARAMETER_VALUE = 65535;
|
||||
|
||||
// The DEC STD 070 reference requires that a minimum of 16 parameter values
|
||||
// are supported, but most modern terminal emulators will allow around twice
|
||||
|
||||
@@ -1589,7 +1589,7 @@ class StateMachineExternalTest final
|
||||
}
|
||||
else if (uiGiven > MAX_PARAMETER_VALUE)
|
||||
{
|
||||
*uiExpected = MAX_PARAMETER_VALUE; // 32767 is our max value.
|
||||
*uiExpected = MAX_PARAMETER_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user