mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-19 13:06:47 +00:00
Compare commits
75 Commits
dev/cazamo
...
v1.15.2874
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abfaa5dc5f | ||
|
|
a2bced81a9 | ||
|
|
72fbcd6559 | ||
|
|
cae559376a | ||
|
|
c6ea72fb61 | ||
|
|
b1306c5e79 | ||
|
|
1735110040 | ||
|
|
aa7681f125 | ||
|
|
0f947043c9 | ||
|
|
0f6d29adaf | ||
|
|
24a8463818 | ||
|
|
c25cd5c9c7 | ||
|
|
78f1bdff69 | ||
|
|
dda7410408 | ||
|
|
07cfad1e35 | ||
|
|
69789eae14 | ||
|
|
daec33babc | ||
|
|
a1879878f0 | ||
|
|
faa4c1ac8b | ||
|
|
d1c7ee2c17 | ||
|
|
377cc05fb7 | ||
|
|
06648e3212 | ||
|
|
acc019b3cb | ||
|
|
8d37b213e2 | ||
|
|
efb7f30717 | ||
|
|
decfc3dcee | ||
|
|
c288df551e | ||
|
|
fc0ad5ab75 | ||
|
|
20b0447774 | ||
|
|
c4130367f3 | ||
|
|
64c774e2a7 | ||
|
|
462192e88b | ||
|
|
062e2b3f20 | ||
|
|
5dcde95bfb | ||
|
|
ecfe4b5d6a | ||
|
|
6027a367b2 | ||
|
|
2f6b546f02 | ||
|
|
eada4d2c9e | ||
|
|
4829e9218e | ||
|
|
edef86b654 | ||
|
|
cd9a114359 | ||
|
|
0b63a33301 | ||
|
|
a0eaea84f0 | ||
|
|
038ad3b509 | ||
|
|
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}"
|
||||
@@ -644,7 +645,8 @@ Global
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -662,7 +664,8 @@ Global
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|x64.Build.0 = Release|x64
|
||||
@@ -2309,7 +2312,8 @@ Global
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -2326,7 +2330,8 @@ Global
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|x64.ActiveCfg = Release|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|x64.Build.0 = Release|x64
|
||||
@@ -3357,7 +3362,8 @@ Global
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -3377,7 +3383,8 @@ Global
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.ActiveCfg = Release|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.Build.0 = Release|x64
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"collection": "microsoft",
|
||||
"project": "OS",
|
||||
"repo": "os.2020",
|
||||
"name": "official/rs_wdx_dxp_windev",
|
||||
"name": "official/rs_we_adept_e4d2",
|
||||
"workitem": "38106206",
|
||||
"CheckinFiles": [
|
||||
{
|
||||
@@ -21,4 +21,4 @@
|
||||
"sendOnErrorOnly": "False"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,7 @@
|
||||
<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" />
|
||||
<package id="Microsoft.Debugging.Tools.PdbStr" version="20220617.1556.0" targetFramework="native" />
|
||||
<package id="Microsoft.Debugging.Tools.SrcTool" version="20220617.1556.0" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Optional, defaults to main. Name of the branch which will be used for calculating branch point. -->
|
||||
<PGOBranch>main</PGOBranch>
|
||||
<PGOBranch>release-1.15</PGOBranch>
|
||||
|
||||
<!-- Mandatory. Name of the NuGet package which will contain PGO databases for consumption by build system. -->
|
||||
<PGOPackageName>Microsoft.Internal.Windows.Terminal.PGODatabase</PGOPackageName>
|
||||
|
||||
@@ -134,8 +134,6 @@ jobs:
|
||||
|
||||
Write-Host "##vso[task.setvariable variable=RationalizedBuildPlatform]${Arch}"
|
||||
- template: .\templates\restore-nuget-steps.yml
|
||||
# Pull the Windows SDK for the developer tools like the debuggers so we can index sources later
|
||||
- template: .\templates\install-winsdk-steps.yml
|
||||
- task: UniversalPackages@0
|
||||
displayName: Download terminal-internal Universal Package
|
||||
inputs:
|
||||
@@ -241,6 +239,7 @@ jobs:
|
||||
filePath: build\scripts\Index-Pdbs.ps1
|
||||
arguments: -SearchDir '$(Build.SourcesDirectory)' -SourceRoot '$(Build.SourcesDirectory)' -recursive -Verbose -CommitId $(Build.SourceVersion)
|
||||
errorActionPreference: silentlyContinue
|
||||
pwsh: true
|
||||
- task: PowerShell@2
|
||||
displayName: Run Unit Tests
|
||||
condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'x86')))
|
||||
@@ -336,6 +335,13 @@ jobs:
|
||||
${{ windowsVersion }}:
|
||||
TerminalTargetWindowsVersion: ${{ windowsVersion }}
|
||||
displayName: Create and sign AppX/MSIX bundles
|
||||
variables:
|
||||
${{ if eq(parameters.branding, 'Release') }}:
|
||||
BundleStemName: Microsoft.WindowsTerminal
|
||||
${{ elseif eq(parameters.branding, 'Preview') }}:
|
||||
BundleStemName: Microsoft.WindowsTerminalPreview
|
||||
${{ else }}:
|
||||
BundleStemName: WindowsTerminalDev
|
||||
dependsOn: Build
|
||||
steps:
|
||||
- checkout: self
|
||||
@@ -360,14 +366,15 @@ jobs:
|
||||
$Components = "$(XES_APPXMANIFESTVERSION)" -Split "\."
|
||||
$Components[0] = ([int]$Components[0] + $VersionEpoch)
|
||||
$BundleVersion = $Components -Join "."
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\Microsoft.WindowsTerminal_$(TerminalTargetWindowsVersion)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
New-Item -Type Directory "$(System.ArtifactsDirectory)\bundle"
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\bundle\$(BundleStemName)_$(TerminalTargetWindowsVersion)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
displayName: Create WindowsTerminal*.msixbundle
|
||||
- task: EsrpCodeSigning@1
|
||||
displayName: Submit *.msixbundle to ESRP for code signing
|
||||
inputs:
|
||||
ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
|
||||
FolderPath: $(System.ArtifactsDirectory)
|
||||
Pattern: Microsoft.WindowsTerminal*.msixbundle
|
||||
FolderPath: $(System.ArtifactsDirectory)\bundle
|
||||
Pattern: $(BundleStemName)*.msixbundle
|
||||
UseMinimatch: true
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: >-
|
||||
@@ -400,7 +407,7 @@ jobs:
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Artifact: appxbundle-signed'
|
||||
inputs:
|
||||
PathtoPublish: $(System.ArtifactsDirectory)
|
||||
PathtoPublish: $(System.ArtifactsDirectory)\bundle
|
||||
ArtifactName: appxbundle-signed-$(TerminalTargetWindowsVersion)
|
||||
|
||||
- ${{ if eq(parameters.buildConPTY, true) }}:
|
||||
@@ -612,6 +619,8 @@ jobs:
|
||||
- task: PkgESSetupBuild@12
|
||||
displayName: Package ES - Setup Build
|
||||
|
||||
- template: .\templates\restore-nuget-steps.yml
|
||||
|
||||
# Download the appx-PLATFORM-CONFIG-VERSION artifact for every platform/version combo
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- ${{ each windowsVersion in parameters.buildWindowsVersions }}:
|
||||
@@ -634,13 +643,12 @@ jobs:
|
||||
}
|
||||
displayName: Extract symbols for public consumption
|
||||
|
||||
# Pull the Windows SDK for the developer tools like the debuggers so we can index sources later
|
||||
- template: .\templates\install-winsdk-steps.yml
|
||||
- task: PowerShell@2
|
||||
displayName: Source Index PDBs (the public ones)
|
||||
inputs:
|
||||
filePath: build\scripts\Index-Pdbs.ps1
|
||||
arguments: -SearchDir '$(Build.SourcesDirectory)/appxsym-temp' -SourceRoot '$(Build.SourcesDirectory)' -recursive -Verbose -CommitId $(Build.SourceVersion)
|
||||
pwsh: true
|
||||
|
||||
# Publish the app symbols to the public MSDL symbol server
|
||||
# accessible via https://msdl.microsoft.com/download/symbols
|
||||
@@ -706,6 +714,7 @@ jobs:
|
||||
description: VPack for the Windows Terminal Application
|
||||
pushPkgName: WindowsTerminal.app
|
||||
owner: conhost
|
||||
githubToken: $(GitHubTokenForVpackProvenance)
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Copy VPack Manifest to Drop'
|
||||
inputs:
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
parameters:
|
||||
sdkVersion: 18362
|
||||
steps:
|
||||
- task: powershell@2
|
||||
inputs:
|
||||
targetType: filePath
|
||||
filePath: build\scripts\Install-WindowsSdkISO.ps1
|
||||
arguments: ${{ parameters.sdkVersion }}
|
||||
displayName: 'Install Windows SDK (${{ parameters.sdkVersion }})'
|
||||
@@ -8,10 +8,11 @@ Param(
|
||||
[switch]$recursive
|
||||
)
|
||||
|
||||
$debuggerPath = (Get-ItemProperty -path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots" -name WindowsDebuggersRoot10).WindowsDebuggersRoot10
|
||||
$srcsrvPath = Join-Path $debuggerPath "x64\srcsrv"
|
||||
$srctoolExe = Join-Path $srcsrvPath "srctool.exe"
|
||||
$pdbstrExe = Join-Path $srcsrvPath "pdbstr.exe"
|
||||
$pdbStrPackage = ([xml](Get-Content "$SourceRoot\build\packages.config")).packages.package | Where-Object id -like "*PdbStr*"
|
||||
# This assumes that we rev PdbStr and SrcTool at the same time.
|
||||
$debugPackageVersions = $pdbStrPackage.version
|
||||
$srctoolExe = Join-Path $SourceRoot "packages" "Microsoft.Debugging.Tools.SrcTool.$debugPackageVersions" "content" "amd64" "srctool.exe"
|
||||
$pdbstrExe = Join-Path $SourceRoot "packages" "Microsoft.Debugging.Tools.PdbStr.$debugPackageVersions" "content" "amd64" "pdbstr.exe"
|
||||
|
||||
$fileTable = @{}
|
||||
foreach ($gitFile in & git ls-files)
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
param([Parameter(Mandatory=$true, Position=0)]
|
||||
[string]$buildNumber)
|
||||
|
||||
# Ensure the error action preference is set to the default for PowerShell3, 'Stop'
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Constants
|
||||
$WindowsSDKOptions = @("OptionId.UWPCpp", "OptionId.DesktopCPPx64", "OptionId.DesktopCPPx86", "OptionId.DesktopCPPARM64", "OptionId.DesktopCPPARM", "OptionId.WindowsDesktopDebuggers")
|
||||
$WindowsSDKRegPath = "HKLM:\Software\WOW6432Node\Microsoft\Windows Kits\Installed Roots"
|
||||
$WindowsSDKRegRootKey = "KitsRoot10"
|
||||
$WindowsSDKVersion = "10.0.$buildNumber.0"
|
||||
$WindowsSDKInstalledRegPath = "$WindowsSDKRegPath\$WindowsSDKVersion\Installed Options"
|
||||
$StrongNameRegPath = "HKLM:\SOFTWARE\Microsoft\StrongName\Verification"
|
||||
$PublicKeyTokens = @("31bf3856ad364e35")
|
||||
|
||||
if ($buildNumber -notmatch "^\d{5,}$")
|
||||
{
|
||||
Write-Host "ERROR: '$buildNumber' doesn't look like a windows build number"
|
||||
Write-Host
|
||||
Exit 1
|
||||
}
|
||||
|
||||
function Download-File
|
||||
{
|
||||
param ([string] $outDir,
|
||||
[string] $downloadUrl,
|
||||
[string] $downloadName)
|
||||
|
||||
$downloadPath = Join-Path $outDir "$downloadName.download"
|
||||
$downloadDest = Join-Path $outDir $downloadName
|
||||
$downloadDestTemp = Join-Path $outDir "$downloadName.tmp"
|
||||
|
||||
Write-Host -NoNewline "Downloading $downloadName..."
|
||||
|
||||
$retries = 10
|
||||
$downloaded = $false
|
||||
while (-not $downloaded)
|
||||
{
|
||||
try
|
||||
{
|
||||
$webclient = new-object System.Net.WebClient
|
||||
$webclient.DownloadFile($downloadUrl, $downloadPath)
|
||||
$downloaded = $true
|
||||
}
|
||||
catch [System.Net.WebException]
|
||||
{
|
||||
Write-Host
|
||||
Write-Warning "Failed to fetch updated file from $downloadUrl : $($error[0])"
|
||||
if (!(Test-Path $downloadDest))
|
||||
{
|
||||
if ($retries -gt 0)
|
||||
{
|
||||
Write-Host "$retries retries left, trying download again"
|
||||
$retries--
|
||||
start-sleep -Seconds 10
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "$downloadName was not found at $downloadDest"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning "$downloadName may be out of date"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Unblock-File $downloadPath
|
||||
|
||||
$downloadDestTemp = $downloadPath;
|
||||
|
||||
# Delete and rename to final dest
|
||||
Write-Host "testing $downloadDest"
|
||||
if (Test-Path $downloadDest)
|
||||
{
|
||||
Write-Host "Deleting: $downloadDest"
|
||||
Remove-Item $downloadDest -Force
|
||||
}
|
||||
|
||||
Move-Item -Force $downloadDestTemp $downloadDest
|
||||
Write-Host "Done"
|
||||
|
||||
return $downloadDest
|
||||
}
|
||||
|
||||
function Get-ISODriveLetter
|
||||
{
|
||||
param ([string] $isoPath)
|
||||
|
||||
$diskImage = Get-DiskImage -ImagePath $isoPath
|
||||
if ($diskImage)
|
||||
{
|
||||
$volume = Get-Volume -DiskImage $diskImage
|
||||
|
||||
if ($volume)
|
||||
{
|
||||
$driveLetter = $volume.DriveLetter
|
||||
if ($driveLetter)
|
||||
{
|
||||
$driveLetter += ":"
|
||||
return $driveLetter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Mount-ISO
|
||||
{
|
||||
param ([string] $isoPath)
|
||||
|
||||
# Check if image is already mounted
|
||||
$isoDrive = Get-ISODriveLetter $isoPath
|
||||
|
||||
if (!$isoDrive)
|
||||
{
|
||||
Mount-DiskImage -ImagePath $isoPath -StorageType ISO | Out-Null
|
||||
}
|
||||
|
||||
$isoDrive = Get-ISODriveLetter $isoPath
|
||||
Write-Verbose "$isoPath mounted to ${isoDrive}:"
|
||||
}
|
||||
|
||||
function Dismount-ISO
|
||||
{
|
||||
param ([string] $isoPath)
|
||||
|
||||
$isoDrive = (Get-DiskImage -ImagePath $isoPath | Get-Volume).DriveLetter
|
||||
|
||||
if ($isoDrive)
|
||||
{
|
||||
Write-Verbose "$isoPath dismounted"
|
||||
Dismount-DiskImage -ImagePath $isoPath | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Disable-StrongName
|
||||
{
|
||||
param ([string] $publicKeyToken = "*")
|
||||
|
||||
reg ADD "HKLM\SOFTWARE\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null
|
||||
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64")
|
||||
{
|
||||
reg ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Test-Admin
|
||||
{
|
||||
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal $identity
|
||||
$principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
|
||||
function Test-RegistryPathAndValue
|
||||
{
|
||||
param (
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $path,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $value)
|
||||
|
||||
try
|
||||
{
|
||||
if (Test-Path $path)
|
||||
{
|
||||
Get-ItemProperty -Path $path | Select-Object -ExpandProperty $value -ErrorAction Stop | Out-Null
|
||||
return $true
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
function Test-InstallWindowsSDK
|
||||
{
|
||||
$retval = $true
|
||||
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey)
|
||||
{
|
||||
# A Windows SDK is installed
|
||||
# Is an SDK of our version installed with the options we need?
|
||||
$allRequiredSdkOptionsInstalled = $true
|
||||
foreach($sdkOption in $WindowsSDKOptions)
|
||||
{
|
||||
if (!(Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value $sdkOption))
|
||||
{
|
||||
$allRequiredSdkOptionsInstalled = $false
|
||||
}
|
||||
}
|
||||
|
||||
if($allRequiredSdkOptionsInstalled)
|
||||
{
|
||||
# It appears we have what we need. Double check the disk
|
||||
$sdkRoot = Get-ItemProperty -Path $WindowsSDKRegPath | Select-Object -ExpandProperty $WindowsSDKRegRootKey
|
||||
if ($sdkRoot)
|
||||
{
|
||||
if (Test-Path $sdkRoot)
|
||||
{
|
||||
$refPath = Join-Path $sdkRoot "References\$WindowsSDKVersion"
|
||||
if (Test-Path $refPath)
|
||||
{
|
||||
$umdPath = Join-Path $sdkRoot "UnionMetadata\$WindowsSDKVersion"
|
||||
if (Test-Path $umdPath)
|
||||
{
|
||||
# Pretty sure we have what we need
|
||||
$retval = $false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $retval
|
||||
}
|
||||
|
||||
function Test-InstallStrongNameHijack
|
||||
{
|
||||
foreach($publicKeyToken in $PublicKeyTokens)
|
||||
{
|
||||
$key = "$StrongNameRegPath\*,$publicKeyToken"
|
||||
if (!(Test-Path $key))
|
||||
{
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
Write-Host -NoNewline "Checking for installed Windows SDK $WindowsSDKVersion..."
|
||||
$InstallWindowsSDK = Test-InstallWindowsSDK
|
||||
if ($InstallWindowsSDK)
|
||||
{
|
||||
Write-Host "Installation required"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "INSTALLED"
|
||||
}
|
||||
|
||||
$StrongNameHijack = Test-InstallStrongNameHijack
|
||||
Write-Host -NoNewline "Checking if StrongName bypass required..."
|
||||
|
||||
if ($StrongNameHijack)
|
||||
{
|
||||
Write-Host "REQUIRED"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Done"
|
||||
}
|
||||
|
||||
if ($StrongNameHijack -or $InstallWindowsSDK)
|
||||
{
|
||||
if (!(Test-Admin))
|
||||
{
|
||||
Write-Host
|
||||
throw "ERROR: Elevation required"
|
||||
}
|
||||
}
|
||||
|
||||
if ($InstallWindowsSDK)
|
||||
{
|
||||
# Static(ish) link for Windows SDK
|
||||
# Note: there is a delay from Windows SDK announcements to availability via the static link
|
||||
$uri = "https://software-download.microsoft.com/download/sg/Windows_InsiderPreview_SDK_en-us_$($buildNumber)_1.iso";
|
||||
|
||||
if ($env:TEMP -eq $null)
|
||||
{
|
||||
$env:TEMP = Join-Path $env:SystemDrive 'temp'
|
||||
}
|
||||
|
||||
$winsdkTempDir = Join-Path (Join-Path $env:TEMP ([System.IO.Path]::GetRandomFileName())) "WindowsSDK"
|
||||
|
||||
if (![System.IO.Directory]::Exists($winsdkTempDir))
|
||||
{
|
||||
[void][System.IO.Directory]::CreateDirectory($winsdkTempDir)
|
||||
}
|
||||
|
||||
$file = "winsdk_$buildNumber.iso"
|
||||
|
||||
Write-Verbose "Getting WinSDK from $uri"
|
||||
$downloadFile = Download-File $winsdkTempDir $uri $file
|
||||
Write-Verbose "File is at $downloadFile"
|
||||
$downloadFileItem = Get-Item $downloadFile
|
||||
|
||||
# Check to make sure the file is at least 10 MB.
|
||||
if ($downloadFileItem.Length -lt 10*1024*1024)
|
||||
{
|
||||
Write-Host
|
||||
Write-Host "ERROR: Downloaded file doesn't look large enough to be an ISO. The requested version may not be on microsoft.com yet."
|
||||
Write-Host
|
||||
Exit 1
|
||||
}
|
||||
|
||||
# TODO Check if zip, exe, iso, etc.
|
||||
try
|
||||
{
|
||||
Write-Host -NoNewline "Mounting ISO $file..."
|
||||
Mount-ISO $downloadFile
|
||||
Write-Host "Done"
|
||||
|
||||
$isoDrive = Get-ISODriveLetter $downloadFile
|
||||
|
||||
if (Test-Path $isoDrive)
|
||||
{
|
||||
Write-Host -NoNewLine "Installing WinSDK..."
|
||||
|
||||
$setupPath = Join-Path "$isoDrive" "WinSDKSetup.exe"
|
||||
Start-Process -Wait $setupPath "/features $WindowsSDKOptions /q"
|
||||
Write-Host "Done"
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Could not find mounted ISO at ${isoDrive}"
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Write-Host -NoNewline "Dismounting ISO $file..."
|
||||
Dismount-ISO $downloadFile
|
||||
Write-Host "Done"
|
||||
}
|
||||
}
|
||||
|
||||
if ($StrongNameHijack)
|
||||
{
|
||||
Write-Host -NoNewline "Disabling StrongName for Windows SDK..."
|
||||
|
||||
foreach($key in $PublicKeyTokens)
|
||||
{
|
||||
Disable-StrongName $key
|
||||
}
|
||||
|
||||
Write-Host "Done"
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{"Registrations":[
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/component-detection-manifest.json",
|
||||
"Registrations": [
|
||||
{
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/CLIUtils/CLI11",
|
||||
"commitHash": "dd0d8e4fe729e5b1110232c7a5c9566dad884686"
|
||||
}
|
||||
}
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/CLIUtils/CLI11",
|
||||
"commitHash": "5cb3efabce007c3a0230e4cc2e27da491c646b6c"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Version": 1
|
||||
],
|
||||
"Version": 1
|
||||
}
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
},
|
||||
"intenseTextStyle": {
|
||||
"default": "bright",
|
||||
"description": "Controls how 'intense' text is rendered. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"description": "Controls how 'intense' text is rendered when unfocused. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"enum": [
|
||||
"none",
|
||||
"bold",
|
||||
@@ -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"
|
||||
},
|
||||
@@ -2136,6 +2209,17 @@
|
||||
],
|
||||
"deprecated": true
|
||||
},
|
||||
"intenseTextStyle": {
|
||||
"default": "bright",
|
||||
"description": "Controls how 'intense' text is rendered. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"enum": [
|
||||
"none",
|
||||
"bold",
|
||||
"bright",
|
||||
"all"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"foreground": {
|
||||
"$ref": "#/$defs/Color",
|
||||
"default": "#cccccc",
|
||||
|
||||
@@ -5,55 +5,34 @@
|
||||
#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")
|
||||
|
||||
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)
|
||||
{
|
||||
_directSoundModule.reset(LoadLibraryExW(L"dsound.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32));
|
||||
if (_directSoundModule)
|
||||
{
|
||||
auto createFunction = GetProcAddressByFunctionDeclaration(_directSoundModule.get(), DirectSoundCreate8);
|
||||
if (SUCCEEDED(createFunction(nullptr, &_directSound, nullptr)))
|
||||
{
|
||||
if (SUCCEEDED(_directSound->SetCooperativeLevel(windowHandle, DSSCL_NORMAL)))
|
||||
{
|
||||
_createBuffers();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MidiAudio::~MidiAudio() noexcept
|
||||
{
|
||||
try
|
||||
@@ -61,7 +40,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 +82,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 +109,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,13 @@ public:
|
||||
void PlayNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) noexcept;
|
||||
|
||||
private:
|
||||
void _createBuffers() noexcept;
|
||||
|
||||
wil::unique_hmodule _directSoundModule;
|
||||
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;
|
||||
|
||||
@@ -1138,7 +1138,7 @@ til::point TextBuffer::GetWordStart(const til::point target, const std::wstring_
|
||||
// that it actually points to a space in the buffer
|
||||
copy = bufferSize.BottomRightInclusive();
|
||||
}
|
||||
else if (target >= limit)
|
||||
else if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
{
|
||||
// if at/past the limit --> clamp to limit
|
||||
copy = limitOptional.value_or(bufferSize.BottomRightInclusive());
|
||||
@@ -1254,7 +1254,7 @@ til::point TextBuffer::GetWordEnd(const til::point target, const std::wstring_vi
|
||||
// Already at/past the limit. Can't move forward.
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
if (target >= limit)
|
||||
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
@@ -1282,7 +1282,7 @@ til::point TextBuffer::_GetWordEndForAccessibility(const til::point target, cons
|
||||
const auto bufferSize{ GetSize() };
|
||||
auto result{ target };
|
||||
|
||||
if (target >= limit)
|
||||
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
{
|
||||
// if we're already on/past the last RegularChar,
|
||||
// clamp result to that position
|
||||
@@ -1419,7 +1419,7 @@ bool TextBuffer::MoveToNextWord(til::point& pos, const std::wstring_view wordDel
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) };
|
||||
|
||||
if (copy >= limit)
|
||||
if (bufferSize.CompareInBounds(copy, limit, true) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1466,7 +1466,7 @@ til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<til::po
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
|
||||
// Clamp pos to limit
|
||||
if (resultPos > limit)
|
||||
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
|
||||
{
|
||||
resultPos = limit;
|
||||
}
|
||||
@@ -1494,7 +1494,7 @@ til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode,
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
|
||||
// Clamp pos to limit
|
||||
if (resultPos > limit)
|
||||
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
|
||||
{
|
||||
resultPos = limit;
|
||||
}
|
||||
@@ -1524,19 +1524,9 @@ til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode,
|
||||
bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
bool pastEndInclusive;
|
||||
til::point limit;
|
||||
{
|
||||
// if the limit is past the end of the buffer,
|
||||
// 1) clamp limit to end of buffer
|
||||
// 2) set pastEndInclusive
|
||||
const auto endInclusive{ bufferSize.BottomRightInclusive() };
|
||||
const auto val = limitOptional.value_or(endInclusive);
|
||||
pastEndInclusive = val > endInclusive;
|
||||
limit = pastEndInclusive ? endInclusive : val;
|
||||
}
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
|
||||
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit) + (pastEndInclusive ? 1 : 0) };
|
||||
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit, true) };
|
||||
if (distanceToLimit >= 0)
|
||||
{
|
||||
// Corner Case: we're on/past the limit
|
||||
@@ -1579,7 +1569,7 @@ bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point>
|
||||
const auto bufferSize = GetSize();
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
|
||||
if (pos > limit)
|
||||
if (bufferSize.CompareInBounds(pos, limit, true) > 0)
|
||||
{
|
||||
// we're past the end
|
||||
// clamp us to the limit
|
||||
@@ -1621,7 +1611,7 @@ const std::vector<til::inclusive_rect> TextBuffer::GetTextRects(til::point start
|
||||
// (0,0) is the top-left of the screen
|
||||
// the physically "higher" coordinate is closer to the top-left
|
||||
// the physically "lower" coordinate is closer to the bottom-right
|
||||
const auto [higherCoord, lowerCoord] = start <= end ?
|
||||
const auto [higherCoord, lowerCoord] = bufferSize.CompareInBounds(start, end) <= 0 ?
|
||||
std::make_tuple(start, end) :
|
||||
std::make_tuple(end, start);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -99,7 +99,8 @@
|
||||
<com:ComInterface>
|
||||
<com:ProxyStub Id="DEC4804D-56D1-4F73-9FBE-6828E7C85C56" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
|
||||
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/> <!-- ITerminalHandoff -->
|
||||
<com:Interface Id="AA6B364F-4A50-4176-9002-0AE755E7B5EF" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/> <!-- ITerminalHandoff2 -->
|
||||
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
|
||||
</com:ComInterface>
|
||||
</com:Extension>
|
||||
|
||||
@@ -188,7 +188,8 @@
|
||||
<com:ComInterface>
|
||||
<com:ProxyStub Id="1833E661-CC81-4DD0-87C6-C2F74BD39EFA" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
|
||||
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/> <!-- ITerminalHandoff -->
|
||||
<com:Interface Id="AA6B364F-4A50-4176-9002-0AE755E7B5EF" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/> <!-- ITerminalHandoff2 -->
|
||||
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
|
||||
</com:ComInterface>
|
||||
</com:Extension>
|
||||
|
||||
@@ -188,7 +188,8 @@
|
||||
<com:ComInterface>
|
||||
<com:ProxyStub Id="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
|
||||
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/> <!-- ITerminalHandoff -->
|
||||
<com:Interface Id="AA6B364F-4A50-4176-9002-0AE755E7B5EF" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/> <!-- ITerminalHandoff2 -->
|
||||
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
</com:ComInterface>
|
||||
</com:Extension>
|
||||
|
||||
@@ -503,7 +503,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Duplicate the first pane"));
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
@@ -521,7 +521,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash"));
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
@@ -843,7 +843,7 @@ namespace TerminalAppLocalTests
|
||||
// | 1 | 2 |
|
||||
// | | |
|
||||
// -------------------
|
||||
page->_SplitPane(SplitDirection::Right, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Right, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
secondId = tab->_activePane->Id().value();
|
||||
});
|
||||
Sleep(250);
|
||||
@@ -861,7 +861,7 @@ namespace TerminalAppLocalTests
|
||||
// | 3 | |
|
||||
// | | |
|
||||
// -------------------
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
// Split again to make the 3rd tab
|
||||
thirdId = tab->_activePane->Id().value();
|
||||
@@ -881,7 +881,7 @@ namespace TerminalAppLocalTests
|
||||
// | 3 | 4 |
|
||||
// | | |
|
||||
// -------------------
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
fourthId = tab->_activePane->Id().value();
|
||||
});
|
||||
|
||||
@@ -30,14 +30,6 @@
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
<Import Project="$(OpenConsoleDir)\src\cppwinrt.build.pre.props" />
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<!-- For CLI11: It uses dynamic_cast to cast types around, which depends
|
||||
on being compiled with RTTI (/GR). -->
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
#include "pch.h"
|
||||
#include "HwndTerminal.hpp"
|
||||
#include <windowsx.h>
|
||||
#include "../../types/TermControlUiaProvider.hpp"
|
||||
#include <DefaultSettings.h>
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "../../types/viewport.cpp"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
|
||||
@@ -54,6 +50,17 @@ LRESULT CALLBACK HwndTerminal::HwndTerminalWndProc(
|
||||
LPARAM lParam) noexcept
|
||||
try
|
||||
{
|
||||
if (WM_NCCREATE == uMsg)
|
||||
{
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
auto cs = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
HwndTerminal* that = static_cast<HwndTerminal*>(cs->lpCreateParams);
|
||||
that->_hwnd = wil::unique_hwnd(hwnd);
|
||||
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(that));
|
||||
return DefWindowProc(hwnd, WM_NCCREATE, wParam, lParam);
|
||||
}
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
auto terminal = reinterpret_cast<HwndTerminal*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
|
||||
@@ -182,7 +189,7 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
|
||||
|
||||
if (RegisterTermClass(hInstance))
|
||||
{
|
||||
_hwnd = wil::unique_hwnd(CreateWindowExW(
|
||||
CreateWindowExW(
|
||||
0,
|
||||
term_window_class,
|
||||
nullptr,
|
||||
@@ -197,10 +204,7 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
|
||||
parentHwnd,
|
||||
nullptr,
|
||||
hInstance,
|
||||
nullptr));
|
||||
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
SetWindowLongPtr(_hwnd.get(), GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,14 +328,15 @@ IRawElementProviderSimple* HwndTerminal::_GetUiaProvider() noexcept
|
||||
{
|
||||
// If TermControlUiaProvider throws during construction,
|
||||
// we don't want to try constructing an instance again and again.
|
||||
// _uiaProviderInitialized helps us prevent this.
|
||||
if (!_uiaProviderInitialized)
|
||||
if (!_uiaProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
LOG_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, this->GetUiaData(), this));
|
||||
_uiaProviderInitialized = true;
|
||||
LOG_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<HwndTerminalAutomationPeer>(&_uiaProvider, this->GetUiaData(), this));
|
||||
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(_uiaProvider.Get());
|
||||
LOG_IF_FAILED(_uiaEngine->Enable());
|
||||
_renderer->AddRenderEngine(_uiaEngine.get());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -380,29 +385,10 @@ void HwndTerminal::SendOutput(std::wstring_view data)
|
||||
|
||||
HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal)
|
||||
{
|
||||
// In order for UIA to hook up properly there needs to be a "static" window hosting the
|
||||
// inner win32 control. If the static window is not present then WM_GETOBJECT messages
|
||||
// will not reach the child control, and the uia element will not be present in the tree.
|
||||
auto _hostWindow = CreateWindowEx(
|
||||
0,
|
||||
L"static",
|
||||
nullptr,
|
||||
WS_CHILD |
|
||||
WS_CLIPCHILDREN |
|
||||
WS_CLIPSIBLINGS |
|
||||
WS_VISIBLE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
parentHwnd,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
auto _terminal = std::make_unique<HwndTerminal>(_hostWindow);
|
||||
auto _terminal = std::make_unique<HwndTerminal>(parentHwnd);
|
||||
RETURN_IF_FAILED(_terminal->Initialize());
|
||||
|
||||
*hwnd = _hostWindow;
|
||||
*hwnd = _terminal->GetHwnd();
|
||||
*terminal = _terminal.release();
|
||||
|
||||
return S_OK;
|
||||
@@ -725,6 +711,10 @@ try
|
||||
{
|
||||
modifiers |= ControlKeyStates::EnhancedKey;
|
||||
}
|
||||
if (vkey && keyDown && _uiaProvider)
|
||||
{
|
||||
_uiaProvider->RecordKeyEvent(vkey);
|
||||
}
|
||||
_terminal->SendKeyEvent(vkey, scanCode, modifiers, keyDown);
|
||||
}
|
||||
CATCH_LOG();
|
||||
@@ -833,12 +823,20 @@ void __stdcall TerminalSetFocus(void* terminal)
|
||||
{
|
||||
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
|
||||
publicTerminal->_focused = true;
|
||||
if (auto uiaEngine = publicTerminal->_uiaEngine.get())
|
||||
{
|
||||
LOG_IF_FAILED(uiaEngine->Enable());
|
||||
}
|
||||
}
|
||||
|
||||
void __stdcall TerminalKillFocus(void* terminal)
|
||||
{
|
||||
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
|
||||
publicTerminal->_focused = false;
|
||||
if (auto uiaEngine = publicTerminal->_uiaEngine.get())
|
||||
{
|
||||
LOG_IF_FAILED(uiaEngine->Disable());
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
#include "../../renderer/uia/UiaRenderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include <UIAutomationCore.h>
|
||||
#include "../../types/IControlAccessibilityInfo.h"
|
||||
#include "../../types/TermControlUiaProvider.hpp"
|
||||
#include "HwndTerminalAutomationPeer.hpp"
|
||||
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
|
||||
@@ -74,15 +74,15 @@ private:
|
||||
FontInfo _actualFont;
|
||||
int _currentDpi;
|
||||
std::function<void(wchar_t*)> _pfnWriteCallback;
|
||||
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
|
||||
::Microsoft::WRL::ComPtr<HwndTerminalAutomationPeer> _uiaProvider;
|
||||
|
||||
std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal;
|
||||
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer;
|
||||
std::unique_ptr<::Microsoft::Console::Render::DxEngine> _renderEngine;
|
||||
std::unique_ptr<::Microsoft::Console::Render::UiaEngine> _uiaEngine;
|
||||
|
||||
bool _focused{ false };
|
||||
bool _uiaProviderInitialized{ false };
|
||||
|
||||
std::chrono::milliseconds _multiClickTime;
|
||||
unsigned int _multiClickCounter{};
|
||||
|
||||
159
src/cascadia/PublicTerminalCore/HwndTerminalAutomationPeer.cpp
Normal file
159
src/cascadia/PublicTerminalCore/HwndTerminalAutomationPeer.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "HwndTerminalAutomationPeer.hpp"
|
||||
#include "../../types/UiaTracing.h"
|
||||
#include <UIAutomationCoreApi.h>
|
||||
|
||||
#pragma warning(suppress : 4471) // We don't control UIAutomationClient
|
||||
#include <UIAutomationClient.h>
|
||||
|
||||
using namespace Microsoft::Console::Types;
|
||||
|
||||
static constexpr wchar_t UNICODE_NEWLINE{ L'\n' };
|
||||
|
||||
// Method Description:
|
||||
// - creates a copy of the provided text with all of the control characters removed
|
||||
// Arguments:
|
||||
// - text: the string we're sanitizing
|
||||
// Return Value:
|
||||
// - a copy of "sanitized" with all of the control characters removed
|
||||
static std::wstring Sanitize(std::wstring_view text)
|
||||
{
|
||||
std::wstring sanitized{ text };
|
||||
sanitized.erase(std::remove_if(sanitized.begin(), sanitized.end(), [](wchar_t c) {
|
||||
return (c < UNICODE_SPACE && c != UNICODE_NEWLINE) || c == 0x7F /*DEL*/;
|
||||
}),
|
||||
sanitized.end());
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - verifies if a given string has text that would be read by a screen reader.
|
||||
// - a string of control characters, for example, would not be read.
|
||||
// Arguments:
|
||||
// - text: the string we're validating
|
||||
// Return Value:
|
||||
// - true, if the text is readable. false, otherwise.
|
||||
static constexpr bool IsReadable(std::wstring_view text)
|
||||
{
|
||||
for (const auto c : text)
|
||||
{
|
||||
if (c > UNICODE_SPACE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HwndTerminalAutomationPeer::RecordKeyEvent(const WORD vkey)
|
||||
{
|
||||
if (const auto charCode{ MapVirtualKey(vkey, MAPVK_VK_TO_CHAR) })
|
||||
{
|
||||
if (const auto keyEventChar{ gsl::narrow_cast<wchar_t>(charCode) }; IsReadable({ &keyEventChar, 1 }))
|
||||
{
|
||||
_keyEvents.emplace_back(keyEventChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of IRawElementProviderSimple::get_PropertyValue.
|
||||
// Gets custom properties.
|
||||
IFACEMETHODIMP HwndTerminalAutomationPeer::GetPropertyValue(_In_ PROPERTYID propertyId,
|
||||
_Out_ VARIANT* pVariant) noexcept
|
||||
{
|
||||
pVariant->vt = VT_EMPTY;
|
||||
|
||||
// Returning the default will leave the property as the default
|
||||
// so we only really need to touch it for the properties we want to implement
|
||||
if (propertyId == UIA_ClassNamePropertyId)
|
||||
{
|
||||
// IMPORTANT: Do NOT change the name. Screen readers like may be dependent on this being "WpfTermControl".
|
||||
pVariant->bstrVal = SysAllocString(L"WPFTermControl");
|
||||
if (pVariant->bstrVal != nullptr)
|
||||
{
|
||||
pVariant->vt = VT_BSTR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// fall back to shared implementation
|
||||
return TermControlUiaProvider::GetPropertyValue(propertyId, pVariant);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the terminal's selection has changed and should be updated
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void HwndTerminalAutomationPeer::SignalSelectionChanged()
|
||||
{
|
||||
UiaTracing::Signal::SelectionChanged();
|
||||
LOG_IF_FAILED(UiaRaiseAutomationEvent(this, UIA_Text_TextSelectionChangedEventId));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the terminal's output has changed and should be updated
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void HwndTerminalAutomationPeer::SignalTextChanged()
|
||||
{
|
||||
UiaTracing::Signal::TextChanged();
|
||||
LOG_IF_FAILED(UiaRaiseAutomationEvent(this, UIA_Text_TextChangedEventId));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the cursor's state has changed and should be updated
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void HwndTerminalAutomationPeer::SignalCursorChanged()
|
||||
{
|
||||
UiaTracing::Signal::CursorChanged();
|
||||
LOG_IF_FAILED(UiaRaiseAutomationEvent(this, UIA_Text_TextSelectionChangedEventId));
|
||||
}
|
||||
|
||||
void HwndTerminalAutomationPeer::NotifyNewOutput(std::wstring_view newOutput)
|
||||
{
|
||||
// Try to suppress any events (or event data)
|
||||
// that is just the keypress the user made
|
||||
auto sanitized{ Sanitize(newOutput) };
|
||||
while (!_keyEvents.empty() && IsReadable(sanitized))
|
||||
{
|
||||
if (til::toupper_ascii(sanitized.front()) == _keyEvents.front())
|
||||
{
|
||||
// the key event's character (i.e. the "A" key) matches
|
||||
// the output character (i.e. "a" or "A" text).
|
||||
// We can assume that the output character resulted from
|
||||
// the pressed key, so we can ignore it.
|
||||
sanitized = sanitized.substr(1);
|
||||
_keyEvents.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The output doesn't match,
|
||||
// so clear the input stack and
|
||||
// move on to fire the event.
|
||||
_keyEvents.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Suppress event if the remaining text is not readable
|
||||
if (!IsReadable(sanitized))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sanitizedBstr = wil::make_bstr_nothrow(sanitized.c_str());
|
||||
static auto activityId = wil::make_bstr_nothrow(L"TerminalTextOutput");
|
||||
LOG_IF_FAILED(UiaRaiseNotificationEvent(this, NotificationKind_ActionCompleted, NotificationProcessing_All, sanitizedBstr.get(), activityId.get()));
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- HwndTerminalAutomationPeer.hpp
|
||||
|
||||
Abstract:
|
||||
- This module provides UI Automation access to the HwndTerminal
|
||||
to support both automation tests and accessibility (screen
|
||||
reading) applications. This mainly interacts with TermControlUiaProvider
|
||||
to allow for shared code with Windows Terminal accessibility providers.
|
||||
|
||||
Author(s):
|
||||
- Carlos Zamora (CaZamor) 2022
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../types/TermControlUiaProvider.hpp"
|
||||
#include "../types/IUiaEventDispatcher.h"
|
||||
#include "../types/IControlAccessibilityInfo.h"
|
||||
|
||||
class HwndTerminalAutomationPeer :
|
||||
public ::Microsoft::Console::Types::IUiaEventDispatcher,
|
||||
public ::Microsoft::Terminal::TermControlUiaProvider
|
||||
{
|
||||
public:
|
||||
void RecordKeyEvent(const WORD vkey);
|
||||
|
||||
IFACEMETHODIMP GetPropertyValue(_In_ PROPERTYID idProp,
|
||||
_Out_ VARIANT* pVariant) noexcept override;
|
||||
|
||||
#pragma region IUiaEventDispatcher
|
||||
void SignalSelectionChanged() override;
|
||||
void SignalTextChanged() override;
|
||||
void SignalCursorChanged() override;
|
||||
void NotifyNewOutput(std::wstring_view newOutput) override;
|
||||
#pragma endregion
|
||||
private:
|
||||
std::deque<wchar_t> _keyEvents;
|
||||
};
|
||||
@@ -15,9 +15,11 @@
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HwndTerminal.cpp" />
|
||||
<ClCompile Include="HwndTerminalAutomationPeer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="HwndTerminal.hpp" />
|
||||
<ClInclude Include="HwndTerminalAutomationPeer.hpp" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -42,6 +44,9 @@
|
||||
<ProjectReference Include="$(SolutionDir)src\api-ms-win-core-synch-l1-2-0\api-ms-win-core-synch-l1-2-0.vcxproj">
|
||||
<Project>{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\renderer\uia\lib\uia.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf63}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
<ClCompile Include="HwndTerminal.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HwndTerminalAutomationPeer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
@@ -32,5 +35,8 @@
|
||||
<ClInclude Include="HwndTerminal.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HwndTerminalAutomationPeer.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -9,3 +9,4 @@
|
||||
#endif
|
||||
|
||||
#include <LibraryIncludes.h>
|
||||
#include <UIAutomationCore.h>
|
||||
@@ -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);
|
||||
|
||||
@@ -25,37 +25,25 @@ static constexpr std::wstring_view VerbName{ L"WindowsTerminalOpenHere" };
|
||||
// failure from an earlier HRESULT.
|
||||
HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
||||
IBindCtx* /*pBindContext*/)
|
||||
try
|
||||
{
|
||||
wil::com_ptr_nothrow<IShellItem> psi;
|
||||
RETURN_IF_FAILED(GetBestLocationFromSelectionOrSite(psiItemArray, psi.put()));
|
||||
if (!psi)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
wil::unique_cotaskmem_string pszName;
|
||||
|
||||
if (psiItemArray == nullptr)
|
||||
{
|
||||
// get the current path from explorer.exe
|
||||
const auto path = this->_GetPathFromExplorer();
|
||||
|
||||
// no go, unable to get a reasonable path
|
||||
if (path.empty())
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
pszName = wil::make_cotaskmem_string(path.c_str(), path.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD count;
|
||||
psiItemArray->GetCount(&count);
|
||||
|
||||
winrt::com_ptr<IShellItem> psi;
|
||||
RETURN_IF_FAILED(psiItemArray->GetItemAt(0, psi.put()));
|
||||
RETURN_IF_FAILED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName));
|
||||
}
|
||||
RETURN_IF_FAILED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName));
|
||||
|
||||
{
|
||||
wil::unique_process_information _piClient;
|
||||
STARTUPINFOEX siEx{ 0 };
|
||||
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
||||
|
||||
auto cmdline{ wil::str_printf<std::wstring>(LR"-("%s" -d %s)-", GetWtExePath().c_str(), QuoteAndEscapeCommandlineArg(pszName.get()).c_str()) };
|
||||
std::wstring cmdline;
|
||||
RETURN_IF_FAILED(wil::str_printf_nothrow(cmdline, LR"-("%s" -d %s)-", GetWtExePath().c_str(), QuoteAndEscapeCommandlineArg(pszName.get()).c_str()));
|
||||
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
nullptr, // lpApplicationName
|
||||
cmdline.data(),
|
||||
@@ -72,6 +60,7 @@ HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
HRESULT OpenTerminalHere::GetToolTip(IShellItemArray* /*psiItemArray*/,
|
||||
LPWSTR* ppszInfoTip)
|
||||
@@ -109,22 +98,14 @@ HRESULT OpenTerminalHere::GetState(IShellItemArray* psiItemArray,
|
||||
// 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
|
||||
// is not at a valid location (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;
|
||||
}
|
||||
wil::com_ptr_nothrow<IShellItem> psi;
|
||||
RETURN_IF_FAILED(GetBestLocationFromSelectionOrSite(psiItemArray, psi.put()));
|
||||
|
||||
SFGAOF attributes;
|
||||
const bool isFileSystemItem = psi && (psi->GetAttributes(SFGAO_FILESYSTEM, &attributes) == S_OK);
|
||||
*pCmdState = isFileSystemItem ? ECS_ENABLED : ECS_HIDDEN;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -160,102 +141,54 @@ HRESULT OpenTerminalHere::EnumSubCommands(IEnumExplorerCommand** ppEnum)
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
std::wstring OpenTerminalHere::_GetPathFromExplorer() const
|
||||
IFACEMETHODIMP OpenTerminalHere::SetSite(IUnknown* site) noexcept
|
||||
{
|
||||
using namespace std;
|
||||
using namespace winrt;
|
||||
|
||||
wstring path;
|
||||
HRESULT hr = NOERROR;
|
||||
|
||||
auto hwnd = ::GetForegroundWindow();
|
||||
if (hwnd == nullptr)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
TCHAR szName[MAX_PATH] = { 0 };
|
||||
::GetClassName(hwnd, szName, MAX_PATH);
|
||||
if (0 == StrCmp(szName, L"WorkerW") ||
|
||||
0 == StrCmp(szName, L"Progman"))
|
||||
{
|
||||
//special folder: desktop
|
||||
hr = ::SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, szName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
path = szName;
|
||||
return path;
|
||||
}
|
||||
|
||||
if (0 != StrCmp(szName, L"CabinetWClass"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
com_ptr<IShellWindows> shell;
|
||||
try
|
||||
{
|
||||
shell = create_instance<IShellWindows>(CLSID_ShellWindows, CLSCTX_ALL);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
//look like try_create_instance is not available no more
|
||||
}
|
||||
|
||||
if (shell == nullptr)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
com_ptr<IDispatch> disp;
|
||||
wil::unique_variant variant;
|
||||
variant.vt = VT_I4;
|
||||
|
||||
com_ptr<IWebBrowserApp> browser;
|
||||
// look for correct explorer window
|
||||
for (variant.intVal = 0;
|
||||
shell->Item(variant, disp.put()) == S_OK;
|
||||
variant.intVal++)
|
||||
{
|
||||
com_ptr<IWebBrowserApp> tmp;
|
||||
if (FAILED(disp->QueryInterface(tmp.put())))
|
||||
{
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
continue;
|
||||
}
|
||||
|
||||
HWND tmpHWND = NULL;
|
||||
hr = tmp->get_HWND(reinterpret_cast<SHANDLE_PTR*>(&tmpHWND));
|
||||
if (hwnd == tmpHWND)
|
||||
{
|
||||
browser = tmp;
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
break; //found
|
||||
}
|
||||
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
}
|
||||
|
||||
if (browser != nullptr)
|
||||
{
|
||||
wil::unique_bstr url;
|
||||
hr = browser->get_LocationURL(&url);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
wstring sUrl(url.get(), SysStringLen(url.get()));
|
||||
DWORD size = MAX_PATH;
|
||||
hr = ::PathCreateFromUrl(sUrl.c_str(), szName, &size, NULL);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
path = szName;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
site_ = site;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OpenTerminalHere::GetSite(REFIID riid, void** site) noexcept
|
||||
{
|
||||
RETURN_IF_FAILED(site_.query_to(riid, site));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OpenTerminalHere::GetLocationFromSite(IShellItem** location) const noexcept
|
||||
{
|
||||
wil::assign_null_to_opt_param(location);
|
||||
|
||||
if (!site_)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IServiceProvider> serviceProvider;
|
||||
RETURN_IF_FAILED(site_.query_to(serviceProvider.put()));
|
||||
wil::com_ptr_nothrow<IFolderView> folderView;
|
||||
RETURN_IF_FAILED(serviceProvider->QueryService(SID_SFolderView, IID_PPV_ARGS(folderView.put())));
|
||||
RETURN_IF_FAILED(folderView->GetFolder(IID_PPV_ARGS(location)));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OpenTerminalHere::GetBestLocationFromSelectionOrSite(IShellItemArray* psiArray, IShellItem** location) const noexcept
|
||||
{
|
||||
wil::com_ptr_nothrow<IShellItem> psi;
|
||||
if (psiArray)
|
||||
{
|
||||
DWORD count{};
|
||||
RETURN_IF_FAILED(psiArray->GetCount(&count));
|
||||
if (count) // Sometimes we get an array with a count of 0. Fall back to the site chain.
|
||||
{
|
||||
RETURN_IF_FAILED(psiArray->GetItemAt(0, psi.put()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!psi)
|
||||
{
|
||||
RETURN_IF_FAILED(GetLocationFromSite(psi.put()));
|
||||
}
|
||||
|
||||
RETURN_HR_IF(S_FALSE, !psi);
|
||||
RETURN_IF_FAILED(psi.copy_to(location));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@ Author(s):
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include <conattrs.hpp>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
struct
|
||||
@@ -34,7 +32,7 @@ struct
|
||||
#else // DEV
|
||||
__declspec(uuid("52065414-e077-47ec-a3ac-1cc5455e1b54"))
|
||||
#endif
|
||||
OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom | InhibitFtmBase>, IExplorerCommand>
|
||||
OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom | InhibitFtmBase>, IExplorerCommand, IObjectWithSite>
|
||||
{
|
||||
#pragma region IExplorerCommand
|
||||
STDMETHODIMP Invoke(IShellItemArray* psiItemArray,
|
||||
@@ -52,9 +50,16 @@ struct
|
||||
STDMETHODIMP GetCanonicalName(GUID* pguidCommandName);
|
||||
STDMETHODIMP EnumSubCommands(IEnumExplorerCommand** ppEnum);
|
||||
#pragma endregion
|
||||
#pragma region IObjectWithSite
|
||||
IFACEMETHODIMP SetSite(IUnknown* site) noexcept;
|
||||
IFACEMETHODIMP GetSite(REFIID riid, void** site) noexcept;
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
std::wstring _GetPathFromExplorer() const;
|
||||
HRESULT GetLocationFromSite(IShellItem** location) const noexcept;
|
||||
HRESULT GetBestLocationFromSelectionOrSite(IShellItemArray* psiArray, IShellItem** location) const noexcept;
|
||||
|
||||
wil::com_ptr_nothrow<IUnknown> site_;
|
||||
};
|
||||
|
||||
CoCreatableClass(OpenTerminalHere);
|
||||
|
||||
@@ -201,10 +201,11 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
const auto& duplicateFromTab{ realArgs.SplitMode() == SplitType::Duplicate ? _GetFocusedTab() : nullptr };
|
||||
_SplitPane(realArgs.SplitDirection(),
|
||||
// This is safe, we're already filtering so the value is (0, 1)
|
||||
::base::saturated_cast<float>(realArgs.SplitSize()),
|
||||
_MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
|
||||
_MakePane(realArgs.TerminalArgs(), duplicateFromTab));
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
@@ -606,7 +607,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
activeTab->ActivateColorPicker();
|
||||
activeTab->RequestColorPicker();
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include <WtExeUtils.h>
|
||||
#include <wil/token_helpers.h >
|
||||
#include <wil/token_helpers.h>
|
||||
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
@@ -292,10 +292,36 @@ namespace winrt::TerminalApp::implementation
|
||||
_root->Maximized(true);
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode))
|
||||
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode) && !IsQuakeWindow())
|
||||
{
|
||||
_root->SetFullscreen(true);
|
||||
}
|
||||
|
||||
FILETIME creationTime, exitTime, kernelTime, userTime, now;
|
||||
if (GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime, &userTime))
|
||||
{
|
||||
static constexpr auto asInteger = [](const FILETIME& f) {
|
||||
ULARGE_INTEGER i;
|
||||
i.LowPart = f.dwLowDateTime;
|
||||
i.HighPart = f.dwHighDateTime;
|
||||
return i.QuadPart;
|
||||
};
|
||||
static constexpr auto asSeconds = [](uint64_t v) {
|
||||
return v * 1e-7f;
|
||||
};
|
||||
|
||||
GetSystemTimeAsFileTime(&now);
|
||||
|
||||
const auto latency = asSeconds(asInteger(now) - asInteger(creationTime));
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"AppInitialized",
|
||||
TraceLoggingDescription("Event emitted once the app is initialized"),
|
||||
TraceLoggingFloat32(latency, "latency"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
});
|
||||
_root->Create();
|
||||
|
||||
@@ -312,7 +338,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingDescription("Event emitted when the application is started"),
|
||||
TraceLoggingBool(_settings.GlobalSettings().ShowTabsInTitlebar(), "TabsInTitlebar"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
void AppLogic::Quit()
|
||||
@@ -504,26 +530,8 @@ namespace winrt::TerminalApp::implementation
|
||||
if (keyboardServiceIsDisabled)
|
||||
{
|
||||
_root->ShowKeyboardServiceWarning();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"KeyboardServiceWasDisabled",
|
||||
TraceLoggingDescription("Event emitted when the keyboard service is disabled, and we warned them about it"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For when the warning was disabled in the settings
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"KeyboardServiceWarningWasDisabledBySetting",
|
||||
TraceLoggingDescription("Event emitted when the user has disabled the KB service warning"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
|
||||
if (FAILED(_settingsLoadedResult))
|
||||
{
|
||||
@@ -557,7 +565,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// not be noisy with this dialog if we failed for some reason.
|
||||
|
||||
// Open the service manager. This will return 0 if it failed.
|
||||
wil::unique_schandle hManager{ OpenSCManager(nullptr, nullptr, 0) };
|
||||
wil::unique_schandle hManager{ OpenSCManagerW(nullptr, nullptr, 0) };
|
||||
|
||||
if (LOG_LAST_ERROR_IF(!hManager.is_valid()))
|
||||
{
|
||||
@@ -565,8 +573,12 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Get a handle to the keyboard service
|
||||
wil::unique_schandle hService{ OpenService(hManager.get(), TabletInputServiceKey.data(), SERVICE_QUERY_STATUS) };
|
||||
if (LOG_LAST_ERROR_IF(!hService.is_valid()))
|
||||
wil::unique_schandle hService{ OpenServiceW(hManager.get(), TabletInputServiceKey.data(), SERVICE_QUERY_STATUS) };
|
||||
|
||||
// Windows 11 doesn't have a TabletInputService.
|
||||
// (It was renamed to TextInputManagementService, because people kept thinking that a
|
||||
// service called "tablet-something" is system-irrelevant on PCs and can be disabled.)
|
||||
if (!hService.is_valid())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -851,15 +863,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// happening during startup, it'll need to happen on a background thread.
|
||||
void AppLogic::LoadSettings()
|
||||
{
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"SettingsLoadStarted",
|
||||
TraceLoggingDescription("Event emitted before loading the settings"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
// Attempt to load the settings.
|
||||
// If it fails,
|
||||
// - use Default settings,
|
||||
@@ -875,17 +878,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_settings = CascadiaSettings::LoadDefaults();
|
||||
}
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> delta = end - start;
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"SettingsLoadComplete",
|
||||
TraceLoggingDescription("Event emitted when loading the settings is finished"),
|
||||
TraceLoggingFloat64(delta.count(), "Duration"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
_loadedInitialSettings = true;
|
||||
|
||||
// Register for directory change notification.
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingDescription("Event emitted when the Command Palette is opened"),
|
||||
TraceLoggingWideString(L"Action", "Mode", "which mode the palette was opened in"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -474,7 +474,13 @@ namespace winrt::TerminalApp::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
auto focusedElementOrAncestor = Input::FocusManager::GetFocusedElement(this->XamlRoot()).try_as<DependencyObject>();
|
||||
auto root = this->XamlRoot();
|
||||
if (!root)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto focusedElementOrAncestor = Input::FocusManager::GetFocusedElement(root).try_as<DependencyObject>();
|
||||
while (focusedElementOrAncestor)
|
||||
{
|
||||
if (focusedElementOrAncestor == *this)
|
||||
@@ -524,6 +530,34 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPalette::_listItemSelectionChanged(const Windows::Foundation::IInspectable& /*sender*/, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& e)
|
||||
{
|
||||
// We don't care about...
|
||||
// - CommandlineMode: it doesn't have any selectable items in the list view
|
||||
// - TabSwitchMode: focus and selected item are in sync
|
||||
if (_currentMode == CommandPaletteMode::ActionMode || _currentMode == CommandPaletteMode::TabSearchMode)
|
||||
{
|
||||
if (auto automationPeer{ Automation::Peers::FrameworkElementAutomationPeer::FromElement(_searchBox()) })
|
||||
{
|
||||
if (const auto selectedList = e.AddedItems(); selectedList.Size() > 0)
|
||||
{
|
||||
const auto selectedCommand = selectedList.GetAt(0);
|
||||
if (const auto filteredCmd = selectedCommand.try_as<TerminalApp::FilteredCommand>())
|
||||
{
|
||||
if (const auto paletteItem = filteredCmd.Item().try_as<TerminalApp::PaletteItem>())
|
||||
{
|
||||
automationPeer.RaiseNotificationEvent(
|
||||
Automation::Peers::AutomationNotificationKind::ItemAdded,
|
||||
Automation::Peers::AutomationNotificationProcessing::MostRecent,
|
||||
paletteItem.Name() + L" " + paletteItem.KeyChordText(),
|
||||
L"CommandPaletteSelectedItemChanged" /* unique name for this notification category */);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// This event is called when the user clicks on an ChevronLeft button right
|
||||
// next to the ParentCommandName (e.g. New Tab...) above the subcommands list.
|
||||
@@ -677,7 +711,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingUInt32(searchTextLength, "SearchTextLength", "Number of characters in the search string"),
|
||||
TraceLoggingUInt32(nestedCommandDepth, "NestedCommandDepth", "the depth in the tree of commands for the dispatched action"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -745,7 +779,7 @@ namespace winrt::TerminalApp::implementation
|
||||
"CommandPaletteDispatchedCommandline",
|
||||
TraceLoggingDescription("Event emitted when the user runs a commandline in the Command Palette"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
if (const auto commandLinePaletteItem{ filteredCommand.value().Item().try_as<winrt::TerminalApp::CommandLinePaletteItem>() })
|
||||
{
|
||||
@@ -783,7 +817,7 @@ namespace winrt::TerminalApp::implementation
|
||||
"CommandPaletteDismissed",
|
||||
TraceLoggingDescription("Event emitted when the user dismisses the Command Palette without selecting an action"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -92,6 +92,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _listItemClicked(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::ItemClickEventArgs& e);
|
||||
|
||||
void _listItemSelectionChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& e);
|
||||
|
||||
void _moveBackButtonClicked(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs&);
|
||||
|
||||
void _updateFilteredActions();
|
||||
|
||||
@@ -402,6 +402,7 @@
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="_listItemClicked"
|
||||
ItemsSource="{x:Bind FilteredActions}"
|
||||
SelectionChanged="_listItemSelectionChanged"
|
||||
SelectionMode="Single" />
|
||||
|
||||
</Grid>
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -20,70 +20,73 @@
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Color x:Key="CloseButtonColor">#C42B1C</Color>
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">1.0</x:Double>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"
|
||||
ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="CaptionButtonStroke"
|
||||
<StaticResource x:Key="CaptionButtonForeground"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonStrokeColor"
|
||||
<StaticResource x:Key="CaptionButtonForegroundColor"
|
||||
ResourceKey="SystemBaseHighColor" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground"
|
||||
Color="Transparent" />
|
||||
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource CloseButtonColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPointerOver"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed"
|
||||
Opacity="0.9"
|
||||
Color="{ThemeResource CloseButtonColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPressed"
|
||||
Opacity="0.7"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackground"
|
||||
Color="#00e81123" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00e81123</Color>
|
||||
Color="#00C42B1C" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00C42B1C</Color>
|
||||
|
||||
<StaticResource x:Key="RestoreButtonGlyph"
|
||||
ResourceKey="RestoreGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<Color x:Key="CloseButtonColor">#C42B1C</Color>
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">1.0</x:Double>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"
|
||||
ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="CaptionButtonStroke"
|
||||
<StaticResource x:Key="CaptionButtonForeground"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonStrokeColor"
|
||||
<StaticResource x:Key="CaptionButtonForegroundColor"
|
||||
ResourceKey="SystemBaseHighColor" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground"
|
||||
Color="Transparent" />
|
||||
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource CloseButtonColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPointerOver"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed"
|
||||
Opacity="0.9"
|
||||
Color="{ThemeResource CloseButtonColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPressed"
|
||||
Opacity="0.7"
|
||||
Color="White" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackground"
|
||||
Color="#00e81123" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00e81123</Color>
|
||||
Color="#00C42B1C" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00C42B1C</Color>
|
||||
|
||||
<StaticResource x:Key="RestoreButtonGlyph"
|
||||
ResourceKey="RestoreGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">2.0</x:Double>
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground"
|
||||
Color="{ThemeResource SystemColorButtonFaceColor}" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundColor"
|
||||
@@ -92,32 +95,43 @@
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonBackgroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonStroke"
|
||||
<SolidColorBrush x:Key="CaptionButtonForeground"
|
||||
Color="{ThemeResource SystemColorButtonTextColor}" />
|
||||
<StaticResource x:Key="CaptionButtonStrokeColor"
|
||||
<StaticResource x:Key="CaptionButtonForegroundColor"
|
||||
ResourceKey="SystemColorButtonTextColor" />
|
||||
<SolidColorBrush x:Key="CaptionButtonStrokePointerOver"
|
||||
<SolidColorBrush x:Key="CaptionButtonForegroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonStrokePressed"
|
||||
<SolidColorBrush x:Key="CaptionButtonForegroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed"
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
|
||||
<StaticResource x:Key="RestoreButtonGlyph"
|
||||
ResourceKey="RestoreGlyphContrast" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<!--
|
||||
These strings need to be initialized to something, so they're
|
||||
just initialized to the path for the close button. Each specific
|
||||
button should override them as needed.
|
||||
Initializes the string to the close button glyph.
|
||||
Each specific button overrides it as needed.
|
||||
-->
|
||||
<x:String x:Key="CaptionButtonPath">M 0 0 L 10 10 M 10 0 L 0 10</x:String>
|
||||
<x:String x:Key="CaptionButtonPathWindowMaximized">M 0 0 L 10 10 M 10 0 L 0 10</x:String>
|
||||
<x:String x:Key="CaptionButtonGlyph"></x:String>
|
||||
|
||||
<x:String x:Key="MinimizeGlyph"></x:String>
|
||||
<x:String x:Key="MaximizeGlyph"></x:String>
|
||||
<x:String x:Key="RestoreGlyph"></x:String>
|
||||
<x:String x:Key="CloseGlyph"></x:String>
|
||||
|
||||
<x:String x:Key="MinimizeGlyphContrast"></x:String>
|
||||
<x:String x:Key="MaximizeGlyphContrast"></x:String>
|
||||
<x:String x:Key="RestoreGlyphContrast"></x:String>
|
||||
<x:String x:Key="CloseGlyphContrast"></x:String>
|
||||
|
||||
<!--
|
||||
"CaptionButtonHeightWindowed" and
|
||||
@@ -151,16 +165,13 @@
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<Path x:Name="Path"
|
||||
Width="10"
|
||||
Height="10"
|
||||
Data="{ThemeResource CaptionButtonPath}"
|
||||
Stretch="Fill"
|
||||
Stroke="{ThemeResource CaptionButtonStroke}"
|
||||
StrokeEndLineCap="Square"
|
||||
StrokeStartLineCap="Square"
|
||||
StrokeThickness="{ThemeResource CaptionButtonStrokeWidth}"
|
||||
UseLayoutRounding="True" />
|
||||
<Viewbox Width="10"
|
||||
Height="10">
|
||||
<FontIcon x:Name="ButtonIcon"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
Foreground="{ThemeResource CaptionButtonForeground}"
|
||||
Glyph="{ThemeResource CaptionButtonGlyph}" />
|
||||
</Viewbox>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
@@ -172,9 +183,9 @@
|
||||
Storyboard.TargetProperty="(UIElement.Background).(SolidColorBrush.Color)"
|
||||
To="{ThemeResource CaptionButtonBackgroundColor}"
|
||||
Duration="0:0:0.15" />
|
||||
<ColorAnimation Storyboard.TargetName="Path"
|
||||
Storyboard.TargetProperty="(UIElement.Stroke).(SolidColorBrush.Color)"
|
||||
To="{ThemeResource CaptionButtonStrokeColor}"
|
||||
<ColorAnimation Storyboard.TargetName="ButtonIcon"
|
||||
Storyboard.TargetProperty="(UIElement.Foreground).(SolidColorBrush.Color)"
|
||||
To="{ThemeResource CaptionButtonForegroundColor}"
|
||||
Duration="0:0:0.1" />
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
@@ -183,21 +194,21 @@
|
||||
<VisualState x:Name="Normal">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackground}" />
|
||||
<Setter Target="Path.Stroke" Value="{ThemeResource CaptionButtonStroke}" />
|
||||
<Setter Target="ButtonIcon.Foreground" Value="{ThemeResource CaptionButtonForeground}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackgroundPointerOver}" />
|
||||
<Setter Target="Path.Stroke" Value="{ThemeResource CaptionButtonStrokePointerOver}" />
|
||||
<Setter Target="ButtonIcon.Foreground" Value="{ThemeResource CaptionButtonForegroundPointerOver}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackgroundPressed}" />
|
||||
<Setter Target="Path.Stroke" Value="{ThemeResource CaptionButtonStrokePressed}" />
|
||||
<Setter Target="ButtonIcon.Foreground" Value="{ThemeResource CaptionButtonForegroundPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
@@ -209,7 +220,7 @@
|
||||
|
||||
<VisualState x:Name="WindowStateMaximized">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Path.Data" Value="{ThemeResource CaptionButtonPathWindowMaximized}" />
|
||||
<Setter Target="ButtonIcon.Glyph" Value="{ThemeResource RestoreButtonGlyph}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
@@ -235,7 +246,20 @@
|
||||
Style="{StaticResource CaptionButton}">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
<x:String x:Key="CaptionButtonPath">M 0 0 H 10</x:String>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MinimizeGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MinimizeGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MinimizeGlyphContrast" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
<ToolTipService.ToolTip>
|
||||
@@ -253,10 +277,21 @@
|
||||
Click="_MaximizeClick"
|
||||
Style="{StaticResource CaptionButton}">
|
||||
<Button.Resources>
|
||||
<!-- These paths are complicated, but taken directly from WinUI's WindowCaptionButton paths. -->
|
||||
<ResourceDictionary>
|
||||
<x:String x:Key="CaptionButtonPath">M 1.516 -0.001 L 7.451 0.009 C 8.751 0.019 9 1 8.981 1.477 L 9.002 7.558 M 9.002 7.547 C 8.929 8.669 8 9 7.43 9.015 L 1.464 9.005 C 0.374 8.973 0 8 -0.004 7.484 L -0.004 1.477 C 0 1 0.415 0.009 1.527 -0.001</x:String>
|
||||
<x:String x:Key="CaptionButtonPathWindowMaximized">M 1.516 -0.001 L 7.451 0.009 C 8.751 0.019 9 1 8.981 1.477 L 9.002 7.558 M 11 6 L 11 2 C 11 0 10 -2 8.011 -1.946 L 7.06 -1.969 L 3 -2 M 9.002 7.547 C 8.929 8.669 8 9 7.43 9.015 L 1.464 9.005 C 0.374 8.973 0 8 -0.004 7.484 L -0.004 1.477 C 0 1 0.415 0.009 1.527 -0.001</x:String>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MaximizeGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MaximizeGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="MaximizeGlyphContrast" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
<ToolTipService.ToolTip>
|
||||
@@ -283,42 +318,46 @@
|
||||
ResourceKey="CloseButtonBackgroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="CloseButtonBackgroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
ResourceKey="CloseButtonStrokePointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
ResourceKey="CloseButtonStrokePressed" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="CloseButtonForegroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="CloseButtonForegroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonBackground"
|
||||
ResourceKey="CloseButtonBackground" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundColor"
|
||||
ResourceKey="CloseButtonBackgroundColor" />
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="CloseGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"
|
||||
ResourceKey="CloseButtonBackgroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="CloseButtonBackgroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
ResourceKey="CloseButtonStrokePointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
ResourceKey="CloseButtonStrokePressed" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="CloseButtonForegroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="CloseButtonForegroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonBackground"
|
||||
ResourceKey="CloseButtonBackground" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundColor"
|
||||
ResourceKey="CloseButtonBackgroundColor" />
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="CloseGlyph" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"
|
||||
ResourceKey="CloseButtonBackgroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed"
|
||||
ResourceKey="CloseButtonBackgroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver"
|
||||
ResourceKey="CloseButtonStrokePointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed"
|
||||
ResourceKey="CloseButtonStrokePressed" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPointerOver"
|
||||
ResourceKey="CloseButtonForegroundPointerOver" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="CloseButtonForegroundPressed" />
|
||||
<StaticResource x:Key="CaptionButtonGlyph"
|
||||
ResourceKey="CloseGlyphContrast" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<x:String x:Key="CaptionButtonPath">M 0 0 L 10 10 M 10 0 L 0 10</x:String>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
<ToolTipService.ToolTip>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "TerminalPage.h"
|
||||
#include "Utils.h"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
#include "../../inc/til/string.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
|
||||
@@ -85,34 +86,7 @@ namespace winrt::TerminalApp::implementation
|
||||
//
|
||||
// This call to _MakePane won't return nullptr, we already checked that
|
||||
// case above with the _maybeElevate call.
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, existingConnection));
|
||||
|
||||
const auto tabCount = _tabs.Size();
|
||||
const auto usedManualProfile = (newTerminalArgs != nullptr) &&
|
||||
(newTerminalArgs.ProfileIndex() != nullptr ||
|
||||
newTerminalArgs.Profile().empty());
|
||||
|
||||
// Lookup the name of the color scheme used by this profile.
|
||||
const auto scheme = _settings.GetColorSchemeForProfile(profile);
|
||||
// If they explicitly specified `null` as the scheme (indicating _no_ scheme), log
|
||||
// that as the empty string.
|
||||
const auto schemeName = scheme ? scheme.Name() : L"\0";
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
|
||||
"TabInformation",
|
||||
TraceLoggingDescription("Event emitted upon new tab creation in TerminalApp"),
|
||||
TraceLoggingUInt32(1u, "EventVer", "Version of this event"),
|
||||
TraceLoggingUInt32(tabCount, "TabCount", "Count of tabs currently opened in TerminalApp"),
|
||||
TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
|
||||
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"),
|
||||
TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"),
|
||||
TraceLoggingFloat64(settings.DefaultSettings().Opacity(), "TintOpacity", "Opacity preference from the settings"),
|
||||
TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"),
|
||||
TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, nullptr, existingConnection));
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
@@ -348,7 +322,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// In the future, it may be preferable to just duplicate the
|
||||
// current control's live settings (which will include changes
|
||||
// made through VT).
|
||||
_CreateNewTabFromPane(_MakePane(nullptr, true, nullptr));
|
||||
_CreateNewTabFromPane(_MakePane(nullptr, tab, nullptr));
|
||||
|
||||
const auto runtimeTabText{ tab.GetTabText() };
|
||||
if (!runtimeTabText.empty())
|
||||
@@ -371,7 +345,7 @@ namespace winrt::TerminalApp::implementation
|
||||
try
|
||||
{
|
||||
_SetFocusedTab(tab);
|
||||
_SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true));
|
||||
_SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, tab));
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -404,7 +378,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// GH#11356 - we can't use the UWP apis for writing the file,
|
||||
// because they don't work elevated (shocker) So just use the
|
||||
// shell32 file picker manually.
|
||||
path = co_await SaveFilePicker(*_hostingHwnd, [control](auto&& dialog) {
|
||||
std::wstring filename{ tab.Title() };
|
||||
path = co_await SaveFilePicker(*_hostingHwnd, [filename = std::move(filename)](auto&& dialog) mutable {
|
||||
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExportFile));
|
||||
try
|
||||
{
|
||||
@@ -418,7 +393,8 @@ namespace winrt::TerminalApp::implementation
|
||||
THROW_IF_FAILED(dialog->SetDefaultExtension(L"txt"));
|
||||
|
||||
// Default to using the tab title as the file name
|
||||
THROW_IF_FAILED(dialog->SetFileName((control.Title() + L".txt").c_str()));
|
||||
filename = til::clean_filename(filename);
|
||||
THROW_IF_FAILED(dialog->SetFileName((filename + L".txt").c_str()));
|
||||
});
|
||||
}
|
||||
else
|
||||
|
||||
@@ -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,17 +20,11 @@
|
||||
<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" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<!-- For CLI11: It uses dynamic_cast to cast types around, which depends
|
||||
on being compiled with RTTI (/GR). -->
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<!-- ========================= XAML files ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- HERE BE DRAGONS:
|
||||
@@ -407,13 +401,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.
|
||||
|
||||
@@ -511,7 +511,7 @@ namespace winrt::TerminalApp::implementation
|
||||
"NewTabByDragDrop",
|
||||
TraceLoggingDescription("Event emitted when the user drag&drops onto the new tab button"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1178,7 +1178,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The profile's GUID"),
|
||||
TraceLoggingGuid(sessionGuid, "SessionGuid", "The WT_SESSION's GUID"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return connection;
|
||||
}
|
||||
@@ -1326,6 +1326,29 @@ namespace winrt::TerminalApp::implementation
|
||||
e.Handled(true);
|
||||
}
|
||||
|
||||
bool TerminalPage::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down)
|
||||
{
|
||||
const auto modifiers = _GetPressedModifierKeys();
|
||||
if (vkey == VK_SPACE && modifiers.IsAltPressed() && down)
|
||||
{
|
||||
if (const auto actionMap = _settings.ActionMap())
|
||||
{
|
||||
if (const auto cmd = actionMap.GetActionByKeyChord({
|
||||
modifiers.IsCtrlPressed(),
|
||||
modifiers.IsAltPressed(),
|
||||
modifiers.IsShiftPressed(),
|
||||
modifiers.IsWinPressed(),
|
||||
gsl::narrow_cast<int32_t>(vkey),
|
||||
scanCode,
|
||||
}))
|
||||
{
|
||||
return _actionDispatch->DoAction(cmd.ActionAndArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the modifier keys that are currently pressed. This can be used to
|
||||
// find out which modifiers (ctrl, alt, shift) are pressed in events that
|
||||
@@ -1531,6 +1554,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 });
|
||||
@@ -2500,8 +2537,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// - newTerminalArgs: an object that may contain a blob of parameters to
|
||||
// control which profile is created and with possible other
|
||||
// configurations. See CascadiaSettings::BuildSettings for more details.
|
||||
// - duplicate: a boolean to indicate whether the pane we create should be
|
||||
// a duplicate of the currently focused pane
|
||||
// - sourceTab: an optional tab reference that indicates that the created
|
||||
// pane should be a duplicate of the tab's focused pane
|
||||
// - existingConnection: optionally receives a connection from the outside
|
||||
// world instead of attempting to create one
|
||||
// Return Value:
|
||||
@@ -2509,29 +2546,25 @@ namespace winrt::TerminalApp::implementation
|
||||
// connection, then we'll return nullptr. Otherwise, we'll return a new
|
||||
// Pane for this connection.
|
||||
std::shared_ptr<Pane> TerminalPage::_MakePane(const NewTerminalArgs& newTerminalArgs,
|
||||
const bool duplicate,
|
||||
const winrt::TerminalApp::TabBase& sourceTab,
|
||||
TerminalConnection::ITerminalConnection existingConnection)
|
||||
{
|
||||
TerminalSettingsCreateResult controlSettings{ nullptr };
|
||||
Profile profile{ nullptr };
|
||||
|
||||
if (duplicate)
|
||||
if (const auto& terminalTab{ _GetTerminalTabImpl(sourceTab) })
|
||||
{
|
||||
const auto focusedTab{ _GetFocusedTabImpl() };
|
||||
if (focusedTab)
|
||||
profile = terminalTab->GetFocusedProfile();
|
||||
if (profile)
|
||||
{
|
||||
profile = focusedTab->GetFocusedProfile();
|
||||
if (profile)
|
||||
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
|
||||
profile = GetClosestProfileForDuplicationOfProfile(profile);
|
||||
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
|
||||
const auto workingDirectory = terminalTab->GetActiveTerminalControl().WorkingDirectory();
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
{
|
||||
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
|
||||
profile = GetClosestProfileForDuplicationOfProfile(profile);
|
||||
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
|
||||
const auto workingDirectory = focusedTab->GetActiveTerminalControl().WorkingDirectory();
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
{
|
||||
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
|
||||
}
|
||||
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3264,13 +3297,18 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
NewTerminalArgs newTerminalArgs;
|
||||
newTerminalArgs.Commandline(connection.Commandline());
|
||||
newTerminalArgs.TabTitle(connection.StartingTitle());
|
||||
// GH #12370: We absolutely cannot allow a defterm connection to
|
||||
// auto-elevate. Defterm doesn't work for elevated scenarios in the
|
||||
// first place. If we try accepting the connection, the spawning an
|
||||
// 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, nullptr, connection);
|
||||
newPane->WalkTree([](auto pane) {
|
||||
pane->FinalizeConfigurationGivenDefault();
|
||||
});
|
||||
_CreateNewTabFromPane(newPane);
|
||||
|
||||
// Request a summon of this window to the foreground
|
||||
_SummonWindowRequestedHandlers(*this, nullptr);
|
||||
@@ -3457,7 +3495,6 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
|
||||
{
|
||||
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipPresented", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
infoBar.IsOpen(true);
|
||||
}
|
||||
}
|
||||
@@ -3482,7 +3519,7 @@ namespace winrt::TerminalApp::implementation
|
||||
return winrt::hstring{ TabletInputServiceKey };
|
||||
}
|
||||
|
||||
wil::unique_schandle hManager{ OpenSCManager(nullptr, nullptr, 0) };
|
||||
wil::unique_schandle hManager{ OpenSCManagerW(nullptr, nullptr, 0) };
|
||||
|
||||
if (LOG_LAST_ERROR_IF(!hManager.is_valid()))
|
||||
{
|
||||
@@ -3490,15 +3527,24 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
DWORD cchBuffer = 0;
|
||||
GetServiceDisplayName(hManager.get(), TabletInputServiceKey.data(), nullptr, &cchBuffer);
|
||||
const auto ok = GetServiceDisplayNameW(hManager.get(), TabletInputServiceKey.data(), nullptr, &cchBuffer);
|
||||
|
||||
// Windows 11 doesn't have a TabletInputService.
|
||||
// (It was renamed to TextInputManagementService, because people kept thinking that a
|
||||
// service called "tablet-something" is system-irrelevant on PCs and can be disabled.)
|
||||
if (ok || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
return winrt::hstring{ TabletInputServiceKey };
|
||||
}
|
||||
|
||||
std::wstring buffer;
|
||||
cchBuffer += 1; // Add space for a null
|
||||
buffer.resize(cchBuffer);
|
||||
|
||||
if (LOG_LAST_ERROR_IF(!GetServiceDisplayName(hManager.get(),
|
||||
TabletInputServiceKey.data(),
|
||||
buffer.data(),
|
||||
&cchBuffer)))
|
||||
if (LOG_LAST_ERROR_IF(!GetServiceDisplayNameW(hManager.get(),
|
||||
TabletInputServiceKey.data(),
|
||||
buffer.data(),
|
||||
&cchBuffer)))
|
||||
{
|
||||
return winrt::hstring{ TabletInputServiceKey };
|
||||
}
|
||||
|
||||
@@ -135,6 +135,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void OpenSettingsUI();
|
||||
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
@@ -171,6 +173,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 };
|
||||
|
||||
@@ -378,7 +381,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
|
||||
|
||||
std::shared_ptr<Pane> _MakePane(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr,
|
||||
const bool duplicate = false,
|
||||
const winrt::TerminalApp::TabBase& sourceTab = nullptr,
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
|
||||
void _RefreshUIForSettingsReload();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
import "TaskbarState.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
@@ -16,7 +17,7 @@ namespace TerminalApp
|
||||
Windows.Foundation.IAsyncOperation<Windows.UI.Xaml.Controls.ContentDialogResult> ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog);
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
[default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged, IDirectKeyListener
|
||||
{
|
||||
TerminalPage();
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -264,13 +264,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
if (_state == AzureState::TermConnected)
|
||||
{
|
||||
// Close the websocket connection
|
||||
auto closedTask = _cloudShellSocket.close();
|
||||
closedTask.wait();
|
||||
_cloudShellSocket.close();
|
||||
}
|
||||
|
||||
if (_hOutputThread)
|
||||
{
|
||||
// Tear down our output thread
|
||||
// Waiting for the output thread to exit ensures that all pending _TerminalOutputHandlers()
|
||||
// calls have returned and won't notify our caller (ControlCore) anymore. This ensures that
|
||||
// we don't call a destroyed event handler asynchronously from a background thread (GH#13880).
|
||||
WaitForSingleObject(_hOutputThread.get(), INFINITE);
|
||||
_hOutputThread.reset();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -97,18 +102,20 @@ static HRESULT _duplicateHandle(const HANDLE in, HANDLE& out) noexcept
|
||||
// - E_NOT_VALID_STATE if a event handler is not registered before calling. `::DuplicateHandle`
|
||||
// error codes if we cannot manage to make our own copy of handles to retain. Or S_OK/error
|
||||
// from the registered handler event function.
|
||||
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client)
|
||||
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client, TERMINAL_STARTUP_INFO startupInfo)
|
||||
{
|
||||
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);
|
||||
@@ -125,7 +132,7 @@ HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE sign
|
||||
THROW_IF_FAILED(_duplicateHandle(client, client));
|
||||
|
||||
// Call registered handler from when we started listening.
|
||||
THROW_IF_FAILED(localPfnHandoff(in, out, signal, ref, server, client));
|
||||
THROW_IF_FAILED(localPfnHandoff(in, out, signal, ref, server, client, startupInfo));
|
||||
|
||||
#pragma warning(suppress : 26477)
|
||||
TraceLoggingWrite(
|
||||
|
||||
@@ -26,10 +26,10 @@ Author(s):
|
||||
#define __CLSID_CTerminalHandoff "051F34EE-C1FD-4B19-AF75-9BA54648434C"
|
||||
#endif
|
||||
|
||||
using NewHandoffFunction = HRESULT (*)(HANDLE, HANDLE, HANDLE, HANDLE, HANDLE, HANDLE);
|
||||
using NewHandoffFunction = HRESULT (*)(HANDLE, HANDLE, HANDLE, HANDLE, HANDLE, HANDLE, TERMINAL_STARTUP_INFO);
|
||||
|
||||
struct __declspec(uuid(__CLSID_CTerminalHandoff))
|
||||
CTerminalHandoff : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::ClassicCom>, ITerminalHandoff>
|
||||
CTerminalHandoff : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::ClassicCom>, ITerminalHandoff2>
|
||||
{
|
||||
#pragma region ITerminalHandoff
|
||||
STDMETHODIMP EstablishPtyHandoff(HANDLE in,
|
||||
@@ -37,12 +37,16 @@ struct __declspec(uuid(__CLSID_CTerminalHandoff))
|
||||
HANDLE signal,
|
||||
HANDLE ref,
|
||||
HANDLE server,
|
||||
HANDLE client) override;
|
||||
HANDLE client,
|
||||
TERMINAL_STARTUP_INFO startupInfo) override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
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
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
TraceLoggingGuid(_guid, "SessionGuid", "The WT_SESSION's GUID"),
|
||||
TraceLoggingWideString(_clientName.c_str(), "Client", "The attached client process"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -203,7 +203,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const HANDLE hOut,
|
||||
const HANDLE hRef,
|
||||
const HANDLE hServerProcess,
|
||||
const HANDLE hClientProcess) :
|
||||
const HANDLE hClientProcess,
|
||||
TERMINAL_STARTUP_INFO startupInfo) :
|
||||
_initialRows{ 25 },
|
||||
_initialCols{ 80 },
|
||||
_guid{ Utils::CreateGuid() },
|
||||
@@ -213,6 +214,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
THROW_IF_FAILED(ConptyPackPseudoConsole(hServerProcess, hRef, hSig, &_hPC));
|
||||
_piClient.hProcess = hClientProcess;
|
||||
|
||||
_startupInfo.title = winrt::hstring{ startupInfo.pszTitle, SysStringLen(startupInfo.pszTitle) };
|
||||
_startupInfo.iconPath = winrt::hstring{ startupInfo.pszIconPath, SysStringLen(startupInfo.pszIconPath) };
|
||||
_startupInfo.iconIndex = startupInfo.iconIndex;
|
||||
|
||||
try
|
||||
{
|
||||
_commandline = _commandlineFromProcess(hClientProcess);
|
||||
@@ -288,6 +293,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
return _commandline;
|
||||
}
|
||||
|
||||
winrt::hstring ConptyConnection::StartingTitle() const
|
||||
{
|
||||
return _startupInfo.title;
|
||||
}
|
||||
|
||||
void ConptyConnection::Start()
|
||||
try
|
||||
{
|
||||
@@ -336,7 +346,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
TraceLoggingGuid(_guid, "SessionGuid", "The WT_SESSION's GUID"),
|
||||
TraceLoggingWideString(_clientName.c_str(), "Client", "The attached client process"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), til::unwrap_coord_size(dimensions)));
|
||||
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
|
||||
@@ -535,28 +545,34 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
if (_transitionToState(ConnectionState::Closing))
|
||||
{
|
||||
// EXIT POINT
|
||||
_clientExitWait.reset(); // immediately stop waiting for the client to exit.
|
||||
|
||||
// _clientExitWait holds a CreateThreadpoolWait() which holds a weak reference to "this".
|
||||
// This manual reset() ensures we wait for it to be teared down via WaitForThreadpoolWaitCallbacks().
|
||||
_clientExitWait.reset();
|
||||
|
||||
_hPC.reset(); // tear down the pseudoconsole (this is like clicking X on a console window)
|
||||
|
||||
// CloseHandle() on pipes blocks until any current WriteFile()/ReadFile() has returned.
|
||||
// CancelSynchronousIo prevents us from deadlocking ourselves.
|
||||
// At this point in Close(), _inPipe won't be used anymore since the UI parts are torn down.
|
||||
// _outPipe is probably still stuck in ReadFile() and might currently be written to.
|
||||
if (_hOutputThread)
|
||||
{
|
||||
CancelSynchronousIo(_hOutputThread.get());
|
||||
}
|
||||
|
||||
_inPipe.reset(); // break the pipes
|
||||
_outPipe.reset();
|
||||
|
||||
if (_hOutputThread)
|
||||
{
|
||||
// Tear down our output thread -- now that the output pipe was closed on the
|
||||
// far side, we can run down our local reader.
|
||||
// Waiting for the output thread to exit ensures that all pending _TerminalOutputHandlers()
|
||||
// calls have returned and won't notify our caller (ControlCore) anymore. This ensures that
|
||||
// we don't call a destroyed event handler asynchronously from a background thread (GH#13880).
|
||||
LOG_LAST_ERROR_IF(WAIT_FAILED == WaitForSingleObject(_hOutputThread.get(), INFINITE));
|
||||
_hOutputThread.reset();
|
||||
}
|
||||
|
||||
if (_piClient.hProcess)
|
||||
{
|
||||
// Wait for the client to terminate (which it should do successfully)
|
||||
LOG_LAST_ERROR_IF(WAIT_FAILED == WaitForSingleObject(_piClient.hProcess, INFINITE));
|
||||
_piClient.reset();
|
||||
}
|
||||
|
||||
_transitionToState(ConnectionState::Closed);
|
||||
}
|
||||
}
|
||||
@@ -606,10 +622,17 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
DWORD read{};
|
||||
|
||||
const auto readFail{ !ReadFile(_outPipe.get(), _buffer.data(), gsl::narrow_cast<DWORD>(_buffer.size()), &read, nullptr) };
|
||||
|
||||
// When we call CancelSynchronousIo() in Close() this is the branch that's taken and gets us out of here.
|
||||
if (_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (readFail) // reading failed (we must check this first, because read will also be 0.)
|
||||
{
|
||||
const auto lastError = GetLastError();
|
||||
if (lastError != ERROR_BROKEN_PIPE && !_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
if (lastError != ERROR_BROKEN_PIPE)
|
||||
{
|
||||
// EXIT POINT
|
||||
_indicateExitWithStatus(HRESULT_FROM_WIN32(lastError)); // print a message
|
||||
@@ -622,12 +645,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const auto result{ til::u8u16(std::string_view{ _buffer.data(), read }, _u16Str, _u8State) };
|
||||
if (FAILED(result))
|
||||
{
|
||||
if (_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
{
|
||||
// This termination was expected.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXIT POINT
|
||||
_indicateExitWithStatus(result); // print a message
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
@@ -667,10 +684,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
winrt::event_token ConptyConnection::NewConnection(const NewConnectionHandler& handler) { return _newConnectionHandlers.add(handler); };
|
||||
void ConptyConnection::NewConnection(const winrt::event_token& token) { _newConnectionHandlers.remove(token); };
|
||||
|
||||
HRESULT ConptyConnection::NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept
|
||||
HRESULT ConptyConnection::NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client, TERMINAL_STARTUP_INFO startupInfo) noexcept
|
||||
try
|
||||
{
|
||||
_newConnectionHandlers(winrt::make<ConptyConnection>(signal, in, out, ref, server, client));
|
||||
_newConnectionHandlers(winrt::make<ConptyConnection>(signal, in, out, ref, server, client, startupInfo));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
|
||||
#include <conpty-static.h>
|
||||
|
||||
#include "ITerminalHandoff.h"
|
||||
|
||||
namespace wil
|
||||
{
|
||||
// These belong in WIL upstream, so when we reingest the change that has them we'll get rid of ours.
|
||||
using unique_static_pseudoconsole_handle = wil::unique_any<HPCON, decltype(&::ConptyClosePseudoConsole), ::ConptyClosePseudoConsole>;
|
||||
using unique_static_pseudoconsole_handle = wil::unique_any<HPCON, decltype(&::ConptyClosePseudoConsole), ::ConptyClosePseudoConsoleNoWait>;
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
@@ -23,7 +25,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const HANDLE hOut,
|
||||
const HANDLE hRef,
|
||||
const HANDLE hServerProcess,
|
||||
const HANDLE hClientProcess);
|
||||
const HANDLE hClientProcess,
|
||||
TERMINAL_STARTUP_INFO startupInfo);
|
||||
|
||||
ConptyConnection() noexcept = default;
|
||||
void Initialize(const Windows::Foundation::Collections::ValueSet& settings);
|
||||
@@ -42,6 +45,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
winrt::guid Guid() const noexcept;
|
||||
winrt::hstring Commandline() const;
|
||||
winrt::hstring StartingTitle() const;
|
||||
|
||||
static void StartInboundListener();
|
||||
static void StopInboundListener();
|
||||
@@ -60,7 +64,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
WINRT_CALLBACK(TerminalOutput, TerminalOutputHandler);
|
||||
|
||||
private:
|
||||
static HRESULT NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept;
|
||||
static HRESULT NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client, TERMINAL_STARTUP_INFO startupInfo) noexcept;
|
||||
static winrt::hstring _commandlineFromProcess(HANDLE process);
|
||||
|
||||
HRESULT _LaunchAttachedClient() noexcept;
|
||||
@@ -93,6 +97,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
std::array<char, 4096> _buffer{};
|
||||
bool _passthroughMode{};
|
||||
|
||||
struct StartupInfoFromDefTerm
|
||||
{
|
||||
winrt::hstring title{};
|
||||
winrt::hstring iconPath{};
|
||||
int32_t iconIndex{};
|
||||
|
||||
} _startupInfo{};
|
||||
|
||||
DWORD _OutputThread();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
ConptyConnection();
|
||||
Guid Guid { get; };
|
||||
String Commandline { get; };
|
||||
String StartingTitle { get; };
|
||||
|
||||
void ClearBuffer();
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_settings = winrt::make_self<implementation::ControlSettings>(settings, unfocusedAppearance);
|
||||
|
||||
_terminal = std::make_unique<::Microsoft::Terminal::Core::Terminal>();
|
||||
_terminal = std::make_shared<::Microsoft::Terminal::Core::Terminal>();
|
||||
|
||||
// Subscribe to the connection's disconnected event and call our connection closed handlers.
|
||||
_connectionStateChangedRevoker = _connection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*v*/) {
|
||||
@@ -195,13 +195,15 @@ 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())
|
||||
[weakTerminal = std::weak_ptr{ _terminal }]() {
|
||||
if (const auto t = weakTerminal.lock())
|
||||
{
|
||||
core->UpdatePatternLocations();
|
||||
auto lock = t->LockForWriting();
|
||||
t->UpdatePatternsUnderLock();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -389,6 +391,55 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _terminal->SendCharEvent(ch, scanCode, modifiers);
|
||||
}
|
||||
|
||||
bool ControlCore::_shouldTryUpdateSelection(const WORD vkey)
|
||||
{
|
||||
// GH#6423 - don't update selection if the key that was pressed was a
|
||||
// modifier key. We'll wait for a real keystroke to dismiss the
|
||||
// GH #7395 - don't update selection when taking PrintScreen
|
||||
// selection.
|
||||
return HasSelection() && !KeyEvent::IsModifierKey(vkey) && vkey != VK_SNAPSHOT;
|
||||
}
|
||||
|
||||
bool ControlCore::TryMarkModeKeybinding(const WORD vkey,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates mods)
|
||||
{
|
||||
if (_shouldTryUpdateSelection(vkey) && _terminal->SelectionMode() == ::Terminal::SelectionInteractionMode::Mark)
|
||||
{
|
||||
if (vkey == 'A' && !mods.IsAltPressed() && !mods.IsShiftPressed() && mods.IsCtrlPressed())
|
||||
{
|
||||
// Ctrl + A --> Select all
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->SelectAll();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
else if (vkey == VK_RETURN && !mods.IsCtrlPressed() && !mods.IsAltPressed())
|
||||
{
|
||||
// [Shift +] Enter --> copy text
|
||||
// Don't lock here! CopySelectionToClipboard already locks for you!
|
||||
CopySelectionToClipboard(mods.IsShiftPressed(), nullptr);
|
||||
_terminal->ClearSelection();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
else if (vkey == VK_ESCAPE)
|
||||
{
|
||||
_terminal->ClearSelection();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
else if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(mods, vkey) })
|
||||
{
|
||||
// try to update the selection
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second, mods);
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Send this particular key event to the terminal.
|
||||
// See Terminal::SendKeyEvent for more information.
|
||||
@@ -405,27 +456,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const bool keyDown)
|
||||
{
|
||||
// Update the selection, if it's present
|
||||
// GH#6423 - don't dismiss selection if the key that was pressed was a
|
||||
// modifier key. We'll wait for a real keystroke to dismiss the
|
||||
// GH #7395 - don't dismiss selection when taking PrintScreen
|
||||
// selection.
|
||||
// GH#8522, GH#3758 - Only modify the selection on key _down_. If we
|
||||
// modify on key up, then there's chance that we'll immediately dismiss
|
||||
// a selection created by an action bound to a keydown.
|
||||
if (HasSelection() &&
|
||||
!KeyEvent::IsModifierKey(vkey) &&
|
||||
vkey != VK_SNAPSHOT &&
|
||||
keyDown)
|
||||
if (_shouldTryUpdateSelection(vkey) && keyDown)
|
||||
{
|
||||
const auto isInMarkMode = _terminal->SelectionMode() == ::Microsoft::Terminal::Core::Terminal::SelectionInteractionMode::Mark;
|
||||
if (isInMarkMode && modifiers.IsCtrlPressed() && vkey == 'A')
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->SelectAll();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
|
||||
// try to update the selection
|
||||
if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) })
|
||||
{
|
||||
@@ -479,7 +514,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)
|
||||
@@ -555,16 +590,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_renderer->TriggerRedrawAll();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Tell TerminalCore to update its knowledge about the locations of visible regex patterns
|
||||
// - We should call this (through the throttled function) when something causes the visible
|
||||
// region to change, such as when new text enters the buffer or the viewport is scrolled
|
||||
void ControlCore::UpdatePatternLocations()
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->UpdatePatternsUnderLock();
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - Updates last hovered cell, renders / removes rendering of hyper-link if required
|
||||
// Arguments:
|
||||
@@ -634,7 +659,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto lock = _terminal->LockForReading(); // Lock for the duration of our reads.
|
||||
if (_lastHoveredCell.has_value())
|
||||
{
|
||||
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(*_lastHoveredCell) };
|
||||
auto uri{ _terminal->GetHyperlinkAtPosition(*_lastHoveredCell) };
|
||||
uri.resize(std::min<size_t>(1024u, uri.size())); // Truncate for display
|
||||
return winrt::hstring{ uri };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -860,6 +887,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void ControlCore::_refreshSizeUnderLock()
|
||||
{
|
||||
if (_IsClosing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto cx = gsl::narrow_cast<til::CoordType>(_panelWidth * _compositionScale);
|
||||
auto cy = gsl::narrow_cast<til::CoordType>(_panelHeight * _compositionScale);
|
||||
|
||||
@@ -1094,6 +1126,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
if (_terminal->IsSelectionActive())
|
||||
{
|
||||
_terminal->SwitchSelectionEndpoint();
|
||||
_updateSelectionUI();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1280,7 +1313,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 +1374,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;
|
||||
@@ -1440,32 +1474,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_FoundMatchHandlers(*this, *foundResults);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Asynchronously close our connection. The Connection will likely wait
|
||||
// until the attached process terminates before Close returns. If that's
|
||||
// the case, we don't want to block the UI thread waiting on that process
|
||||
// handle.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget ControlCore::_asyncCloseConnection()
|
||||
{
|
||||
if (auto localConnection{ std::exchange(_connection, nullptr) })
|
||||
{
|
||||
// Close the connection on the background thread.
|
||||
co_await winrt::resume_background(); // ** DO NOT INTERACT WITH THE CONTROL CORE AFTER THIS LINE **
|
||||
|
||||
// Here, the ControlCore very well might be gone.
|
||||
// _asyncCloseConnection is called on the dtor, so it's entirely
|
||||
// possible that the background thread is resuming after we've been
|
||||
// cleaned up.
|
||||
|
||||
localConnection.Close();
|
||||
// connection is destroyed.
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::Close()
|
||||
{
|
||||
if (!_IsClosing())
|
||||
@@ -1475,13 +1483,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Stop accepting new output and state changes before we disconnect everything.
|
||||
_connection.TerminalOutput(_connectionOutputEventToken);
|
||||
_connectionStateChangedRevoker.revoke();
|
||||
|
||||
// GH#1996 - Close the connection asynchronously on a background
|
||||
// thread.
|
||||
// Since TermControl::Close is only ever triggered by the UI, we
|
||||
// don't really care to wait for the connection to be completely
|
||||
// closed. We can just do it whenever.
|
||||
_asyncCloseConnection();
|
||||
_connection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1569,7 +1571,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
auto lock = _terminal->LockForReading();
|
||||
return _terminal->GetCursorPosition().to_core_point();
|
||||
return _terminal->GetViewportRelativeCursorPosition().to_core_point();
|
||||
}
|
||||
|
||||
// This one's really pushing the boundary of what counts as "encapsulation".
|
||||
@@ -1673,7 +1675,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 +1913,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()
|
||||
|
||||
@@ -87,6 +87,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ToggleMarkMode();
|
||||
Control::SelectionInteractionMode SelectionMode() const;
|
||||
bool SwitchSelectionEndpoint();
|
||||
bool TryMarkModeKeybinding(const WORD vkey,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers);
|
||||
|
||||
void GotFocus();
|
||||
void LostFocus();
|
||||
@@ -95,7 +97,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void AdjustOpacity(const double adjustment);
|
||||
void ResumeRendering();
|
||||
|
||||
void UpdatePatternLocations();
|
||||
void SetHoveredCell(Core::Point terminalPosition);
|
||||
void ClearHoveredCell();
|
||||
winrt::hstring GetHyperlink(const Core::Point position) const;
|
||||
@@ -230,7 +231,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
winrt::com_ptr<ControlSettings> _settings{ nullptr };
|
||||
|
||||
std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
|
||||
std::shared_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
|
||||
|
||||
// NOTE: _renderEngine must be ordered before _renderer.
|
||||
//
|
||||
@@ -265,15 +266,14 @@ 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();
|
||||
|
||||
bool _setFontSizeUnderLock(int fontSize);
|
||||
void _updateFont(const bool initialUpdate = false);
|
||||
void _refreshSizeUnderLock();
|
||||
void _updateSelectionUI();
|
||||
bool _shouldTryUpdateSelection(const WORD vkey);
|
||||
|
||||
void _sendInputToConnection(std::wstring_view wstr);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -14,9 +14,7 @@ namespace Microsoft.Terminal.Control
|
||||
// !! LOAD BEARING !! If you make this a struct with Booleans (like they
|
||||
// make the most sense as), then the app will crash trying to toss one of
|
||||
// these across the process boundary. I haven't the damndest idea why.
|
||||
[flags]
|
||||
enum MouseButtonState
|
||||
{
|
||||
[flags] enum MouseButtonState {
|
||||
IsLeftButtonDown = 0x1,
|
||||
IsMiddleButtonDown = 0x2,
|
||||
IsRightButtonDown = 0x4
|
||||
@@ -37,9 +35,7 @@ namespace Microsoft.Terminal.Control
|
||||
Mark
|
||||
};
|
||||
|
||||
[flags]
|
||||
enum SelectionEndpointTarget
|
||||
{
|
||||
[flags] enum SelectionEndpointTarget {
|
||||
Start = 0x1,
|
||||
End = 0x2
|
||||
};
|
||||
@@ -79,13 +75,15 @@ namespace Microsoft.Terminal.Control
|
||||
Double Opacity { get; };
|
||||
Boolean UseAcrylic { get; };
|
||||
|
||||
Boolean TryMarkModeKeybinding(Int16 vkey,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers);
|
||||
Boolean TrySendKeyEvent(Int16 vkey,
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Boolean keyDown);
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Boolean keyDown);
|
||||
Boolean SendCharEvent(Char ch,
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers);
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers);
|
||||
void SendInput(String text);
|
||||
void PasteText(String text);
|
||||
void SelectAll();
|
||||
@@ -109,7 +107,6 @@ namespace Microsoft.Terminal.Control
|
||||
Microsoft.Terminal.Core.Point CursorPosition { get; };
|
||||
void ResumeRendering();
|
||||
void BlinkAttributeTick();
|
||||
void UpdatePatternLocations();
|
||||
void Search(String text, Boolean goForward, Boolean caseSensitive);
|
||||
Microsoft.Terminal.Core.Color BackgroundColor { get; };
|
||||
|
||||
|
||||
@@ -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();
|
||||
@@ -677,7 +679,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
margins.Top,
|
||||
margins.Right,
|
||||
margins.Bottom };
|
||||
_automationPeer = winrt::make<implementation::TermControlAutomationPeer>(this, padding, interactivityAutoPeer);
|
||||
_automationPeer = winrt::make<implementation::TermControlAutomationPeer>(get_strong(), padding, interactivityAutoPeer);
|
||||
return _automationPeer;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
@@ -1066,7 +1081,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// keybindings on the keyUp, then we'll still send the keydown to the
|
||||
// connected terminal application, and something like ctrl+shift+T will
|
||||
// emit a ^T to the pipe.
|
||||
if (!modifiers.IsAltGrPressed() && keyDown && _TryHandleKeyBinding(vkey, scanCode, modifiers))
|
||||
if (!modifiers.IsAltGrPressed() &&
|
||||
keyDown &&
|
||||
_TryHandleKeyBinding(vkey, scanCode, modifiers))
|
||||
{
|
||||
e.Handled(true);
|
||||
return;
|
||||
@@ -1092,6 +1109,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - modifiers: The ControlKeyStates representing the modifier key states.
|
||||
bool TermControl::_TryHandleKeyBinding(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const
|
||||
{
|
||||
// Mark mode has a specific set of pre-defined key bindings.
|
||||
// If we're in mark mode, we should be prioritizing those over
|
||||
// the custom defined key bindings.
|
||||
if (_core.TryMarkModeKeybinding(vkey, modifiers))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: GH#5000
|
||||
// The Core owning the keybindings is weird. That's for sure. In the
|
||||
// future, we may want to pass the keybindings into the control
|
||||
@@ -1163,12 +1188,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.
|
||||
|
||||
@@ -67,10 +67,10 @@ static constexpr bool IsReadable(std::wstring_view text)
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
TermControlAutomationPeer::TermControlAutomationPeer(TermControl* owner,
|
||||
TermControlAutomationPeer::TermControlAutomationPeer(winrt::com_ptr<TermControl> owner,
|
||||
const Core::Padding padding,
|
||||
Control::InteractivityAutomationPeer impl) :
|
||||
TermControlAutomationPeerT<TermControlAutomationPeer>(*owner), // pass owner to FrameworkElementAutomationPeer
|
||||
TermControlAutomationPeerT<TermControlAutomationPeer>(*owner.get()), // pass owner to FrameworkElementAutomationPeer
|
||||
_termControl{ owner },
|
||||
_contentAutomationPeer{ impl }
|
||||
{
|
||||
@@ -134,8 +134,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
// The event that is raised when the text selection is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
if (auto control{ strongThis->_termControl.get() })
|
||||
{
|
||||
// The event that is raised when the text selection is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -157,8 +160,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
// The event that is raised when textual content is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged);
|
||||
if (auto control{ strongThis->_termControl.get() })
|
||||
{
|
||||
// The event that is raised when textual content is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -180,13 +186,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
// The event that is raised when the text was changed in an edit control.
|
||||
// Do NOT fire a TextEditTextChanged. Generally, an app on the other side
|
||||
// will expect more information. Though you can dispatch that event
|
||||
// on its own, it may result in a nullptr exception on the other side
|
||||
// because no additional information was provided. Crashing the screen
|
||||
// reader.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
if (auto control{ strongThis->_termControl.get() })
|
||||
{
|
||||
// The event that is raised when the text was changed in an edit control.
|
||||
// Do NOT fire a TextEditTextChanged. Generally, an app on the other side
|
||||
// will expect more information. Though you can dispatch that event
|
||||
// on its own, it may result in a nullptr exception on the other side
|
||||
// because no additional information was provided. Crashing the screen
|
||||
// reader.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -236,14 +245,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }, sanitizedCopy{ hstring{ sanitized } }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
try
|
||||
if (auto control{ strongThis->_termControl.get() })
|
||||
{
|
||||
strongThis->RaiseNotificationEvent(AutomationNotificationKind::ActionCompleted,
|
||||
AutomationNotificationProcessing::All,
|
||||
sanitizedCopy,
|
||||
L"TerminalTextOutput");
|
||||
try
|
||||
{
|
||||
strongThis->RaiseNotificationEvent(AutomationNotificationKind::ActionCompleted,
|
||||
AutomationNotificationProcessing::All,
|
||||
sanitizedCopy,
|
||||
L"TerminalTextOutput");
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -284,17 +296,29 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
hstring TermControlAutomationPeer::GetNameCore() const
|
||||
{
|
||||
// fallback to title if profile name is empty
|
||||
auto profileName = _termControl->GetProfileName();
|
||||
if (profileName.empty())
|
||||
if (auto control{ _termControl.get() })
|
||||
{
|
||||
return _termControl->Title();
|
||||
const auto profileName = control->GetProfileName();
|
||||
if (profileName.empty())
|
||||
{
|
||||
return control->Title();
|
||||
}
|
||||
else
|
||||
{
|
||||
return profileName;
|
||||
}
|
||||
}
|
||||
return profileName;
|
||||
|
||||
return L"";
|
||||
}
|
||||
|
||||
hstring TermControlAutomationPeer::GetHelpTextCore() const
|
||||
{
|
||||
return _termControl->Title();
|
||||
if (const auto control{ _termControl.get() })
|
||||
{
|
||||
return control->Title();
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
AutomationLiveSetting TermControlAutomationPeer::GetLiveSettingCore() const
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
::Microsoft::Console::Types::IUiaEventDispatcher
|
||||
{
|
||||
public:
|
||||
TermControlAutomationPeer(Microsoft::Terminal::Control::implementation::TermControl* owner,
|
||||
TermControlAutomationPeer(winrt::com_ptr<Microsoft::Terminal::Control::implementation::TermControl> owner,
|
||||
const Core::Padding padding,
|
||||
Control::InteractivityAutomationPeer implementation);
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
winrt::Microsoft::Terminal::Control::implementation::TermControl* _termControl;
|
||||
winrt::weak_ref<Microsoft::Terminal::Control::implementation::TermControl> _termControl;
|
||||
Control::InteractivityAutomationPeer _contentAutomationPeer;
|
||||
std::deque<wchar_t> _keyEvents;
|
||||
};
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -1615,3 +1615,12 @@ til::color Terminal::GetColorForMark(const Microsoft::Console::VirtualTerminal::
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns the position of the cursor relative to the active viewport
|
||||
til::point Terminal::GetViewportRelativeCursorPosition() const noexcept
|
||||
{
|
||||
const auto absoluteCursorPosition{ GetCursorPosition() };
|
||||
const auto viewport{ _GetMutableViewport() };
|
||||
return absoluteCursorPosition - viewport.Origin();
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@ public:
|
||||
bool IsXtermBracketedPasteModeEnabled() const;
|
||||
std::wstring_view GetWorkingDirectory();
|
||||
|
||||
til::point GetViewportRelativeCursorPosition() const noexcept;
|
||||
|
||||
// Write comes from the PTY and goes to our parser to be stored in the output buffer
|
||||
void Write(std::wstring_view stringView);
|
||||
|
||||
@@ -424,6 +426,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);
|
||||
|
||||
@@ -228,7 +228,7 @@ void Terminal::SetSelectionEnd(const til::point viewportPos, std::optional<Selec
|
||||
// - the new start/end for a selection
|
||||
std::pair<til::point, til::point> Terminal::_PivotSelection(const til::point targetPos, bool& targetStart) const
|
||||
{
|
||||
if (targetStart = targetPos <= _selection->pivot)
|
||||
if (targetStart = _activeBuffer().GetSize().CompareInBounds(targetPos, _selection->pivot) <= 0)
|
||||
{
|
||||
// target is before pivot
|
||||
// treat target as start
|
||||
@@ -298,14 +298,24 @@ void Terminal::ToggleMarkMode()
|
||||
// Enter Mark Mode
|
||||
// NOTE: directly set cursor state. We already should have locked before calling this function.
|
||||
_activeBuffer().GetCursor().SetIsOn(false);
|
||||
const auto cursorPos{ _activeBuffer().GetCursor().GetPosition() };
|
||||
_selection = SelectionAnchors{};
|
||||
_selection->start = cursorPos;
|
||||
_selection->end = cursorPos;
|
||||
_selection->pivot = cursorPos;
|
||||
if (!IsSelectionActive())
|
||||
{
|
||||
// No selection --> start one at the cursor
|
||||
const auto cursorPos{ _activeBuffer().GetCursor().GetPosition() };
|
||||
_selection = SelectionAnchors{};
|
||||
_selection->start = cursorPos;
|
||||
_selection->end = cursorPos;
|
||||
_selection->pivot = cursorPos;
|
||||
_blockSelection = false;
|
||||
WI_SetAllFlags(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End);
|
||||
}
|
||||
else if (WI_AreAllFlagsClear(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End))
|
||||
{
|
||||
// Selection already existed
|
||||
WI_SetFlag(_selectionEndpoint, SelectionEndpoint::End);
|
||||
}
|
||||
_ScrollToPoint(_selection->start);
|
||||
_selectionMode = SelectionInteractionMode::Mark;
|
||||
_blockSelection = false;
|
||||
WI_SetAllFlags(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,22 +469,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 +480,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)
|
||||
@@ -524,7 +520,7 @@ void Terminal::_MoveByWord(SelectionDirection direction, til::point& pos)
|
||||
case SelectionDirection::Left:
|
||||
{
|
||||
const auto wordStartPos{ _activeBuffer().GetWordStart(pos, _wordDelimiters) };
|
||||
if (_selection->pivot < pos)
|
||||
if (_activeBuffer().GetSize().CompareInBounds(_selection->pivot, pos) < 0)
|
||||
{
|
||||
// If we're moving towards the pivot, move one more cell
|
||||
pos = wordStartPos;
|
||||
@@ -547,7 +543,7 @@ void Terminal::_MoveByWord(SelectionDirection direction, til::point& pos)
|
||||
case SelectionDirection::Right:
|
||||
{
|
||||
const auto wordEndPos{ _activeBuffer().GetWordEnd(pos, _wordDelimiters) };
|
||||
if (pos < _selection->pivot)
|
||||
if (_activeBuffer().GetSize().CompareInBounds(pos, _selection->pivot) < 0)
|
||||
{
|
||||
// If we're moving towards the pivot, move one more cell
|
||||
pos = _activeBuffer().GetWordEnd(pos, _wordDelimiters);
|
||||
@@ -685,3 +681,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);
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_Label{ label },
|
||||
_SubPage{ subPage } {}
|
||||
|
||||
hstring ToString() { return _Label; }
|
||||
|
||||
WINRT_PROPERTY(IInspectable, Tag);
|
||||
WINRT_PROPERTY(winrt::hstring, Label);
|
||||
WINRT_PROPERTY(BreadcrumbSubPage, SubPage);
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
Profile_Advanced
|
||||
};
|
||||
|
||||
runtimeclass Breadcrumb
|
||||
runtimeclass Breadcrumb : Windows.Foundation.IStringable
|
||||
{
|
||||
IInspectable Tag;
|
||||
String Label;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -62,7 +62,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
template<typename TIconSource>
|
||||
TIconSource _getColoredBitmapIcon(const winrt::hstring& path)
|
||||
{
|
||||
if (!path.empty())
|
||||
// FontIcon uses glyphs in the private use area, whereas valid URIs only contain ASCII characters.
|
||||
// To skip throwing on Uri construction, we can quickly check if the first character is ASCII.
|
||||
if (!path.empty() && path.front() < 128)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -435,6 +435,27 @@ void TerminalCoreUnitTests::TerminalApiTest::SetWorkingDirectory()
|
||||
stateMachine.ProcessString(L"\x1b]9;9\"C:\\\"\x1b\\");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
stateMachine.ProcessString(L"\x1b"
|
||||
LR"(]9;9;"C:\invalid path "with" quotes")"
|
||||
L"\x1b\\");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
// These OSC 9;9 sequences will result in invalid CWD. It should end up empty, like above.
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\x1b\\");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\"\x1b\\");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\x1b\\");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\"\x1b\\");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;No quotes \"until\" later\x1b\\");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
// Valid sequences should change CWD
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"C:\\\"\x1b\\");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"C:\\");
|
||||
@@ -454,17 +475,4 @@ void TerminalCoreUnitTests::TerminalApiTest::SetWorkingDirectory()
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;D:\\中文\x1b\\");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"D:\\中文");
|
||||
|
||||
// These OSC 9;9 sequences will result in invalid CWD. We shouldn't crash on these.
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\x1b\\");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\"\x1b\\");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"\"");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\x1b\\");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\"\x1b\\");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"\"");
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
@@ -677,13 +683,6 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, til::rect proposedRect, Launc
|
||||
// If we can't resize the window, that's really okay. We can just go on with
|
||||
// the originally proposed window size.
|
||||
LOG_LAST_ERROR_IF(!succeeded);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hWindowsTerminalProvider,
|
||||
"WindowCreated",
|
||||
TraceLoggingDescription("Event emitted upon creating the application window"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1206,7 +1253,6 @@ bool IslandWindow::RegisterHotKey(const int index, const winrt::Microsoft::Termi
|
||||
// TODO GH#8888: We should display a warning of some kind if this fails.
|
||||
// This can fail if something else already bound this hotkey.
|
||||
const auto result = ::RegisterHotKey(_window.get(), index, hotkeyFlags, vkey);
|
||||
LOG_IF_WIN32_BOOL_FALSE(result);
|
||||
|
||||
TraceLoggingWrite(g_hWindowsTerminalProvider,
|
||||
"RegisterHotKey",
|
||||
@@ -1452,23 +1498,31 @@ void IslandWindow::_globalActivateWindow(const uint32_t dropdownDuration,
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto windowThreadProcessId = GetWindowThreadProcessId(oldForegroundWindow, nullptr);
|
||||
const auto currentThreadId = GetCurrentThreadId();
|
||||
// Try first to send a message to the current foreground window. If it's not responding, it may
|
||||
// be waiting on us to finsh launching. Passing SMTO_NOTIMEOUTIFNOTHUNG means that we get the same
|
||||
// behavior as before--that is, waiting for the message loop--but we've done an early return if
|
||||
// it turns out that it was hung.
|
||||
// SendMessageTimeoutW returns nonzero if it succeeds.
|
||||
if (0 != SendMessageTimeoutW(oldForegroundWindow, WM_NULL, 0, 0, SMTO_NOTIMEOUTIFNOTHUNG | SMTO_BLOCK | SMTO_ABORTIFHUNG, 1000, nullptr))
|
||||
{
|
||||
const auto windowThreadProcessId = GetWindowThreadProcessId(oldForegroundWindow, nullptr);
|
||||
const auto currentThreadId = GetCurrentThreadId();
|
||||
|
||||
LOG_IF_WIN32_BOOL_FALSE(AttachThreadInput(windowThreadProcessId, currentThreadId, true));
|
||||
// Just in case, add the thread detach as a scope_exit, to make _sure_ we do it.
|
||||
auto detachThread = wil::scope_exit([windowThreadProcessId, currentThreadId]() {
|
||||
LOG_IF_WIN32_BOOL_FALSE(AttachThreadInput(windowThreadProcessId, currentThreadId, false));
|
||||
});
|
||||
LOG_IF_WIN32_BOOL_FALSE(BringWindowToTop(_window.get()));
|
||||
ShowWindow(_window.get(), SW_SHOW);
|
||||
LOG_IF_WIN32_BOOL_FALSE(AttachThreadInput(windowThreadProcessId, currentThreadId, true));
|
||||
// Just in case, add the thread detach as a scope_exit, to make _sure_ we do it.
|
||||
auto detachThread = wil::scope_exit([windowThreadProcessId, currentThreadId]() {
|
||||
LOG_IF_WIN32_BOOL_FALSE(AttachThreadInput(windowThreadProcessId, currentThreadId, false));
|
||||
});
|
||||
LOG_IF_WIN32_BOOL_FALSE(BringWindowToTop(_window.get()));
|
||||
ShowWindow(_window.get(), SW_SHOW);
|
||||
|
||||
// Activate the window too. This will force us to the virtual desktop this
|
||||
// window is on, if it's on another virtual desktop.
|
||||
LOG_LAST_ERROR_IF_NULL(SetActiveWindow(_window.get()));
|
||||
// Activate the window too. This will force us to the virtual desktop this
|
||||
// window is on, if it's on another virtual desktop.
|
||||
LOG_LAST_ERROR_IF_NULL(SetActiveWindow(_window.get()));
|
||||
|
||||
// Throw us on the active monitor.
|
||||
_moveToMonitor(oldForegroundWindow, toMonitor);
|
||||
// Throw us on the active monitor.
|
||||
_moveToMonitor(oldForegroundWindow, toMonitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -99,12 +99,6 @@ static bool _messageIsAltSpaceKeypress(const MSG& message)
|
||||
int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||
{
|
||||
TraceLoggingRegister(g_hWindowsTerminalProvider);
|
||||
TraceLoggingWrite(
|
||||
g_hWindowsTerminalProvider,
|
||||
"ExecutableStarted",
|
||||
TraceLoggingDescription("Event emitted immediately on startup"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
::Microsoft::Console::ErrorReporting::EnableFallbackFailureReporting(g_hWindowsTerminalProvider);
|
||||
|
||||
// If Terminal is spawned by a shortcut that requests that it run in a new process group
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace Microsoft.Terminal.Wpf
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
@@ -52,6 +54,30 @@ namespace Microsoft.Terminal.Wpf
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WPF's HwndHost likes to mark the WM_GETOBJECT message as handled to
|
||||
/// force the usage of the WPF automation peer. We explicitly mark it as
|
||||
/// not handled and don't return an automation peer in "OnCreateAutomationPeer" below.
|
||||
/// This forces the message to go down to the HwndTerminal where we return terminal's UiaProvider.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||
{
|
||||
if (msg == (int)NativeMethods.WindowMessage.WM_GETOBJECT)
|
||||
{
|
||||
handled = false;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return base.WndProc(hwnd, msg, wParam, lParam, ref handled);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override AutomationPeer OnCreateAutomationPeer()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that is fired when the terminal buffer scrolls from text output.
|
||||
/// </summary>
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Microsoft.Terminal.Wpf
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
@@ -42,6 +43,20 @@ namespace Microsoft.Terminal.Wpf
|
||||
this.GotFocus += this.TerminalControl_GotFocus;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override AutomationPeer OnCreateAutomationPeer()
|
||||
{
|
||||
var peer = FrameworkElementAutomationPeer.FromElement(this);
|
||||
if (peer == null)
|
||||
{
|
||||
// Provide our own automation peer here that just sets IsContentElement/IsControlElement to false
|
||||
// (aka AccessibilityView = Raw). This makes it not pop up in the UIA tree.
|
||||
peer = new TermControlAutomationPeer(this);
|
||||
}
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current character rows available to the terminal.
|
||||
/// </summary>
|
||||
@@ -266,5 +281,22 @@ namespace Microsoft.Terminal.Wpf
|
||||
var viewTop = (int)e.NewValue;
|
||||
this.termContainer.UserScroll(viewTop);
|
||||
}
|
||||
|
||||
private class TermControlAutomationPeer : UserControlAutomationPeer
|
||||
{
|
||||
public TermControlAutomationPeer(UserControl owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool IsContentElementCore()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsControlElementCore()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,6 @@
|
||||
<Import Project="$(OpenConsoleDir)\src\common.build.pre.props" />
|
||||
<Import Project="$(SolutionDir)\src\common.nugetversions.props" />
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<!-- For CLI11: It uses dynamic_cast to cast types around, which depends
|
||||
on being compiled with RTTI (/GR). -->
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="precomp.h" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user