Compare commits

..

1 Commits

Author SHA1 Message Date
Leonard Hecker
532b3a72dc Improve error checking around AttachThreadInput 2025-08-01 14:48:15 +02:00
310 changed files with 2568 additions and 5510 deletions

View File

@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"XamlStyler.Console": {
"version": "3.2501.8",
"version": "3.2311.2",
"commands": [
"xstyler"
]

View File

@@ -174,11 +174,9 @@ tokeninfo
tolower
toupper
TRACKMOUSEEVENT
ubrk
UChar
UFIELD
ULARGE
UNCEx
UOI
UPDATEINIFILE
urlmon

View File

@@ -34,7 +34,6 @@ issecret
libucrt
libucrtd
LOCKFILE
LTCG
Lxss
makepri
microsoft

View File

@@ -28,7 +28,6 @@ jerrysh
Kaiyu
leonardder
lhecker
Lovecraft
masserano
menger
migrie

View File

@@ -141,7 +141,6 @@ BValue
Cacafire
CALLCONV
CANDRABINDU
CANTCALLOUT
capslock
CARETBLINKINGENABLED
CARRIAGERETURN
@@ -810,7 +809,6 @@ inclusivity
INCONTEXT
INFOEX
inheritcursor
ININPUTSYNCCALL
INITCOMMONCONTROLSEX
INITDIALOG
INITGUID
@@ -824,7 +822,6 @@ INPUTSCOPE
INSERTMODE
INTERACTIVITYBASE
INTERCEPTCOPYPASTE
internalevent
INTERNALNAME
intsafe
INVALIDARG
@@ -963,7 +960,6 @@ lstatus
lstrcmp
lstrcmpi
LTEXT
lto
ltsc
LUID
luma
@@ -1063,7 +1059,6 @@ Mypair
Myval
NAMELENGTH
namestream
NCACTIVATE
NCCALCSIZE
NCCREATE
NCLBUTTONDOWN
@@ -1094,8 +1089,6 @@ NEXTLINE
nfe
NLSMODE
NOACTIVATE
NOACTIVATEKEYBOARDLAYOUT
NOACTIVATETIP
NOAPPLYNOW
NOCLIP
NOCOMM
@@ -1510,6 +1503,7 @@ scrolllock
scrolloffset
SCROLLSCALE
SCROLLSCREENBUFFER
scursor
sddl
SDKDDK
segfault
@@ -1707,16 +1701,13 @@ TEXTMETRIC
TEXTMETRICW
textmode
texttests
TFCAT
THUMBPOSITION
THUMBTRACK
tilunittests
TIPCAP
titlebars
TITLEISLINKNAME
TLDP
TLEN
Tlgg
TMAE
TMPF
tmultiple
@@ -1763,8 +1754,6 @@ UIACCESS
uiacore
uiautomationcore
uielem
UIELEMENTENABLED
UIELEMENTENABLEDONLY
UINTs
uld
uldash
@@ -1981,7 +1970,6 @@ WRITECONSOLEOUTPUT
WRITECONSOLEOUTPUTSTRING
wrkstr
WRL
wrl
wrp
WRunoff
WSLENV

View File

@@ -17,6 +17,7 @@
"Microsoft.VisualStudio.Component.AppInsights.Tools",
"Microsoft.Net.Component.4.8.TargetingPack",
"Microsoft.VisualStudio.Component.DiagnosticTools",
"Microsoft.NetCore.Component.Runtime.6.0",
"Microsoft.VisualStudio.Component.ClassDesigner",
"Microsoft.VisualStudio.Component.GraphDocument",
"Microsoft.VisualStudio.Component.CodeMap",

View File

@@ -4,7 +4,7 @@
<clear />
<!-- Dependencies that we can turn on to force override for testing purposes before uploading. -->
<!--<add key="Static Package Dependencies" value="dep\packages" />-->
<add key="TerminalDependencies" value="https://pkgs.dev.azure.com/shine-oss/terminal/_packaging/TerminalDependencies%40Local/nuget/v3/index.json" />
<add key="TerminalDependencies" value="https://pkgs.dev.azure.com/shine-oss/terminal/_packaging/TerminalDependencies/nuget/v3/index.json" />
</packageSources>
<disabledPackageSources>
<clear />

View File

@@ -309,6 +309,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{D3EF
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winconpty.Tests.Feature", "src\winconpty\ft_pty\winconpty.FeatureTests.vcxproj", "{024052DE-83FB-4653-AEA4-90790D29D5BD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAzBridge", "src\cascadia\TerminalAzBridge\TerminalAzBridge.vcxproj", "{067F0A06-FCB7-472C-96E9-B03B54E8E18D}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "src\cascadia\WpfTerminalTestNetCore\WpfTerminalTestNetCore.csproj", "{1588FD7C-241E-4E7D-9113-43735F3E6BAD}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070}
@@ -1698,6 +1703,30 @@ Global
{024052DE-83FB-4653-AEA4-90790D29D5BD}.Release|x64.Build.0 = Release|x64
{024052DE-83FB-4653-AEA4-90790D29D5BD}.Release|x86.ActiveCfg = Release|Win32
{024052DE-83FB-4653-AEA4-90790D29D5BD}.Release|x86.Build.0 = Release|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.AuditMode|x64.ActiveCfg = Release|x64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.AuditMode|x86.ActiveCfg = AuditMode|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.AuditMode|x86.Build.0 = AuditMode|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Debug|Any CPU.ActiveCfg = Debug|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Debug|ARM64.Build.0 = Debug|ARM64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Debug|x64.ActiveCfg = Debug|x64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Debug|x64.Build.0 = Debug|x64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Debug|x86.ActiveCfg = Debug|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Debug|x86.Build.0 = Debug|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|Any CPU.ActiveCfg = Release|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|ARM64.ActiveCfg = Release|ARM64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|ARM64.Build.0 = Release|ARM64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x64.ActiveCfg = Release|x64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x64.Build.0 = Release|x64
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x86.ActiveCfg = Release|Win32
{067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x86.Build.0 = Release|Win32
{1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|Any CPU.ActiveCfg = Debug|Any CPU
{1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|ARM64.ActiveCfg = Debug|Any CPU
{1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|x64.ActiveCfg = Debug|Any CPU
@@ -2274,6 +2303,7 @@ Global
{6B5A44ED-918D-4747-BFB1-2472A1FCA173} = {04170EEF-983A-4195-BFEF-2321E5E38A1E}
{D3EF7B96-CD5E-47C9-B9A9-136259563033} = {04170EEF-983A-4195-BFEF-2321E5E38A1E}
{024052DE-83FB-4653-AEA4-90790D29D5BD} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
{067F0A06-FCB7-472C-96E9-B03B54E8E18D} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C}
{1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {4DAF0299-495E-4CD1-A982-9BAC16A45932}
{506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C}
{416FD703-BAA7-4F6E-9361-64F550EC8FCA} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C}

View File

@@ -56,9 +56,9 @@ This is an open source project and we welcome community participation. To partic
<ReleaseNotes _locID="App_ReleaseNotes">
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__}{Locked=wt.exe} App Release Note" -->Version __VERSION_NUMBER__
- A whole new Extensions page that shows what has been installed into your Terminal
- Command Palette now shows up in your native language as well as English
- New VT features such as synchronized rendering, new color schemes, configuration for quick mouse actions like zooming, and more
- We've added dozens of settings to the UI that once only existed in the JSON file, including a new page for customizing the layout of your New Tab menu!
- We have rearchitected window management to improve reliability; please file any bugs you encounter with the wt.exe alias
- Profiles now show an icon if they've been hidden or refer to programs which were uninstalled.
Please see our GitHub releases page for additional details.
</ReleaseNotes>

View File

@@ -20,7 +20,6 @@
"DisableAutoPackageNameFormatting": false
},
"appSubmission": {
"appId": "9N8G5RFZ9XK3",
"productId": "00014050269303149694",
"targetPublishMode": "NotSet",
"targetPublishDate": null,

View File

@@ -54,11 +54,14 @@ This is an open source project and we welcome community participation. To partic
<!-- _locComment_text="{MaxLength=255} App DevStudio" -->
</DevStudio>
<ReleaseNotes _locID="App_ReleaseNotes">
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__}{Locked=wt.exe} App Release Note" -->Version __VERSION_NUMBER__
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__} App Release Note" -->Version __VERSION_NUMBER__
- We've added dozens of settings to the UI that once only existed in the JSON file, including a new page for customizing the layout of your New Tab menu!
- We have rearchitected window management to improve reliability; please file any bugs you encounter with the wt.exe alias
- Profiles now show an icon if they've been hidden or refer to programs which were uninstalled.
- We've rewritten how console applications are hosted inside Terminal! Please report any bugs you encounter.
- Terminal now supports Sixels!
- You can now open a docked panel containing snippets of commands you have saved to use later
- Command Prompt users on the latest Windows 11 release may see a "quick tip" icon that suggests installable software from WinGet
- Selected text will now be much more visible (and customizable!)
- A number of reliabilty bugs, convenience issues and annoyances have been fixed.
Please see our GitHub releases page for additional details.
</ReleaseNotes>

View File

@@ -20,7 +20,6 @@
"DisableAutoPackageNameFormatting": false
},
"appSubmission": {
"appId": "9N0DX20HK701",
"productId": "00013926773940052066",
"targetPublishMode": "NotSet",
"targetPublishDate": null,

View File

@@ -4,7 +4,7 @@
"collection": "microsoft",
"project": "OS",
"repo": "os.2020",
"name": "official/ge_current_directwinpd_deep",
"name": "official/rs_we_adept_e4d2",
"workitem": "38106206",
"CheckinFiles": [
{

View File

@@ -17,6 +17,7 @@
"PackageContents/WindowsTerminalShellExt.dll",
// The rest
"PackageContents/TerminalAzBridge.exe",
"PackageContents/wt.exe",
"PackageContents/WindowsTerminal.exe",
"PackageContents/elevate-shim.exe"

View File

@@ -2,7 +2,7 @@
{
"MatchedPath": [
"WpfTerminalControl/net472/Microsoft.Terminal.Wpf.dll",
"WpfTerminalControl/net8.0-windows/Microsoft.Terminal.Wpf.dll"
"WpfTerminalControl/net6.0-windows/Microsoft.Terminal.Wpf.dll"
],
"SigningInfo": {
"Operations": [

View File

@@ -9,7 +9,7 @@
<PropertyGroup>
<!-- Optional, defaults to main. Name of the branch which will be used for calculating branch point. -->
<PGOBranch>release-1.24</PGOBranch>
<PGOBranch>main</PGOBranch>
<!-- Mandatory. Name of the NuGet package which will contain PGO databases for consumption by build system. -->
<PGOPackageName>Microsoft.Internal.Windows.Terminal.PGODatabase</PGOPackageName>

View File

@@ -53,12 +53,8 @@ parameters:
displayName: "Publish Symbols to MSDL"
type: boolean
default: true
- name: createVpack
displayName: "Create a VPack for Windows"
type: boolean
default: false
- name: publishVpackToWindows
displayName: "Publish above VPack to Windows"
displayName: "Publish VPack to Windows"
type: boolean
default: false
@@ -93,7 +89,6 @@ extends:
clientId: $(SigningOriginalClientId)
terminalInternalPackageVersion: ${{ parameters.terminalInternalPackageVersion }}
publishSymbolsToPublic: ${{ parameters.publishSymbolsToPublic }}
createVpack: ${{ parameters.createVpack }}
publishVpackToWindows: ${{ parameters.publishVpackToWindows }}
symbolPublishingSubscription: $(SymbolPublishingServiceConnection)
symbolPublishingProject: $(SymbolPublishingProject)

View File

@@ -50,7 +50,6 @@ stages:
buildEverything: true
pgoBuildMode: Instrument
artifactStem: -instrumentation
keepAllExpensiveBuildOutputs: false # the ARM64 build agent runs out of memory downloading the artifacts...
- stage: RunPGO
displayName: Run PGO

View File

@@ -86,7 +86,7 @@ jobs:
$MachineToken = $env:SYSTEM_ACCESSTOKEN | ConvertTo-SecureString -AsPlainText -Force
$Credential = [PSCredential]::new("ONEBRANCH_TOKEN", $MachineToken)
$MachineToken = $null
$Feed = "https://pkgs.dev.azure.com/shine-oss/terminal/_packaging/TerminalDependencies%40Local/nuget/v3/index.json"
$Feed = "https://pkgs.dev.azure.com/shine-oss/terminal/_packaging/TerminalDependencies/nuget/v3/index.json"
Register-PSResourceRepository -Name "PSGalleryUpstream" -Uri $Feed -Trusted
Get-PSResourceRepository

View File

@@ -26,7 +26,6 @@ jobs:
pgoToolsPath: $(Build.SourcesDirectory)\build\PGO
nuspecPath: $(pgoToolsPath)\NuSpecs
nuspecFilename: PGO.nuspec
nugetFeed: "https://pkgs.dev.azure.com/shine-oss/terminal/_packaging/TerminalDependencies/nuget/v3/index.json"
steps:
- checkout: self
@@ -46,8 +45,7 @@ jobs:
- task: NuGetAuthenticate@1
inputs:
azureDevOpsServiceConnection: 'Terminal Public Artifact Feed'
feedUrl: $(nugetFeed)
nuGetServiceConnections: 'Terminal Public Artifact Feed'
# In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
# This should be `task: NuGetCommand@2`
@@ -70,7 +68,15 @@ jobs:
artifact: pgo-nupkg-${{ parameters.buildConfiguration }}${{ parameters.artifactStem }}
displayName: "Publish Pipeline Artifact"
- pwsh: |-
$nupkg = Get-Item "$(Build.ArtifactStagingDirectory)/*.nupkg"
& nuget push -ApiKey az -Source "$(nugetFeed)" "$nupkg"
displayName: NuGet push
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
displayName: 'NuGet push'
inputs:
command: push
nuGetFeedType: external
packagesToPush: $(Build.ArtifactStagingDirectory)/*.nupkg
# The actual URL and PAT for this feed is configured at
# https://microsoft.visualstudio.com/Dart/_settings/adminservices
# This is the name of that connection
publishFeedCredentials: 'Terminal Public Artifact Feed'
feedsToUse: config
nugetConfigPath: '$(Build.SourcesDirectory)/NuGet.config'

View File

@@ -45,10 +45,6 @@ jobs:
displayName: Extract the unpackaged build for PGO
- template: steps-ensure-nuget-version.yml
parameters:
${{ if eq(parameters.buildPlatform, 'arm64') }}:
# The ARM64 agents do not seem to have NuGet installed
forceNugetInstallation: true
- powershell: |-
$Package = 'Microsoft.Internal.Windows.Terminal.TestContent'

View File

@@ -69,3 +69,10 @@ jobs:
artifact: $(JobOutputArtifactName)
displayName: 'Publish VPack Manifest to Drop'
- task: PkgESFCIBGit@12
displayName: 'Submit VPack Manifest to Windows'
inputs:
configPath: '$(Build.SourcesDirectory)\build\config\GitCheckin.json'
artifactsDirectory: $(XES_VPACKMANIFESTDIRECTORY)
prTimeOut: 5

View File

@@ -49,9 +49,6 @@ parameters:
- name: symbolExpiryTime
type: string
default: 36530 # This is the default from PublishSymbols@2
- name: createVpack
type: boolean
default: false
- name: publishVpackToWindows
type: boolean
default: false
@@ -195,8 +192,8 @@ extends:
ob_outputDirectory: $(JobOutputDirectory)
ob_artifactBaseName: $(JobOutputArtifactName)
### This job is also in charge of submitting the vpack to Windows if it's enabled
ob_createvpack_enabled: ${{ and(parameters.buildTerminal, parameters.createVpack) }}
ob_updateOSManifest_enabled: ${{ and(parameters.buildTerminal, parameters.createVpack, parameters.publishVpackToWindows) }}
ob_createvpack_enabled: ${{ and(parameters.buildTerminal, parameters.publishVpackToWindows) }}
ob_updateOSManifest_enabled: ${{ and(parameters.buildTerminal, parameters.publishVpackToWindows) }}
### If enabled above, these options are in play.
ob_createvpack_packagename: 'WindowsTerminal.app'
ob_createvpack_owneralias: 'conhost@microsoft.com'
@@ -210,8 +207,6 @@ extends:
ob_createvpack_taskLogVerbosity: Detailed
ob_createvpack_verbose: true
ob_createvpack_vpackdirectory: '$(JobOutputDirectory)\vpack'
ob_createvpack_versionAs: string
ob_createvpack_version: '$(XES_PACKAGEVERSIONNUMBER)'
ob_updateOSManifest_gitcheckinConfigPath: '$(Build.SourcesDirectory)\build\config\GitCheckin.json'
# We're skipping the 'fetch' part of the OneBranch rules, but that doesn't mean
# that it doesn't expect to have downloaded a manifest directly to some 'destination'
@@ -234,7 +229,7 @@ extends:
New-Item "$(JobOutputDirectory)/vpack" -Type Directory
displayName: Make sure the vpack directory exists
- ${{ if parameters.createVpack }}:
- ${{ if parameters.publishVpackToWindows }}:
- pwsh: |-
Copy-Item -Verbose -Path "$(MsixBundlePath)" -Destination (Join-Path "$(JobOutputDirectory)/vpack" 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle')
displayName: Stage msixbundle for vpack

View File

@@ -1,10 +1,5 @@
parameters:
- name: forceNugetInstallation
type: boolean
default: false
steps:
- ${{ if and(ne(parameters.forceNugetInstallation, true), eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564')) }}:
- ${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}:
- pwsh: |-
Write-Host "Assuming NuGet is already installed..."
& nuget.exe help
@@ -12,6 +7,6 @@ steps:
- ${{ else }}:
- task: NuGetToolInstaller@1
displayName: Use NuGet 7.0.1
displayName: Use NuGet 6.6.1
inputs:
versionSpec: 7.0.1
versionSpec: 6.6.1

View File

@@ -4,8 +4,8 @@
<!-- Native packages -->
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
<package id="Microsoft.Taef" version="10.93.240607003" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.250303.1" targetFramework="native" />
<package id="Microsoft.Internal.Windows.Terminal.ThemeHelpers" version="0.8.250811004" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.230207.1" targetFramework="native" />
<package id="Microsoft.Internal.Windows.Terminal.ThemeHelpers" version="0.7.230706001" targetFramework="native" />
<package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="2.3.2262" targetFramework="native" developmentDependency="true" />
<package id="Microsoft.UI.Xaml" version="2.8.4" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.1661.34" targetFramework="native" />

View File

@@ -2302,15 +2302,8 @@
"additionalProperties": false,
"properties": {
"id": {
"description": "The ID of the command this keybinding should execute (or null to disable a default).",
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
"description": "The ID of the command this keybinding should execute.",
"type": "string"
},
"keys": {
"description": "Defines the key combinations used to call the command. It must be composed of...\n -any number of modifiers (ctrl/alt/shift)\n -a non-modifier key",
@@ -2466,7 +2459,6 @@
"description": "Direct3D 11 provides a more performant and feature-rich experience, whereas Direct2D is more stable. The default option \"Automatic\" will pick the API that best fits your graphics hardware. If you experience significant issues, consider using Direct2D.",
"type": "string",
"enum": [
"automatic",
"direct2d",
"direct3d11"
]
@@ -2480,9 +2472,8 @@
"type": "boolean"
},
"experimental.input.forceVT": {
"type": "boolean",
"description": "[Deprecated] Replaced with the \"compatibility.input.forceVT\" profile setting.",
"deprecated": true
"description": "Force the terminal to use the legacy input encoding. Certain keys in some applications may stop working when enabling this setting.",
"type": "boolean"
},
"experimental.useBackgroundImageForWindow": {
"default": false,
@@ -2529,14 +2520,14 @@
"type": "string"
},
"rowsToScroll": {
"default": "system",
"description": "This parameter once allowed you to override the systemwide \"choose how many lines to scroll at one time\" setting. It no longer does so. However, you can customize the number of lines to scroll in \"scrollUp\" and \"scrollDown\" bindings.",
"maximum": 999,
"minimum": 0,
"type": [
"integer",
"string"
],
"description": "[Deprecated] This setting no longer has any effect. However, you can customize the number of lines to scroll using the \"rowsToScroll\" argument on the \"scrollUp\" and \"scrollDown\" actions.",
"default": "system",
"minimum": 0,
"maximum": 999,
"deprecated": true
},
"minimizeToNotificationArea": {
@@ -2582,12 +2573,9 @@
"$ref": "#/$defs/NewTabMenu"
},
"language": {
"type": [
"string",
"null"
],
"default": "",
"description": "Sets an override for the app's preferred language, expressed as a BCP-47 language tag like en-US.",
"default": null
"type": "string"
},
"theme": {
"default": "dark",
@@ -2651,19 +2639,19 @@
"type": "boolean"
},
"useTabSwitcher": {
"description": "[Deprecated] Replaced with the \"tabSwitcherMode\" setting.",
"default": true,
"description": "Deprecated. Please use \"tabSwitcherMode\" instead.",
"oneOf": [
{
"type": "boolean"
},
{
"type": "string",
"enum": [
"mru",
"inOrder",
"disabled"
]
],
"type": "string"
}
],
"deprecated": true
@@ -2720,12 +2708,12 @@
"type": "object",
"properties": {
"acrylicOpacity": {
"type": "number",
"description": "[Deprecated] Replaced with the \"opacity\" setting.",
"default": 0.5,
"minimum": 0,
"description": "[deprecated] Please use `opacity` instead.",
"deprecated": true,
"maximum": 1,
"deprecated": true
"minimum": 0,
"type": "number"
},
"antialiasingMode": {
"default": "grayscale",
@@ -2751,11 +2739,6 @@
"description": "When set to true, when opening a new tab or pane it will get reloaded environment variables.",
"type": "boolean"
},
"compatibility.input.forceVT": {
"default": false,
"description": "Force the terminal to use the legacy input encoding. Certain keys in some applications may stop working when enabling this setting.",
"type": "boolean"
},
"compatibility.allowDECRQCRA": {
"default": false,
"description": "When set to true, the terminal will support the DECRQCRA (Request Checksum of Rectangular Area) escape sequence.",
@@ -2927,29 +2910,24 @@
"type": "boolean"
},
"experimental.autoMarkPrompts": {
"type": "boolean",
"description": "[Deprecated] Replaced with the \"autoMarkPrompts\" setting.",
"deprecated": true
"deprecated": true,
"description": "This has been replaced by autoMarkPrompts in 1.21",
"type": "boolean"
},
"experimental.retroTerminalEffect": {
"description": "When set to true, enable retro terminal effects. This is an experimental feature, and its continued existence is not guaranteed.",
"type": "boolean"
},
"experimental.showMarksOnScrollbar": {
"type": "boolean",
"description": "[Deprecated] Replaced with the \"showMarksOnScrollbar\" setting.",
"deprecated": true
"deprecated": true,
"description": "This has been replaced by showMarksOnScrollbar in 1.21",
"type": "boolean"
},
"showMarksOnScrollbar": {
"default": false,
"description": "When set to true, marks added to the buffer via the addMark action will appear on the scrollbar.",
"type": "boolean"
},
"experimental.rainbowSuggestions": {
"type": "boolean",
"description": "Enables displaying command suggestions in the terminal in RGB (all the colors of the rainbow!).",
"default": false
},
"experimental.rightClickContextMenu": {
"default": false,
"description": "When true, right-click shows a context menu; otherwise, it pastes from the clipboard or copies selection.",
@@ -2965,29 +2943,23 @@
"type": "string"
},
"fontFace": {
"type": "string",
"description": "[Deprecated] Replaced with the \"face\" setting within the \"font\" object.",
"default": "Cascadia Mono",
"description": "[deprecated] Define 'face' within the 'font' object instead.",
"type": "string",
"deprecated": true
},
"fontSize": {
"type": "number",
"description": "[Deprecated] Replaced with the \"size\" setting within the \"font\" object.",
"default": 12,
"description": "[deprecated] Define 'size' within the 'font' object instead.",
"minimum": 1,
"type": "number",
"deprecated": true
},
"fontWeight": {
"description": "[Deprecated] Replaced with the \"weight\" setting within the \"font\" object.",
"default": "normal",
"description": "[deprecated] Define 'weight' within the 'font' object instead.",
"oneOf": [
{
"type": "integer",
"minimum": 100,
"maximum": 990
},
{
"type": "string",
"enum": [
"thin",
"extra-light",
@@ -3000,7 +2972,13 @@
"extra-bold",
"black",
"extra-black"
]
],
"type": "string"
},
{
"maximum": 990,
"minimum": 100,
"type": "integer"
}
],
"deprecated": true
@@ -3111,10 +3089,7 @@
},
"answerbackMessage": {
"description": "The response that is sent when an ENQ control character is received.",
"type": [
"string",
"null"
]
"type": "string"
},
"source": {
"description": "Stores the name of the profile generator that originated this profile.",

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.250303.1" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.230207.1" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.8.4" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.1661.34" targetFramework="native" />
</packages>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.250303.1" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.230207.1" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.8.4" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.1661.34" targetFramework="native" />
</packages>

View File

@@ -942,12 +942,12 @@ void ROW::_resizeChars(uint16_t colEndDirty, uint16_t chBegDirty, size_t chEndDi
}
}
RowAttributes& ROW::Attributes() noexcept
til::small_rle<TextAttribute, uint16_t, 1>& ROW::Attributes() noexcept
{
return _attr;
}
const RowAttributes& ROW::Attributes() const noexcept
const til::small_rle<TextAttribute, uint16_t, 1>& ROW::Attributes() const noexcept
{
return _attr;
}

View File

@@ -14,11 +14,6 @@
class ROW;
class TextBuffer;
// Because MarkKind::Output gets set only on the actually written text,
// most rows will end up having at least 2 runs: The start of the line
// with MarkKind::Output and the rest of the line with MarkKind::None.
using RowAttributes = til::small_rle<TextAttribute, uint16_t, 2>;
enum class DelimiterClass
{
ControlChar,
@@ -154,8 +149,8 @@ public:
void ReplaceText(RowWriteState& state);
void CopyTextFrom(RowCopyTextFromState& state);
RowAttributes& Attributes() noexcept;
const RowAttributes& Attributes() const noexcept;
til::small_rle<TextAttribute, uint16_t, 1>& Attributes() noexcept;
const til::small_rle<TextAttribute, uint16_t, 1>& Attributes() const noexcept;
TextAttribute GetAttrByColumn(til::CoordType column) const;
std::vector<uint16_t> GetHyperlinks() const;
ImageSlice* SetImageSlice(ImageSlice::Pointer imageSlice) noexcept;
@@ -303,7 +298,7 @@ private:
std::span<uint16_t> _charOffsets;
// _attr is a run-length-encoded vector of TextAttribute with a decompressed
// length equal to _columnCount (= 1 TextAttribute per column).
RowAttributes _attr;
til::small_rle<TextAttribute, uint16_t, 1> _attr;
// The width of the row in visual columns.
uint16_t _columnCount = 0;
// Stores double-width/height (DECSWL/DECDWL/DECDHL) attributes.

View File

@@ -77,6 +77,9 @@
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WindowsTerminal\WindowsTerminal.vcxproj">
<Project>{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}</Project>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalAzBridge\TerminalAzBridge.vcxproj">
<Project>{067F0A06-FCB7-472C-96E9-B03B54E8E18D}</Project>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\ShellExtension\WindowsTerminalShellExt.vcxproj">
<Project>{f2ed628a-db22-446f-a081-4cc845b51a2b}</Project>
</ProjectReference>

View File

@@ -24,7 +24,6 @@
<PropertyGroup Label="NuGet Dependencies">
<!-- TerminalCppWinrt is intentionally not set -->
<TerminalMUX>true</TerminalMUX>
<TerminalThemeHelpers>true</TerminalThemeHelpers>
</PropertyGroup>
<Import Project="$(SolutionDir)\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />

View File

@@ -548,9 +548,7 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = args.ActionArgs().try_as<CopyTextArgs>())
{
const auto copyFormatting = realArgs.CopyFormatting();
const auto format = copyFormatting ? copyFormatting.Value() : _settings.GlobalSettings().CopyFormatting();
const auto handled = _CopyText(realArgs.DismissSelection(), realArgs.SingleLine(), realArgs.WithControlSequences(), format);
const auto handled = _CopyText(realArgs.DismissSelection(), realArgs.SingleLine(), realArgs.WithControlSequences(), realArgs.CopyFormatting());
args.Handled(handled);
}
}
@@ -900,10 +898,7 @@ namespace winrt::TerminalApp::implementation
co_return;
}
// ShellExecuteExW may block, so do it on a background thread.
//
// NOTE: All remaining code of this function doesn't touch `this`, so we don't need weak/strong_ref.
// NOTE NOTE: Don't touch `this` when you make changes here.
// Hop to the BG thread
co_await winrt::resume_background();
// This will get us the correct exe for dev/preview/release. If you
@@ -1456,8 +1451,6 @@ namespace winrt::TerminalApp::implementation
safe_void_coroutine TerminalPage::_doHandleSuggestions(SuggestionsArgs realArgs)
{
const auto weak = get_weak();
const auto dispatcher = Dispatcher();
const auto source = realArgs.Source();
std::vector<Command> commandsCollection;
Control::CommandHistoryContext context{ nullptr };
@@ -1524,12 +1517,7 @@ namespace winrt::TerminalApp::implementation
}
}
co_await wil::resume_foreground(dispatcher);
const auto strong = weak.get();
if (!strong)
{
co_return;
}
co_await wil::resume_foreground(Dispatcher());
// Open the palette with all these commands in it.
_OpenSuggestions(_GetActiveControl(),

View File

@@ -135,24 +135,15 @@ namespace winrt::TerminalApp::implementation
_isElevated = ::Microsoft::Console::Utils::IsRunningElevated();
_canDragDrop = ::Microsoft::Console::Utils::CanUwpDragDrop();
_reloadSettings = std::make_shared<ThrottledFunc<>>(
DispatcherQueue::GetForCurrentThread(),
til::throttled_func_options{
.delay = std::chrono::milliseconds{ 100 },
.debounce = true,
.trailing = true,
},
[weakSelf = get_weak()]() {
if (auto self{ weakSelf.get() })
{
self->ReloadSettings();
}
});
_reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(winrt::Windows::System::DispatcherQueue::GetForCurrentThread(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() {
if (auto self{ weakSelf.get() })
{
self->ReloadSettings();
}
});
_languageProfileNotifier = winrt::make_self<LanguageProfileNotifier>([this]() {
// TODO: This is really bad, because we reset any current user customizations.
// See GH#11522.
ReloadSettingsThrottled();
_reloadSettings->Run();
});
// Do this here, rather than at the top of main. This will prevent us from
@@ -332,7 +323,7 @@ namespace winrt::TerminalApp::implementation
if (modifiedBasename == settingsBasename)
{
ReloadSettingsThrottled();
_reloadSettings->Run();
}
});
}
@@ -438,11 +429,6 @@ namespace winrt::TerminalApp::implementation
SettingsChanged.raise(*this, *ev);
}
void AppLogic::ReloadSettingsThrottled()
{
_reloadSettings->Run();
}
// This is a continuation of AppLogic::Create() and includes the more expensive parts.
void AppLogic::NotifyRootInitialized()
{

View File

@@ -36,7 +36,6 @@ namespace winrt::TerminalApp::implementation
bool IsRunningElevated() const noexcept;
bool CanDragDrop() const noexcept;
void ReloadSettings();
void ReloadSettingsThrottled();
void NotifyRootInitialized();
bool HasSettingsStartupActions() const noexcept;
@@ -65,7 +64,7 @@ namespace winrt::TerminalApp::implementation
bool _hasSettingsStartupActions{ false };
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
std::shared_ptr<ThrottledFunc<>> _reloadSettings;
std::shared_ptr<ThrottledFuncTrailing<>> _reloadSettings;
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> _warnings{};
@@ -81,6 +80,7 @@ namespace winrt::TerminalApp::implementation
[[nodiscard]] HRESULT _TryLoadSettings() noexcept;
void _ProcessLazySettingsChanges();
void _RegisterSettingsChange();
safe_void_coroutine _DispatchReloadSettings();
void _setupFolderPathEnvVar();

View File

@@ -25,7 +25,6 @@ namespace TerminalApp
Boolean HasSettingsStartupActions();
void ReloadSettings();
void ReloadSettingsThrottled();
Microsoft.Terminal.Settings.Model.CascadiaSettings Settings { get; };
TerminalWindow CreateNewWindow();

View File

@@ -929,17 +929,6 @@ namespace winrt::TerminalApp::implementation
void CommandPalette::_filterTextChanged(const IInspectable& /*sender*/,
const Windows::UI::Xaml::RoutedEventArgs& /*args*/)
{
// GH#18737: Only respond to this change if we are visible:
// _close calls _searchBox().Text(L"") to reset the search text, which lands us
// in here after the command palette is dismissed. Since we have a code path here that
// could potentially lead to an action being previewed (specifically if there is a
// preview-able action as the first entry in the command list), that preview will
// appear after the palette is dismissed without this check.
if (Visibility() != Visibility::Visible)
{
return;
}
// When we are executing the _SelectNextTab in the TabManagement.cpp, this method
// is getting triggered because we set up the default value for that CommandPalette
// with an empty string. Therefore, to avoid the reset of the index when executing

View File

@@ -61,7 +61,7 @@ namespace winrt::TerminalApp::implementation
winrt::hstring Icon()
{
return _Command.Icon().Resolved();
return _Command.IconPath();
}
WINRT_PROPERTY(Microsoft::Terminal::Settings::Model::Command, Command, nullptr);

View File

@@ -34,15 +34,9 @@ namespace winrt::Microsoft::TerminalApp::implementation
// before actually starting the connection to the client app. This
// will ensure both controls are initialized before the client app
// is.
const auto weak = get_weak();
co_await winrt::resume_background();
const auto strong = weak.get();
if (!strong)
{
co_return;
}
_pairedTap->_start.wait();
_wrappedConnection.Start();
}
void WriteInput(const winrt::array_view<const char16_t> buffer)

View File

@@ -19,6 +19,41 @@ DEFINE_PROPERTYKEY(PKEY_AppUserModel_DestListLogoUri, 0x9F4C2855, 0x9F79, 0x4B39
{ 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 }, 29 \
}
// Function Description:
// - This function guesses whether a string is a file path.
static constexpr bool _isProbableFilePath(std::wstring_view path)
{
// "C:X", "C:\X", "\\?", "\\."
// _this function rejects \??\ as a path_
if (path.size() >= 3)
{
const auto firstColon{ path.find(L':') };
if (firstColon == 1)
{
return true;
}
const auto prefix{ path.substr(0, 2) };
return prefix == LR"(//)" || prefix == LR"(\\)";
}
return false;
}
// Function Description:
// - DestListLogoUri cannot take paths that are separated by / unless they're URLs.
// This function uses std::filesystem to normalize strings that appear to be file
// paths to have the "correct" slash direction.
static std::wstring _normalizeIconPath(std::wstring_view path)
{
const auto fullPath{ wil::ExpandEnvironmentStringsW<std::wstring>(path.data()) };
if (_isProbableFilePath(fullPath))
{
std::filesystem::path asPath{ fullPath };
return asPath.make_preferred().wstring();
}
return std::wstring{ fullPath };
}
// Method Description:
// - Updates the items of the Jumplist based on the given settings.
// Arguments:
@@ -43,9 +78,6 @@ safe_void_coroutine Jumplist::UpdateJumplist(const CascadiaSettings& settings) n
// make sure to capture the settings _before_ the co_await
const auto strongSettings = settings;
// Explorer APIs may block, so do it on a background thread.
//
// NOTE: Jumplist has no members, so we don't need to hold onto `this` here.
co_await winrt::resume_background();
try
@@ -92,7 +124,7 @@ void Jumplist::_updateProfiles(IObjectCollection* jumplistItems, winrt::Windows:
auto args = fmt::format(FMT_COMPILE(L"-p {}"), to_hstring(profile.Guid()));
// Create the shell link object for the profile
const auto normalizedIconPath{ profile.Icon().Resolved() };
const auto normalizedIconPath{ _normalizeIconPath(profile.Icon()) };
const auto shLink = _createShellLink(profile.Name(), normalizedIconPath, args);
THROW_IF_FAILED(jumplistItems->AddObject(shLink.get()));
}

View File

@@ -35,23 +35,17 @@ namespace winrt::TerminalApp::implementation
// (which should be the default, see:
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-trackmouseevent#remarks)
unsigned int hoverTimeoutMillis{ 400 };
if (FAILED(SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hoverTimeoutMillis, 0)))
{
hoverTimeoutMillis = 400;
}
LOG_IF_WIN32_BOOL_FALSE(SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hoverTimeoutMillis, 0));
const auto toolTipInterval = std::chrono::milliseconds(hoverTimeoutMillis);
// Create a ThrottledFunc for opening the tooltip after the hover
// timeout. If we hover another button, we should make sure to call
// Run() with the new button. Calling `_displayToolTip.Run(nullptr)`,
// which will cause us to not display a tooltip, which is used when we
// leave the control entirely.
_displayToolTip = std::make_shared<ThrottledFunc<Controls::Button>>(
_displayToolTip = std::make_shared<ThrottledFuncTrailing<Controls::Button>>(
dispatcher,
til::throttled_func_options{
.delay = std::chrono::milliseconds{ hoverTimeoutMillis },
.debounce = true,
.trailing = true,
},
toolTipInterval,
[weakThis = get_weak()](Controls::Button button) {
// If we provide a button, then open the tooltip on that button.
// We can "dismiss" this throttled func by calling it with null,
@@ -89,18 +83,6 @@ namespace winrt::TerminalApp::implementation
CloseClick.raise(*this, e);
}
bool MinMaxCloseControl::Focused() const
{
return _focused;
}
void MinMaxCloseControl::Focused(bool focused)
{
_focused = focused;
ReleaseButtons();
}
void MinMaxCloseControl::SetWindowVisualState(WindowVisualState visualState)
{
// Look up the heights we should use for the caption buttons from our
@@ -182,25 +164,25 @@ namespace winrt::TerminalApp::implementation
// animate the fade in/out transition between colors.
case CaptionButton::Minimize:
VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", true);
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
_displayToolTip->Run(MinimizeButton());
closeToolTipForButton(MaximizeButton());
closeToolTipForButton(CloseButton());
break;
case CaptionButton::Maximize:
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", true);
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
closeToolTipForButton(MinimizeButton());
_displayToolTip->Run(MaximizeButton());
closeToolTipForButton(CloseButton());
break;
case CaptionButton::Close:
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
VisualStateManager::GoToState(CloseButton(), L"PointerOver", true);
closeToolTipForButton(MinimizeButton());
@@ -223,17 +205,17 @@ namespace winrt::TerminalApp::implementation
{
case CaptionButton::Minimize:
VisualStateManager::GoToState(MinimizeButton(), L"Pressed", true);
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
break;
case CaptionButton::Maximize:
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
VisualStateManager::GoToState(MaximizeButton(), L"Pressed", true);
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
break;
case CaptionButton::Close:
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
VisualStateManager::GoToState(CloseButton(), L"Pressed", true);
break;
}
@@ -246,9 +228,9 @@ namespace winrt::TerminalApp::implementation
void MinMaxCloseControl::ReleaseButtons()
{
_displayToolTip->Run(nullptr);
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
closeToolTipForButton(MinimizeButton());
closeToolTipForButton(MaximizeButton());
@@ -256,11 +238,4 @@ namespace winrt::TerminalApp::implementation
_lastPressedButton = std::nullopt;
}
const winrt::param::hstring& MinMaxCloseControl::_normalState() const
{
static const winrt::param::hstring normal = L"Normal";
static const winrt::param::hstring unfocused = L"Unfocused";
return (_focused ? normal : unfocused);
}
}

View File

@@ -21,9 +21,6 @@ namespace winrt::TerminalApp::implementation
void PressButton(CaptionButton button);
void ReleaseButtons();
bool Focused() const;
void Focused(bool focused);
void _MinimizeClick(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _MaximizeClick(const winrt::Windows::Foundation::IInspectable& sender,
@@ -35,12 +32,8 @@ namespace winrt::TerminalApp::implementation
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> MaximizeClick;
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> CloseClick;
bool _focused{ false };
std::shared_ptr<ThrottledFunc<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
std::shared_ptr<ThrottledFuncTrailing<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
std::optional<CaptionButton> _lastPressedButton{ std::nullopt };
private:
const winrt::param::hstring& _normalState() const;
};
}

View File

@@ -14,7 +14,6 @@ namespace TerminalApp
void HoverButton(CaptionButton button);
void PressButton(CaptionButton button);
void ReleaseButtons();
Boolean Focused { get; set; };
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MinimizeClick;
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MaximizeClick;

View File

@@ -32,10 +32,6 @@
ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CaptionButtonForegroundPressed"
ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CaptionButtonForegroundUnfocusedColor"
ResourceKey="TextFillColorDisabled" />
<SolidColorBrush x:Key="CaptionButtonForegroundUnfocused"
Color="{ThemeResource CaptionButtonForegroundUnfocusedColor}" />
<SolidColorBrush x:Key="CaptionButtonBackground"
Color="Transparent" />
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
@@ -70,10 +66,6 @@
ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CaptionButtonForegroundPressed"
ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CaptionButtonForegroundUnfocusedColor"
ResourceKey="TextFillColorDisabled" />
<SolidColorBrush x:Key="CaptionButtonForegroundUnfocused"
Color="{ThemeResource CaptionButtonForegroundUnfocusedColor}" />
<SolidColorBrush x:Key="CaptionButtonBackground"
Color="Transparent" />
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
@@ -111,10 +103,6 @@
Color="{ThemeResource SystemColorHighlightTextColor}" />
<SolidColorBrush x:Key="CaptionButtonForegroundPressed"
Color="{ThemeResource SystemColorHighlightTextColor}" />
<SolidColorBrush x:Key="CaptionButtonForegroundUnfocused"
Color="{ThemeResource SystemColorButtonTextColor}" />
<StaticResource x:Key="CaptionButtonForegroundUnfocusedColor"
ResourceKey="SystemColorButtonTextColor" />
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="CloseButtonForegroundPointerOver"
@@ -201,20 +189,6 @@
Duration="0:0:0.1" />
</Storyboard>
</VisualTransition>
<VisualTransition From="PointerOver"
To="Unfocused">
<Storyboard>
<ColorAnimation Storyboard.TargetName="ButtonBaseElement"
Storyboard.TargetProperty="(UIElement.Background).(SolidColorBrush.Color)"
To="{ThemeResource CaptionButtonBackgroundColor}"
Duration="0:0:0.15" />
<ColorAnimation Storyboard.TargetName="ButtonIcon"
Storyboard.TargetProperty="(UIElement.Foreground).(SolidColorBrush.Color)"
To="{ThemeResource CaptionButtonForegroundUnfocusedColor}"
Duration="0:0:0.1" />
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal">
@@ -224,13 +198,6 @@
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unfocused">
<VisualState.Setters>
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackground}" />
<Setter Target="ButtonIcon.Foreground" Value="{ThemeResource CaptionButtonForegroundUnfocused}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackgroundPointerOver}" />

View File

@@ -1161,12 +1161,10 @@ void Pane::SetActive()
// focused, else the profile of the last control to be focused
Profile Pane::GetFocusedProfile()
{
if (auto lastFocused{ GetActivePane() })
auto lastFocused = GetActivePane();
if (const auto& terminalPane{ lastFocused->_getTerminalContent() })
{
if (const auto& terminalPane{ lastFocused->_getTerminalContent() })
{
return terminalPane.GetProfile();
}
return terminalPane.GetProfile();
}
return nullptr;
}

View File

@@ -44,6 +44,10 @@ namespace winrt::TerminalApp::implementation
{
_args = { value.begin(), value.end() };
_parseResult = _parsed.ParseArgs(_args);
if (_parseResult == 0)
{
_parsed.ValidateStartupCommands();
}
}
winrt::com_array<winrt::hstring> CommandlineArgs::Commandline()

View File

@@ -270,9 +270,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Registerkarte kopieren</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>Mindestens eine in den Einstellungen angegebene Ressource (z. B. icon oder backgroundImage) wurde nicht gefunden.</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>Profil mit einem ungültigen "backgroundImage" gefunden. Dieses Profil hat standardmäßig kein Hintergrundbild. Stellen Sie sicher, dass beim Festlegen eines "backgroundImage" der Wert ein gültiger Dateipfad zu einem Bild ist.</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>Profil mit einem ungültigen "icon" gefunden. Dieses Profil hat standardmäßig kein Symbol. Stellen Sie sicher, dass beim Festlegen eines "icon" der Wert ein gültiger Dateipfad zu einem Bild ist.</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Beim Analysieren Ihrer Tastenzuordnungen wurden Warnungen gefunden:</value>

View File

@@ -271,9 +271,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Duplicate tab</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>One or more resources (such as icon or backgroundImage) specified in your settings could not be found.</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>Found a profile with an invalid "backgroundImage". Defaulting that profile to have no background image. Make sure that when setting a "backgroundImage", the value is a valid file path to an image.</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>Found a profile with an invalid "icon". Defaulting that profile to have no icon. Make sure that when setting an "icon", the value is a valid file path to an image.</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Warnings were found while parsing your keybindings:</value>

View File

@@ -267,9 +267,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Duplicar pestaña</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>No se encontraron uno o varios recursos (como icon o backgroundImage) especificados en la configuración.</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>Se encontró un perfil con un "backgroundImage" no válido. Si se predetermina que ese perfil no tiene imagen de fondo. Asegúrese de que al establecer "backgroundImage", el valor sea una ruta de acceso de archivo válida a una imagen.</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>Se encontró un perfil con un "icon" no válido. Estableciendo ese perfil para no tener icono. Asegúrese de que, al establecer un "icon", el valor es una ruta de acceso de archivo válida a una imagen.</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Se encontraron advertencias al analizar los enlaces de teclado:</value>

View File

@@ -267,9 +267,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Dupliquer longlet</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>Une ou plusieurs ressources (telles que icon ou backgroundImage) spécifiées dans vos paramètres sont introuvables.</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>Profil détecté avec une "backgroundImage" non valide. Par défaut, ce profil ne possède pas dimage darrière-plan. Assurez-vous que lorsque vous définissez une "backgroundImage", la valeur est un chemin daccès de fichier valide vers une image.</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>Profil détecté avec une "icon" non valide. Par défaut, ce profil ne possède pas dicône. Assurez-vous que lorsque vous définissez une "icon", la valeur est un chemin daccès de fichier valide vers une image.</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Des avertissements ont été détectés lors de lanalyse de vos combinaisons de touches :</value>
@@ -887,7 +891,7 @@
<value>Déplacer l'onglet vers une nouvelle fenêtre </value>
</data>
<data name="RunAsAdminFlyout.Text" xml:space="preserve">
<value>Exécuter en tant qu'administrateur (restreint)</value>
<value>Exécuter en temps qu'administrateur (restreint)</value>
<comment>This text is displayed on context menu for profile entries in add new tab button.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">

View File

@@ -267,9 +267,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Duplica scheda</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>Impossibile trovare una o più risorse, ad esempio icon o backgroundImage, specificate nelle impostazioni.</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>È stato trovato un profilo con un "backgroundImage" non valido. Impostazione predefinita per il profilo non è disponibile un'immagine di sfondo. Accertarsi che quando si imposta un "backgroundImage", il valore è un percorso di file valido per un'immagine.</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>Trovato un profilo con "icon" non valida. Impostare il profilo senza icon. Assicurarsi che, quando si imposta una "icon", il valore abbia un percorso file valido per un'immagine.</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Sono stati trovati avvisi durante l'analisi delle associazioni di tasti:</value>

View File

@@ -185,7 +185,7 @@
<value>終了</value>
</data>
<data name="MultiplePanes" xml:space="preserve">
<value>複数ペイン</value>
<value>複数ウィンドウ</value>
</data>
<data name="TabCloseSubMenu" xml:space="preserve">
<value>閉じる</value>
@@ -203,13 +203,13 @@
<value>タブを閉じる</value>
</data>
<data name="PaneClose" xml:space="preserve">
<value>ペインを閉じる</value>
<value>ウィンドウを閉じる</value>
</data>
<data name="SplitTabText" xml:space="preserve">
<value>タブを分割</value>
</data>
<data name="SplitPaneText" xml:space="preserve">
<value>ペインを分割する</value>
<value>ウィンドウを分割する</value>
</data>
<data name="SplitPaneToolTipText" xml:space="preserve">
<value>分割する方向を右クリック - 右/下/上/左</value>
@@ -230,7 +230,7 @@
<value>複製</value>
</data>
<data name="SwapPaneText" xml:space="preserve">
<value>ペインを入れ替える</value>
<value>ウィンドウを入れ替える</value>
</data>
<data name="SwapPaneDownText" xml:space="preserve">
<value>下とペインを入れ替え</value>
@@ -245,10 +245,10 @@
<value>左とペインを入れ替え</value>
</data>
<data name="TogglePaneZoomText" xml:space="preserve">
<value>ペインのズームの切り替え</value>
<value>ウィンドウのズームの切り替え</value>
</data>
<data name="CloseOtherPanesText" xml:space="preserve">
<value>他のペインを閉じる</value>
<value>他のウィンドウを閉じる</value>
</data>
<data name="SearchWebText" xml:space="preserve">
<value>Web 検索</value>
@@ -268,9 +268,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>タブを複製する</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>設定で指定された 1 つ以上のリソース (icon や backgroundImage など) が見つかりませんでした。</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>無効な "backgroundImage" を持つプロファイルが見つかりました。既定では、そのプロファイルに背景画像はありません。"backgroundImage" を設定するときに、値が画像への有効なファイル パスとなっていることをご確認ください。</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>無効な "icon" を持つプロファイルが見つかりました。既定では、そのプロファイルにアイコンはありません。"icon" を設定するときに、値が画像への有効なファイル パスとなっていることをご確認ください。</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>キー バインドの解析中に警告が検出されました:</value>
@@ -317,7 +321,7 @@
<value>同じ名前ですが大文字と小文字が異なる環境変数が複数見つかりました。使用される値は 1 つだけです。</value>
</data>
<data name="CmdCommandArgDesc" xml:space="preserve">
<value>新しいタブまたはペインで生成されるオプションのコマンドと引数</value>
<value>新しいタブまたはウィンドウで生成されるオプションのコマンドと引数</value>
</data>
<data name="SaveSnippetDesc" xml:space="preserve">
<value>コマンド ラインを入力アクションとして保存する</value>
@@ -345,17 +349,17 @@
<value>指定されたインデックスのタブにフォーカスを移動する</value>
</data>
<data name="CmdMovePaneTabArgDesc" xml:space="preserve">
<value>フォーカスされたペインを指定されたインデックスのタブに移動する</value>
<value>フォーカスされたウィンドウを指定されたインデックスのタブに移動する</value>
</data>
<data name="CmdMovePaneDesc" xml:space="preserve">
<value>フォーカスされたペインを別のタブに移動する</value>
<value>フォーカスされたウィンドウを別のタブに移動する</value>
</data>
<data name="CmdMPDesc" xml:space="preserve">
<value>"move-pane" サブコマンドのエイリアス。</value>
<comment>{Locked="\"move-pane\""}</comment>
</data>
<data name="CmdSplitPaneSizeArgDesc" xml:space="preserve">
<value>サイズを親ペインに対する割合として指定します。有効な値は (0,1) の間で、排他的です。</value>
<value>サイズを親ウィンドウに対する割合として指定します。有効な値は (0,1) の間で、排他的です。</value>
</data>
<data name="CmdNewTabDesc" xml:space="preserve">
<value>新しいタブの作成</value>
@@ -365,14 +369,14 @@
<comment>{Locked="\"new-tab\""}</comment>
</data>
<data name="CmdFocusPaneDesc" xml:space="preserve">
<value>別のペインにフォーカスを移動する</value>
<value>別のウィンドウにフォーカスを移動する</value>
</data>
<data name="CmdFPDesc" xml:space="preserve">
<value>"focus-pane" サブコマンドのエイリアス。</value>
<comment>{Locked="\"focus-pane\""}</comment>
</data>
<data name="CmdFocusPaneTargetArgDesc" xml:space="preserve">
<value>指定されたインデックスのペインをフォーカスする</value>
<value>指定されたインデックスのウィンドウをフォーカスする</value>
</data>
<data name="CmdProfileArgDesc" xml:space="preserve">
<value>指定されたプロファイルで開きます。プロファイルの名前または GUID を指定できます</value>
@@ -381,20 +385,20 @@
<value>WT_SESSION 変数を設定します; GUID である必要があります</value>
</data>
<data name="CmdSplitPaneDesc" xml:space="preserve">
<value>新しい分割ペインの作成</value>
<value>新しい分割ウィンドウの作成</value>
</data>
<data name="CmdSPDesc" xml:space="preserve">
<value>"split-pane" サブコマンドのエイリアス。</value>
<comment>{Locked="\"split-pane\""}</comment>
</data>
<data name="CmdSplitPaneHorizontalArgDesc" xml:space="preserve">
<value>新しいペインを水平方向に分割して作成します ([-]と考えてください)</value>
<value>新しいウィンドウを水平方向に分割して作成します ([-]と考えてください)</value>
</data>
<data name="CmdSplitPaneVerticalArgDesc" xml:space="preserve">
<value>新しいペインを垂直方向に分割して作成します ([|]と考えてください)</value>
<value>新しいウィンドウを垂直方向に分割して作成します ([|]と考えてください)</value>
</data>
<data name="CmdSplitPaneDuplicateArgDesc" xml:space="preserve">
<value>フォーカスされたペインのプロファイルを複製して、新しいペインを作成します</value>
<value>フォーカスされたウィンドウのプロファイルを複製して、新しいウィンドウを作成します</value>
</data>
<data name="CmdStartingDirArgDesc" xml:space="preserve">
<value>プロファイルの "startingDirectory" の設定ではなく、指定されたディレクトリで開きます</value>
@@ -412,7 +416,7 @@
<comment>{Locked="\"tabTitle\""}</comment>
</data>
<data name="CmdInheritEnvDesc" xml:space="preserve">
<value>新しい環境ブロックを作成するのではなく、新しいタブまたはペインを作成するときに、ターミナル独自の環境変数を継承します。これは、"command" が渡されたときに既定で設定されます。 </value>
<value>新しい環境ブロックを作成するのではなく、新しいタブまたはウィンドウを作成するときに、ターミナル独自の環境変数を継承します。これは、"command" が渡されたときに既定で設定されます。 </value>
<comment>{Locked="\"command\""}</comment>
</data>
<data name="CmdColorSchemeArgDesc" xml:space="preserve">
@@ -429,7 +433,7 @@
<value>ウィンドウを全画面表示モードで起動する</value>
</data>
<data name="CmdMoveFocusDesc" xml:space="preserve">
<value>指定した方向にある隣のペインにフォーカスを移動する</value>
<value>指定した方向にある隣のウィンドウにフォーカスを移動する</value>
</data>
<data name="CmdMFDesc" xml:space="preserve">
<value>"move-focus" サブコマンドのエイリアス。</value>
@@ -439,10 +443,10 @@
<value>フォーカスを移動する方向</value>
</data>
<data name="CmdSwapPaneDesc" xml:space="preserve">
<value>フォーカスされたペインを、指定された方向の隣接するペインと入れ替える</value>
<value>フォーカスされたウィンドウを、指定された方向の隣接するウィンドウと入れ替える</value>
</data>
<data name="CmdSwapPaneDirectionArgDesc" xml:space="preserve">
<value>フォーカスされたペインを移動する方向</value>
<value>フォーカスされたウィンドウを移動する方向</value>
</data>
<data name="CmdFocusDesc" xml:space="preserve">
<value>ウィンドウをフォーカス モードで起動</value>
@@ -857,7 +861,7 @@
<value>設定ページを開きます</value>
</data>
<data name="SplitTabToolTip" xml:space="preserve">
<value>現在のディレクトリのアクティブなプロファイルを使用して新しいペインを開きます</value>
<value>現在のディレクトリのアクティブなプロファイルを使用して新しいウィンドウを開きます</value>
</data>
<data name="TabCloseAfterToolTip" xml:space="preserve">
<value>このタブの右側にあるすべてのタブを閉じます</value>
@@ -872,10 +876,10 @@
<value>なし</value>
</data>
<data name="ClosePaneText" xml:space="preserve">
<value>ペインを閉じる</value>
<value>ウィンドウを閉じる</value>
</data>
<data name="ClosePaneToolTip" xml:space="preserve">
<value>複数のペインが存在する場合は、アクティブなペインを閉じます</value>
<value>複数のウィンドウが存在する場合は、アクティブなウィンドウを閉じます</value>
</data>
<data name="TabColorClearButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.FullDescription" xml:space="preserve">
<value>タブの色をリセット</value>
@@ -892,7 +896,7 @@
<comment>This text is displayed on context menu for profile entries in add new tab button.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>アクティブなペインを [{0}] タブに移動しました</value>
<value>アクティブなウィンドウを [{0}] タブに移動しました</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
@@ -908,19 +912,19 @@
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the new tab index in the tab row.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow" xml:space="preserve">
<value>アクティブなペインを "{1}" ウィンドウの [{0}] タブに移動しました</value>
<value>アクティブなウィンドウを "{1}" ウィンドウの [{0}] タブに移動しました</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to. {1} is the name of the window the pane was moved to. Replaced in 1.19 by TerminalPage_PaneMovedAnnouncement_ExistingWindow2</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>アクティブなペインを "{0}" ウィンドウに移動しました</value>
<value>アクティブなウィンドウを "{0}" ウィンドウに移動しました</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>アクティブなペインを新しいウィンドウに移動しました</value>
<value>アクティブなウィンドウを新しいウィンドウに移動しました</value>
<comment>This text is read out by screen readers upon a successful pane movement to a new window.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewTab" xml:space="preserve">
<value>アクティブなペインを新しいタブに移動しました</value>
<value>アクティブなウィンドウを新しいタブに移動しました</value>
<comment>This text is read out by screen readers upon a successful pane movement to a new tab within the existing window.</comment>
</data>
<data name="CmdAppendCommandLineDesc" xml:space="preserve">
@@ -930,7 +934,7 @@
<value>接続の再起動</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>アクティブ ペイン接続を再起動します</value>
<value>アクティブウィンドウ接続を再起動します</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>抜粋</value>
@@ -961,10 +965,10 @@
<value>操作の保存に失敗しました</value>
</data>
<data name="CloseSnippetsPaneButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>ペインを閉じる</value>
<value>ウィンドウを閉じる</value>
</data>
<data name="CloseSnippetsPaneButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>ペインを閉じる</value>
<value>ウィンドウを閉じる</value>
</data>
<data name="TabMoveLeft" xml:space="preserve">
<value>左へ移動</value>

View File

@@ -267,9 +267,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>탭 복제</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>설정에 지정된 하나 이상의 리소스(예: icon 또는 backgroundImage)찾을 수 없습니다.</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>잘못된 "backgroundImage" 프로필을 찾았습니다. 해당 프로필을 배경 이미지가 없는 기본값으로 설정합니다. "backgroundImage"설정할 때 값이 이미지에 대한 유효한 파일 경로인지 확인합니다.</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>잘못된 "icon"이 있는 프로필을 발견했습니다. 해당 프로필에 아이콘이 없도록 기본값을 설정합니다. "icon" 설정 시 값이 이미지에 대한 올바른 파일 경로인지 확인합니다.</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>키 바인딩 구문을 분석하는 동안 경고를 발견했습니다.</value>

View File

@@ -267,9 +267,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Duplicar guia</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>Um ou mais recursos (como icon ou backgroundImage) especificados em suas configurações não foram encontrados.</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>Foi encontrado um perfil com um "backgroundImage" inválido. O perfil deve ser o padrão para que não haja nenhuma imagem de tela de fundo. Certifique-se de que, ao definir um "backgroundImage", o valor é um caminho de arquivo válido para uma imagem.</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>Foi encontrado um perfil com um "icon" inválido. Padronize esse perfil para ele não ter ícone. Certifique-se de que, ao definir um "icon", o valor seja um caminho de arquivo válido para uma imagem.</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Os avisos foram encontrados durante a análise das suas ligações de teclas:</value>

View File

@@ -271,9 +271,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Ďϋφľіčάтέ τàв !!! </value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>Ωňę бггě яėŝǿüґсėş (šυćн âş icon ōя backgroundImage) ŝрěçìƒįєð ίπ ýőūŕ ŝėтťīлġš ċòŭĺð йöŧ вέ ƒòúпď. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! </value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>₣σúŋδ ą φѓοƒĩļé ẃϊţħ äй ïηνàĺìď "backgroundImage". Đēƒãųŀŧϊпğ ťнªт φѓőƒĭļè το нªνе πō ьąçќġгθúпδ ιмãġė. Маĸē śμѓē ŧћäţ ẁђēή šêťτϊлġ å "backgroundImage", ţĥě νаłųё ïŝ ά νάľîď ƒĩŀê φąťħ ţŏ άń ΐмąġė. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>₣ǿũиđ à рřöƒϊℓз ŵĩţн аñ įņνàŀїδ "icon". Ðěƒаúľτīŋğ ţħаτ ρřόƒìŀё тб ђâνє пǿ íčой. Мàĸë ŝùřë ŧĥаţ ωĥĕл ŝеτŧīлĝ ăй "icon", τħε νāłϋë ïŝ ă νàľīđ ƒïŀè рªтн ţő äи ïмäģё. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! </value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Щαѓńΐňģš ώĕřе ƒбŭπδ ώħīļë рăяşìⁿġ ўσυŕ κёỳвĩиðīήġş: !!! !!! !!! !!! !!!</value>

View File

@@ -271,9 +271,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Ďϋφľіčάтέ τàв !!! </value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>Ωňę бггě яėŝǿüґсėş (šυćн âş icon ōя backgroundImage) ŝрěçìƒįєð ίπ ýőūŕ ŝėтťīлġš ċòŭĺð йöŧ вέ ƒòúпď. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! </value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>₣σúŋδ ą φѓοƒĩļé ẃϊţħ äй ïηνàĺìď "backgroundImage". Đēƒãųŀŧϊпğ ťнªт φѓőƒĭļè το нªνе πō ьąçќġгθúпδ ιмãġė. Маĸē śμѓē ŧћäţ ẁђēή šêťτϊлġ å "backgroundImage", ţĥě νаłųё ïŝ ά νάľîď ƒĩŀê φąťħ ţŏ άń ΐмąġė. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>₣ǿũиđ à рřöƒϊℓз ŵĩţн аñ įņνàŀїδ "icon". Ðěƒаúľτīŋğ ţħаτ ρřόƒìŀё тб ђâνє пǿ íčой. Мàĸë ŝùřë ŧĥаţ ωĥĕл ŝеτŧīлĝ ăй "icon", τħε νāłϋë ïŝ ă νàľīđ ƒïŀè рªтн ţő äи ïмäģё. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! </value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Щαѓńΐňģš ώĕřе ƒбŭπδ ώħīļë рăяşìⁿġ ўσυŕ κёỳвĩиðīήġş: !!! !!! !!! !!! !!!</value>

View File

@@ -271,9 +271,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Ďϋφľіčάтέ τàв !!! </value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>Ωňę бггě яėŝǿüґсėş (šυćн âş icon ōя backgroundImage) ŝрěçìƒįєð ίπ ýőūŕ ŝėтťīлġš ċòŭĺð йöŧ вέ ƒòúпď. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! </value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>₣σúŋδ ą φѓοƒĩļé ẃϊţħ äй ïηνàĺìď "backgroundImage". Đēƒãųŀŧϊпğ ťнªт φѓőƒĭļè το нªνе πō ьąçќġгθúпδ ιмãġė. Маĸē śμѓē ŧћäţ ẁђēή šêťτϊлġ å "backgroundImage", ţĥě νаłųё ïŝ ά νάľîď ƒĩŀê φąťħ ţŏ άń ΐмąġė. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>₣ǿũиđ à рřöƒϊℓз ŵĩţн аñ įņνàŀїδ "icon". Ðěƒаúľτīŋğ ţħаτ ρřόƒìŀё тб ђâνє пǿ íčой. Мàĸë ŝùřë ŧĥаţ ωĥĕл ŝеτŧīлĝ ăй "icon", τħε νāłϋë ïŝ ă νàľīđ ƒïŀè рªтн ţő äи ïмäģё. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! </value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Щαѓńΐňģš ώĕřе ƒбŭπδ ώħīļë рăяşìⁿġ ўσυŕ κёỳвĩиðīήġş: !!! !!! !!! !!! !!!</value>

View File

@@ -267,9 +267,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>Дублировать вкладку</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>Не удалось найти один или несколько ресурсов (icon или backgroundImage), указанных в параметрах.</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>Найден профиль с недопустимым объектом "backgroundImage". По умолчанию для этого профиля не используется фоновое изображение. Убедитесь, что значение, заданное для "backgroundImage", является допустимым путем файла к изображению.</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>Найден профиль с недопустимым объектом "icon". По умолчанию для этого профиля не используется значок. Убедитесь, что значение, заданное для "icon", является допустимым путем файла к изображению.</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>При анализе настраиваемых сочетаний клавиш найдены предупреждения:</value>

View File

@@ -267,9 +267,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>复制标签页</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>找不到设置中指定的一个或多个资源 (,如 icon 或 backgroundImage)。</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>找到一个具有无效 "backgroundImage" 的配置文件。将该配置文件设置为默认设置为不包含背景图像。请确保在设置 "backgroundImage" 时,该值是指向图像的有效文件路径。</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>找到一个带有无效 "icon" 的配置文件。将该配置文件默认为无图标。确保设置 "icon" 时,该值是图像的有效文件路径。</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>分析键绑定时发现警告:</value>

View File

@@ -267,9 +267,13 @@
<data name="DuplicateTabText" xml:space="preserve">
<value>複製索引標籤</value>
</data>
<data name="InvalidMediaResource" xml:space="preserve">
<value>找不到一或多個資源 (,例如在您的設定中指定的 icon 或 backgroundImage)。</value>
<comment>{Locked="icon","backgroundImage"} Indicates that something has gone wrong while reading a user's settings.</comment>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>找到具有無效 "backgroundImage" 的設定檔。將該設定檔的預設值設為沒有背景影像。請確定設定 "backgroundImage" 時,該值是影像的有效檔案路徑。</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>已發現具有無效 "icon" 的設定檔。將該設定檔預設為無圖示。設定 "icon" 時,請確認值是有效的影像檔案路徑。</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>剖析金鑰繫結時發現警告:</value>

View File

@@ -48,22 +48,13 @@ namespace winrt::TerminalApp::implementation
{
_settings = settings;
const auto dispatcher = Dispatcher();
const auto weak = get_weak();
// You'd think that `FilterToSendInput(queryString)` would work. It
// doesn't! That uses the queryString as the current command the user
// has typed, then relies on the suggestions UI to _also_ filter with that
// string.
const auto tasks = co_await _settings.GlobalSettings().ActionMap().FilterToSnippets(winrt::hstring{}, winrt::hstring{}); // IVector<Model::Command>
co_await wil::resume_foreground(dispatcher);
const auto strong = weak.get();
if (!strong)
{
co_return;
}
co_await wil::resume_foreground(Dispatcher());
_allTasks.Clear();
for (const auto& t : tasks)

View File

@@ -1035,48 +1035,27 @@ namespace winrt::TerminalApp::implementation
void Tab::_AttachEventHandlersToContent(const uint32_t paneId, const TerminalApp::IPaneContent& content)
{
auto weakThis{ get_weak() };
auto dispatcher = DispatcherQueue::GetForCurrentThread();
auto dispatcher = TabViewItem().Dispatcher();
ContentEventTokens events{};
auto throttledTitleChanged = std::make_shared<ThrottledFunc<>>(
dispatcher,
til::throttled_func_options{
.delay = std::chrono::milliseconds{ 200 },
.leading = true,
.trailing = true,
},
[weakThis]() {
if (const auto tab = weakThis.get())
{
tab->UpdateTitle();
}
});
events.TitleChanged = content.TitleChanged(
winrt::auto_revoke,
[func = std::move(throttledTitleChanged)](auto&&, auto&&) {
func->Run();
});
auto throttledTaskbarProgressChanged = std::make_shared<ThrottledFunc<>>(
dispatcher,
til::throttled_func_options{
.delay = std::chrono::milliseconds{ 200 },
.trailing = true,
},
[weakThis]() {
if (const auto tab = weakThis.get())
[dispatcher, weakThis](auto&&, auto&&) -> safe_void_coroutine {
// The lambda lives in the `std::function`-style container owned by `control`. That is, when the
// `control` gets destroyed the lambda struct also gets destroyed. In other words, we need to
// copy `weakThis` onto the stack, because that's the only thing that gets captured in coroutines.
// See: https://devblogs.microsoft.com/oldnewthing/20211103-00/?p=105870
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
// Check if Tab's lifetime has expired
if (auto tab{ weakThisCopy.get() })
{
tab->_UpdateProgressState();
// The title of the control changed, but not necessarily the title of the tab.
// Set the tab's text to the active panes' text.
tab->UpdateTitle();
}
});
events.TaskbarProgressChanged = content.TaskbarProgressChanged(
winrt::auto_revoke,
[func = std::move(throttledTaskbarProgressChanged)](auto&&, auto&&) {
func->Run();
});
events.TabColorChanged = content.TabColorChanged(
winrt::auto_revoke,
[dispatcher, weakThis](auto&&, auto&&) -> safe_void_coroutine {
@@ -1092,6 +1071,18 @@ namespace winrt::TerminalApp::implementation
}
});
events.TaskbarProgressChanged = content.TaskbarProgressChanged(
winrt::auto_revoke,
[dispatcher, weakThis](auto&&, auto&&) -> safe_void_coroutine {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
// Check if Tab's lifetime has expired
if (auto tab{ weakThisCopy.get() })
{
tab->_UpdateProgressState();
}
});
events.ConnectionStateChanged = content.ConnectionStateChanged(
winrt::auto_revoke,
[dispatcher, weakThis](auto&&, auto&&) -> safe_void_coroutine {
@@ -2126,9 +2117,9 @@ namespace winrt::TerminalApp::implementation
// - The value to populate in the title run of the tool tip
winrt::hstring Tab::_CreateToolTipTitle()
{
if (const auto profile{ GetFocusedProfile() })
if (const auto& control{ GetActiveTerminalControl() })
{
const auto profileName{ profile.Name() };
const auto profileName{ control.Settings().ProfileName() };
if (profileName != Title())
{
return winrt::hstring{ fmt::format(FMT_COMPILE(L"{}: {}"), profileName, Title()) };
@@ -2417,7 +2408,7 @@ namespace winrt::TerminalApp::implementation
const auto& currentDictionary = v.as<ResourceDictionary>();
// TabViewItem.Background
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackground"), selectedTabBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackground"), deselectedTabBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackgroundSelected"), selectedTabBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPointerOver"), isHighContrast ? fontBrush : hoverTabBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPressed"), selectedTabBrush);

View File

@@ -21,8 +21,8 @@ namespace TerminalApp
UInt32 TabViewIndex;
UInt32 TabViewNumTabs;
void Focus(Windows.UI.Xaml.FocusState focusState);
void Shutdown();
overridable void Focus(Windows.UI.Xaml.FocusState focusState);
overridable void Shutdown();
void SetDispatch(ShortcutActionDispatch dispatch);
}

View File

@@ -157,7 +157,12 @@ namespace winrt::TerminalApp::implementation
// Set this tab's icon to the icon from the content
_UpdateTabIcon(*newTabImpl);
// This is necessary, because WinUI does not have support for middle clicks.
// Its Tapped event doesn't provide the information what button was used either.
tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabPointerPressed });
tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabPointerReleased });
tabViewItem.PointerExited({ this, &TerminalPage::_OnTabPointerExited });
tabViewItem.PointerEntered({ this, &TerminalPage::_OnTabPointerEntered });
// When the tab requests close, try to close it (prompt for approval, if required)
newTabImpl->CloseRequested([weakTab, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) {
@@ -397,18 +402,12 @@ namespace winrt::TerminalApp::implementation
// - tab: the tab to remove
winrt::Windows::Foundation::IAsyncAction TerminalPage::_HandleCloseTabRequested(winrt::TerminalApp::Tab tab)
{
winrt::com_ptr<TerminalPage> strong;
if (tab.ReadOnly())
{
const auto weak = get_weak();
auto warningResult = co_await _ShowCloseReadOnlyDialog();
strong = weak.get();
// If the user didn't explicitly click on close tab - leave
if (!strong || warningResult != ContentDialogResult::Primary)
if (warningResult != ContentDialogResult::Primary)
{
co_return;
}
@@ -665,7 +664,7 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - returns a tab corresponding to a view item. This might return null,
// so make sure to check the result!
winrt::TerminalApp::Tab TerminalPage::_GetTabByTabViewItem(const IInspectable& tabViewItem) const noexcept
winrt::TerminalApp::Tab TerminalPage::_GetTabByTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept
{
uint32_t tabIndexFromControl{};
const auto items{ _tabView.TabItems() };
@@ -719,14 +718,10 @@ namespace winrt::TerminalApp::implementation
{
if (pane->ContainsReadOnly())
{
const auto weak = get_weak();
auto warningResult = co_await _ShowCloseReadOnlyDialog();
const auto strong = weak.get();
// If the user didn't explicitly click on close tab - leave
if (!strong || warningResult != ContentDialogResult::Primary)
if (warningResult != ContentDialogResult::Primary)
{
co_return false;
}
@@ -784,13 +779,9 @@ namespace winrt::TerminalApp::implementation
if (const auto pane{ activeTab->GetActivePane() })
{
const auto weak = get_weak();
if (co_await _PaneConfirmCloseReadOnly(pane))
{
if (const auto strong = weak.get())
{
_HandleClosePaneRequested(pane);
}
_HandleClosePaneRequested(pane);
}
}
}
@@ -848,22 +839,9 @@ namespace winrt::TerminalApp::implementation
// - tabs - tabs to remove
safe_void_coroutine TerminalPage::_RemoveTabs(const std::vector<winrt::TerminalApp::Tab> tabs)
{
const auto weak = get_weak();
for (auto& tab : tabs)
{
winrt::Windows::Foundation::IAsyncAction action{ nullptr };
if (const auto strong = weak.get())
{
action = _HandleCloseTabRequested(tab);
}
if (!action)
{
co_return;
}
co_await action;
co_await _HandleCloseTabRequested(tab);
}
}
// Method Description:
@@ -898,69 +876,60 @@ namespace winrt::TerminalApp::implementation
_UpdateTabView();
}
void TerminalPage::_OnTabPointerPressed(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e)
// Method Description:
// - Additional responses to clicking on a TabView's item. Currently, just remove tab with middle click
// Arguments:
// - sender: the control that originated this event (TabViewItem)
// - eventArgs: the event's constituent arguments
void TerminalPage::_OnTabPointerPressed(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs)
{
if (!_tabItemMiddleClickHookEnabled || !e.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
if (eventArgs.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
{
return;
}
const auto tabViewItem = sender.try_as<MUX::Controls::TabViewItem>();
if (!tabViewItem || !tabViewItem.CapturePointer(e.Pointer()))
{
return;
}
_tabItemMiddleClickExited = false;
_tabItemMiddleClickPointerEntered = tabViewItem.PointerEntered(winrt::auto_revoke, [this](auto&&, auto&& e) {
_tabItemMiddleClickExited = false;
e.Handled(true);
});
_tabItemMiddleClickPointerExited = tabViewItem.PointerExited(winrt::auto_revoke, [this](auto&&, auto&& e) {
_tabItemMiddleClickExited = true;
e.Handled(true);
});
_tabItemMiddleClickPointerCaptureLost = tabViewItem.PointerCaptureLost(winrt::auto_revoke, [this](auto&& sender, auto&& e) {
// The WinUI TabView calls CapturePointer() internally and it's not reference counted,
// so when it calls ReleasePointerCapture() in its PointerReleased handler,
// we get a PointerCaptureLost before we receive the PointerReleased event.
// This makes typical handling of PointerReleased events on our side difficult.
// Well, whatever, now we just hook PointerCaptureLost because we know WinUI will trigger it.
_tabItemMiddleClickPointerEntered.revoke();
_tabItemMiddleClickPointerExited.revoke();
_tabItemMiddleClickPointerCaptureLost.revoke();
if (!_tabItemMiddleClickExited && !e.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
if (const auto tabViewItem{ sender.try_as<MUX::Controls::TabViewItem>() })
{
_OnTabPointerReleasedCloseTab(std::move(sender));
_tabPointerMiddleButtonPressed = tabViewItem.CapturePointer(eventArgs.Pointer());
_tabPointerMiddleButtonExited = false;
}
e.Handled(true);
});
e.Handled(true);
eventArgs.Handled(true);
}
}
safe_void_coroutine TerminalPage::_OnTabPointerReleasedCloseTab(IInspectable sender)
// Method Description:
// - Tracking pointer state for tab remove
// Arguments:
// - sender: the control that originated this event (TabViewItem)
// - eventArgs: the event's constituent arguments
void TerminalPage::_OnTabPointerReleased(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs)
{
// WinUI asynchronously updates its tab view items, so it may happen that we're given a
// `TabViewItem` that still contains a `Tab` which has actually already been removed.
// First we must yield once, to flush out whatever TabView is currently doing.
const auto weak = get_weak();
co_await wil::resume_foreground(Dispatcher());
const auto strong = weak.get();
if (!strong)
if (_tabPointerMiddleButtonPressed && !eventArgs.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
{
co_return;
_tabPointerMiddleButtonPressed = false;
if (auto tabViewItem{ sender.try_as<MUX::Controls::TabViewItem>() })
{
tabViewItem.ReleasePointerCapture(eventArgs.Pointer());
if (!_tabPointerMiddleButtonExited)
{
_OnTabPointerReleasedCloseTab(std::move(tabViewItem));
}
}
eventArgs.Handled(true);
}
}
safe_void_coroutine TerminalPage::_OnTabPointerReleasedCloseTab(winrt::Microsoft::UI::Xaml::Controls::TabViewItem sender)
{
const auto tab = _GetTabByTabViewItem(sender);
if (!tab)
{
co_return;
}
// WinUI asynchronously updates its tab view items, so it may happen that we're given a
// `TabViewItem` that still contains a `Tab` which has actually already been removed.
// First we must yield once, to flush out whatever TabView is currently doing.
const auto strong = get_strong();
co_await wil::resume_foreground(Dispatcher());
// `tab.Shutdown()` in `_RemoveTab()` sets the content to null = This checks if the tab is closed.
if (tab.Content())
{
@@ -968,6 +937,34 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - Tracking pointer state for tab remove
// Arguments:
// - sender: the control that originated this event (TabViewItem)
// - eventArgs: the event's constituent arguments
void TerminalPage::_OnTabPointerEntered(const IInspectable& /*sender*/, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs)
{
if (eventArgs.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
{
_tabPointerMiddleButtonExited = false;
eventArgs.Handled(true);
}
}
// Method Description:
// - Tracking pointer state for tab remove
// Arguments:
// - sender: the control that originated this event (TabViewItem)
// - eventArgs: the event's constituent arguments
void TerminalPage::_OnTabPointerExited(const IInspectable& /*sender*/, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs)
{
if (eventArgs.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
{
_tabPointerMiddleButtonExited = true;
eventArgs.Handled(true);
}
}
void TerminalPage::_UpdatedSelectedTab(const winrt::TerminalApp::Tab& tab)
{
// Unfocus all the tabs.
@@ -1002,7 +999,10 @@ namespace winrt::TerminalApp::implementation
tab.TabViewItem().StartBringIntoView();
// Raise an event that our title changed
TitleChanged.raise(*this, nullptr);
if (_settings.GlobalSettings().ShowTitleInTitlebar())
{
TitleChanged.raise(*this, tab.Title());
}
_updateThemeColors();
@@ -1012,8 +1012,6 @@ namespace winrt::TerminalApp::implementation
auto profile = tabImpl->GetFocusedProfile();
_UpdateBackground(profile);
}
_adjustProcessPriorityThrottled->Run();
}
CATCH_LOG();
}

View File

@@ -26,7 +26,6 @@
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalMUX>true</TerminalMUX>
<TerminalWinGetInterop>true</TerminalWinGetInterop>
<TerminalThemeHelpers>true</TerminalThemeHelpers>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
@@ -174,7 +173,9 @@
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClInclude>
<ClInclude Include="Toast.h" />
<ClInclude Include="TerminalSettingsCache.h" />
<ClInclude Include="TerminalSettingsCache.h">
<DependentUpon>TerminalSettingsCache.idl</DependentUpon>
</ClInclude>
<ClInclude Include="SuggestionsControl.h">
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
</ClInclude>
@@ -287,7 +288,9 @@
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="Toast.cpp" />
<ClCompile Include="TerminalSettingsCache.cpp" />
<ClCompile Include="TerminalSettingsCache.cpp">
<DependentUpon>TerminalSettingsCache.idl</DependentUpon>
</ClCompile>
<ClCompile Include="SuggestionsControl.cpp">
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
</ClCompile>
@@ -362,6 +365,7 @@
<DependentUpon>TaskPaneContent.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="TerminalSettingsCache.idl" />
<Midl Include="MarkdownPaneContent.idl">
<DependentUpon>MarkdownPaneContent.xaml</DependentUpon>
<SubType>Code</SubType>

View File

@@ -90,6 +90,7 @@
<Midl Include="TerminalWindow.idl" />
<Midl Include="TaskbarState.idl" />
<Midl Include="IPaneContent.idl" />
<Midl Include="TerminalSettingsCache.idl" />
<Midl Include="Monarch.idl" />
</ItemGroup>
<ItemGroup>

View File

@@ -6,8 +6,6 @@
#include "TerminalPage.h"
#include <LibraryResources.h>
#include <TerminalThemeHelpers.h>
#include <til/unicode.h>
#include <Utils.h>
#include <TerminalCore/ControlKeyStates.hpp>
@@ -19,7 +17,6 @@
#include "SettingsPaneContent.h"
#include "SnippetsPaneContent.h"
#include "TabRowControl.h"
#include "TerminalSettingsCache.h"
#include "../../types/inc/ColorFix.hpp"
#include "../../types/inc/utils.hpp"
@@ -59,160 +56,6 @@ namespace winrt
using VirtualKeyModifiers = Windows::System::VirtualKeyModifiers;
}
namespace clipboard
{
static SRWLOCK lock = SRWLOCK_INIT;
struct ClipboardHandle
{
explicit ClipboardHandle(bool open) :
_open{ open }
{
}
~ClipboardHandle()
{
if (_open)
{
ReleaseSRWLockExclusive(&lock);
CloseClipboard();
}
}
explicit operator bool() const noexcept
{
return _open;
}
private:
bool _open = false;
};
ClipboardHandle open(HWND hwnd)
{
// Turns out, OpenClipboard/CloseClipboard are not thread-safe whatsoever,
// and on CloseClipboard, the GetClipboardData handle may get freed.
// The problem is that WinUI also uses OpenClipboard (through WinRT which uses OLE),
// and so even with this mutex we can still crash randomly if you copy something via WinUI.
// Makes you wonder how many Windows apps are subtly broken, huh.
AcquireSRWLockExclusive(&lock);
bool success = false;
// OpenClipboard may fail to acquire the internal lock --> retry.
for (DWORD sleep = 10;; sleep *= 2)
{
if (OpenClipboard(hwnd))
{
success = true;
break;
}
// 10 iterations
if (sleep > 10000)
{
break;
}
Sleep(sleep);
}
if (!success)
{
ReleaseSRWLockExclusive(&lock);
}
return ClipboardHandle{ success };
}
void write(wil::zwstring_view text, std::string_view html, std::string_view rtf)
{
static const auto regular = [](const UINT format, const void* src, const size_t bytes) {
wil::unique_hglobal handle{ THROW_LAST_ERROR_IF_NULL(GlobalAlloc(GMEM_MOVEABLE, bytes)) };
const auto locked = GlobalLock(handle.get());
memcpy(locked, src, bytes);
GlobalUnlock(handle.get());
THROW_LAST_ERROR_IF_NULL(SetClipboardData(format, handle.get()));
handle.release();
};
static const auto registered = [](const wchar_t* format, const void* src, size_t bytes) {
const auto id = RegisterClipboardFormatW(format);
if (!id)
{
LOG_LAST_ERROR();
return;
}
regular(id, src, bytes);
};
EmptyClipboard();
if (!text.empty())
{
// As per: https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats
// CF_UNICODETEXT: [...] A null character signals the end of the data.
// --> We add +1 to the length. This works because .c_str() is null-terminated.
regular(CF_UNICODETEXT, text.c_str(), (text.size() + 1) * sizeof(wchar_t));
}
if (!html.empty())
{
registered(L"HTML Format", html.data(), html.size());
}
if (!rtf.empty())
{
registered(L"Rich Text Format", rtf.data(), rtf.size());
}
}
winrt::hstring read()
{
// This handles most cases of pasting text as the OS converts most formats to CF_UNICODETEXT automatically.
if (const auto handle = GetClipboardData(CF_UNICODETEXT))
{
const wil::unique_hglobal_locked lock{ handle };
const auto str = static_cast<const wchar_t*>(lock.get());
if (!str)
{
return {};
}
const auto maxLen = GlobalSize(handle) / sizeof(wchar_t);
const auto len = wcsnlen(str, maxLen);
return winrt::hstring{ str, gsl::narrow_cast<uint32_t>(len) };
}
// We get CF_HDROP when a user copied a file with Ctrl+C in Explorer and pastes that into the terminal (among others).
if (const auto handle = GetClipboardData(CF_HDROP))
{
const wil::unique_hglobal_locked lock{ handle };
const auto drop = static_cast<HDROP>(lock.get());
if (!drop)
{
return {};
}
const auto cap = DragQueryFileW(drop, 0, nullptr, 0);
if (cap == 0)
{
return {};
}
auto buffer = winrt::impl::hstring_builder{ cap };
const auto len = DragQueryFileW(drop, 0, buffer.data(), cap + 1);
if (len == 0)
{
return {};
}
return buffer.to_hstring();
}
return {};
}
} // namespace clipboard
namespace winrt::TerminalApp::implementation
{
TerminalPage::TerminalPage(TerminalApp::WindowProperties properties, const TerminalApp::ContentManager& manager) :
@@ -259,17 +102,6 @@ namespace winrt::TerminalApp::implementation
// before restoring previous tabs in that scenario.
}
}
_adjustProcessPriorityThrottled = std::make_shared<ThrottledFunc<>>(
DispatcherQueue::GetForCurrentThread(),
til::throttled_func_options{
.delay = std::chrono::milliseconds{ 100 },
.debounce = true,
.trailing = true,
},
[=]() {
_adjustProcessPriority();
});
_hostingHwnd = hwnd;
return S_OK;
}
@@ -281,7 +113,7 @@ namespace winrt::TerminalApp::implementation
if (_settings == nullptr)
{
// Create this only on the first time we load the settings.
_terminalSettingsCache = std::make_shared<TerminalSettingsCache>(settings, *_bindings);
_terminalSettingsCache = TerminalApp::TerminalSettingsCache{ settings, *_bindings };
}
_settings = settings;
@@ -384,8 +216,6 @@ namespace winrt::TerminalApp::implementation
{
const auto visibility = theme.Tab() ? theme.Tab().ShowCloseButton() : Settings::Model::TabCloseButtonVisibility::Always;
_tabItemMiddleClickHookEnabled = visibility == Settings::Model::TabCloseButtonVisibility::Never;
switch (visibility)
{
case Settings::Model::TabCloseButtonVisibility::Never:
@@ -715,32 +545,22 @@ namespace winrt::TerminalApp::implementation
_WindowProperties.VirtualEnvVars(env);
}
// The current TerminalWindow & TerminalPage architecture is rather instable
// and fails to start up if the first tab isn't created synchronously.
//
// While that's a fair assumption in on itself, simultaneously WinUI will
// not assign tab contents a size if they're not shown at least once,
// which we need however in order to initialize ControlCore with a size.
//
// So, we do two things here:
// * DO NOT suspend if this is the first tab.
// * DO suspend between the creation of panes (or tabs) in order to allow
// WinUI to layout the new controls and for ControlCore to get a size.
//
// This same logic is also applied to CreateTabFromConnection.
//
// See GH#13136.
auto suspend = _tabs.Size() > 0;
for (size_t i = 0; i < actions.size(); ++i)
{
if (suspend)
if (i != 0)
{
// Each action may rely on the XAML layout of a preceding action.
// Most importantly, this is the case for the combination of NewTab + SplitPane,
// as the former appears to only have a layout size after at least 1 resume_foreground,
// while the latter relies on that information. This is also why it uses Low priority.
//
// Curiously, this does not seem to be required when using startupActions, but only when
// tearing out a tab (this currently creates a new window with injected startup actions).
// This indicates that this is really more of an architectural issue and not a fundamental one.
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Low);
}
_actionDispatch->DoAction(actions[i]);
suspend = true;
}
// GH#6586: now that we're done processing all startup commands,
@@ -755,16 +575,8 @@ namespace winrt::TerminalApp::implementation
}
}
safe_void_coroutine TerminalPage::CreateTabFromConnection(ITerminalConnection connection)
void TerminalPage::CreateTabFromConnection(ITerminalConnection connection)
{
const auto strong = get_strong();
// This is the exact same logic as in ProcessStartupActions.
if (_tabs.Size() > 0)
{
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Low);
}
NewTerminalArgs newTerminalArgs;
if (const auto conpty = connection.try_as<ConptyConnection>())
@@ -779,7 +591,6 @@ namespace winrt::TerminalApp::implementation
// elevated version of the Terminal with that profile... that's a
// recipe for disaster. We won't ever open up a tab in this window.
newTerminalArgs.Elevate(false);
const auto newPane = _MakePane(newTerminalArgs, nullptr, std::move(connection));
newPane->WalkTree([](const auto& pane) {
pane->FinalizeConfigurationGivenDefault();
@@ -1112,7 +923,7 @@ namespace winrt::TerminalApp::implementation
auto folderEntryItems = _CreateNewTabFlyoutItems(folderEntries);
// If the folder should auto-inline and there is only one item, do so.
if (folderEntry.Inlining() == FolderEntryInlining::Auto && folderEntryItems.size() == 1)
if (folderEntry.Inlining() == FolderEntryInlining::Auto && folderEntries.Size() == 1)
{
for (auto const& folderEntryItem : folderEntryItems)
{
@@ -1126,7 +937,7 @@ namespace winrt::TerminalApp::implementation
auto folderItem = WUX::Controls::MenuFlyoutSubItem{};
folderItem.Text(folderEntry.Name());
auto icon = _CreateNewTabFlyoutIcon(folderEntry.Icon().Resolved());
auto icon = _CreateNewTabFlyoutIcon(folderEntry.Icon());
folderItem.Icon(icon);
for (const auto& folderEntryItem : folderEntryItems)
@@ -1176,7 +987,7 @@ namespace winrt::TerminalApp::implementation
break;
}
auto profileItem = _CreateNewTabFlyoutProfile(profileEntry.Profile(), profileEntry.ProfileIndex(), profileEntry.Icon().Resolved());
auto profileItem = _CreateNewTabFlyoutProfile(profileEntry.Profile(), profileEntry.ProfileIndex(), profileEntry.Icon());
items.push_back(profileItem);
break;
}
@@ -1186,7 +997,7 @@ namespace winrt::TerminalApp::implementation
const auto actionId = actionEntry.ActionId();
if (_settings.ActionMap().GetActionByID(actionId))
{
auto actionItem = _CreateNewTabFlyoutAction(actionId, actionEntry.Icon().Resolved());
auto actionItem = _CreateNewTabFlyoutAction(actionId, actionEntry.Icon());
items.push_back(actionItem);
}
@@ -1225,7 +1036,7 @@ namespace winrt::TerminalApp::implementation
// If a custom icon path has been specified, set it as the icon for
// this flyout item. Otherwise, if an icon is set for this profile, set that icon
// for this flyout item.
const auto& iconPath = iconPathOverride.empty() ? profile.Icon().Resolved() : iconPathOverride;
const auto& iconPath = iconPathOverride.empty() ? profile.EvaluatedIcon() : iconPathOverride;
if (!iconPath.empty())
{
const auto icon = _CreateNewTabFlyoutIcon(iconPath);
@@ -1311,7 +1122,7 @@ namespace winrt::TerminalApp::implementation
// If a custom icon path has been specified, set it as the icon for
// this flyout item. Otherwise, if an icon is set for this action, set that icon
// for this flyout item.
const auto& iconPath = iconPathOverride.empty() ? action.Icon().Resolved() : iconPathOverride;
const auto& iconPath = iconPathOverride.empty() ? action.IconPath() : iconPathOverride;
if (!iconPath.empty())
{
const auto icon = _CreateNewTabFlyoutIcon(iconPath);
@@ -1490,8 +1301,18 @@ namespace winrt::TerminalApp::implementation
if (connectionType == TerminalConnection::AzureConnection::ConnectionType() &&
TerminalConnection::AzureConnection::IsAzureConnectionAvailable())
{
connection = TerminalConnection::AzureConnection{};
valueSet = TerminalConnection::ConptyConnection::CreateSettings(winrt::hstring{},
std::filesystem::path azBridgePath{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
azBridgePath.replace_filename(L"TerminalAzBridge.exe");
if constexpr (Feature_AzureConnectionInProc::IsEnabled())
{
connection = TerminalConnection::AzureConnection{};
}
else
{
connection = TerminalConnection::ConptyConnection{};
}
valueSet = TerminalConnection::ConptyConnection::CreateSettings(azBridgePath.native(),
L".",
L"Azure",
false,
@@ -1936,9 +1757,11 @@ namespace winrt::TerminalApp::implementation
// - tab: the Tab to update the title for.
void TerminalPage::_UpdateTitle(const Tab& tab)
{
auto newTabTitle = tab.Title();
if (tab == _GetFocusedTab())
{
TitleChanged.raise(*this, nullptr);
TitleChanged.raise(*this, newTabTitle);
}
}
@@ -1953,7 +1776,7 @@ namespace winrt::TerminalApp::implementation
{
term.RaiseNotice({ this, &TerminalPage::_ControlNoticeRaisedHandler });
term.WriteToClipboard({ get_weak(), &TerminalPage::_copyToClipboard });
// Add an event handler when the terminal wants to paste data from the Clipboard.
term.PasteFromClipboard({ this, &TerminalPage::_PasteFromClipboardHandler });
term.OpenHyperlink({ this, &TerminalPage::_OpenHyperlinkHandler });
@@ -1975,7 +1798,9 @@ namespace winrt::TerminalApp::implementation
});
term.ShowWindowChanged({ get_weak(), &TerminalPage::_ShowWindowChangedHandler });
term.SearchMissingCommand({ get_weak(), &TerminalPage::_SearchMissingCommandHandler });
term.WindowSizeChanged({ get_weak(), &TerminalPage::_WindowSizeChanged });
// Don't even register for the event if the feature is compiled off.
@@ -2121,7 +1946,7 @@ namespace winrt::TerminalApp::implementation
return false;
}
TermControl TerminalPage::_GetActiveControl() const
TermControl TerminalPage::_GetActiveControl()
{
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
@@ -2206,15 +2031,7 @@ namespace winrt::TerminalApp::implementation
if (!_displayingCloseDialog)
{
_displayingCloseDialog = true;
const auto weak = get_weak();
auto warningResult = co_await _ShowQuitDialog();
const auto strong = weak.get();
if (!strong)
{
co_return;
}
_displayingCloseDialog = false;
if (warningResult != ContentDialogResult::Primary)
@@ -2590,8 +2407,6 @@ namespace winrt::TerminalApp::implementation
auto profile = tab->GetFocusedProfile();
_UpdateBackground(profile);
}
_adjustProcessPriorityThrottled->Run();
}
uint32_t TerminalPage::NumberOfTabs() const
@@ -2810,9 +2625,17 @@ namespace winrt::TerminalApp::implementation
{
if (_settings.GlobalSettings().ShowTitleInTitlebar())
{
if (const auto tab{ _GetFocusedTab() })
auto selectedIndex = _tabView.SelectedIndex();
if (selectedIndex >= 0)
{
return tab.Title();
try
{
if (auto focusedControl{ _GetActiveControl() })
{
return focusedControl.Title();
}
}
CATCH_LOG();
}
}
return { L"Terminal" };
@@ -2907,6 +2730,75 @@ namespace winrt::TerminalApp::implementation
return dimension;
}
static wil::unique_close_clipboard_call _openClipboard(HWND hwnd)
{
bool success = false;
// OpenClipboard may fail to acquire the internal lock --> retry.
for (DWORD sleep = 10;; sleep *= 2)
{
if (OpenClipboard(hwnd))
{
success = true;
break;
}
// 10 iterations
if (sleep > 10000)
{
break;
}
Sleep(sleep);
}
return wil::unique_close_clipboard_call{ success };
}
static winrt::hstring _extractClipboard()
{
// This handles most cases of pasting text as the OS converts most formats to CF_UNICODETEXT automatically.
if (const auto handle = GetClipboardData(CF_UNICODETEXT))
{
const wil::unique_hglobal_locked lock{ handle };
const auto str = static_cast<const wchar_t*>(lock.get());
if (!str)
{
return {};
}
const auto maxLen = GlobalSize(handle) / sizeof(wchar_t);
const auto len = wcsnlen(str, maxLen);
return winrt::hstring{ str, gsl::narrow_cast<uint32_t>(len) };
}
// We get CF_HDROP when a user copied a file with Ctrl+C in Explorer and pastes that into the terminal (among others).
if (const auto handle = GetClipboardData(CF_HDROP))
{
const wil::unique_hglobal_locked lock{ handle };
const auto drop = static_cast<HDROP>(lock.get());
if (!drop)
{
return {};
}
const auto cap = DragQueryFileW(drop, 0, nullptr, 0);
if (cap == 0)
{
return {};
}
auto buffer = winrt::impl::hstring_builder{ cap };
const auto len = DragQueryFileW(drop, 0, buffer.data(), cap + 1);
if (len == 0)
{
return {};
}
return buffer.to_hstring();
}
return {};
}
// Function Description:
// - This function is called when the `TermControl` requests that we send
// it the clipboard's content.
@@ -2926,55 +2818,36 @@ namespace winrt::TerminalApp::implementation
const auto weakThis = get_weak();
const auto dispatcher = Dispatcher();
const auto globalSettings = _settings.GlobalSettings();
const auto bracketedPaste = eventArgs.BracketedPasteEnabled();
// GetClipboardData might block for up to 30s for delay-rendered contents.
co_await winrt::resume_background();
winrt::hstring text;
if (const auto clipboard = clipboard::open(nullptr))
if (const auto clipboard = _openClipboard(nullptr))
{
text = clipboard::read();
text = _extractClipboard();
}
if (!bracketedPaste && globalSettings.TrimPaste())
if (globalSettings.TrimPaste())
{
text = winrt::hstring{ Utils::TrimPaste(text) };
}
// LOAD BEARING: Send an empty bracketed paste even if the clipboard was empty.
// Bracketed Paste provides an application a way to know whether the
// user pasted, even if there was no applicable content on it. This
// behavior is observed in GNOME Terminal, among others.
if (!bracketedPaste && text.empty())
{
co_return;
}
bool warnMultiLine = false;
switch (globalSettings.WarnAboutMultiLinePaste())
{
case WarnAboutMultiLinePaste::Automatic:
// NOTE that this is unsafe, because a shell that doesn't support bracketed paste
// will allow an attacker to enable the mode, not realize that, and then accept
// the paste as if it was a series of legitimate commands. See GH#13014.
warnMultiLine = !bracketedPaste;
break;
case WarnAboutMultiLinePaste::Always:
warnMultiLine = true;
break;
default:
warnMultiLine = false;
break;
text = { Utils::TrimPaste(text) };
if (text.empty())
{
// Text is all white space, nothing to paste
co_return;
}
}
// If the requesting terminal is in bracketed paste mode, then we don't need to warn about a multi-line paste.
auto warnMultiLine = globalSettings.WarnAboutMultiLinePaste() && !eventArgs.BracketedPasteEnabled();
if (warnMultiLine)
{
const std::wstring_view view{ text };
warnMultiLine = view.find_first_of(L"\r\n") != std::wstring_view::npos;
const auto isNewLineLambda = [](auto c) { return c == L'\n' || c == L'\r'; };
const auto hasNewLine = std::find_if(text.cbegin(), text.cend(), isNewLineLambda) != text.cend();
warnMultiLine = hasNewLine;
}
constexpr std::size_t minimumSizeForWarning = 1024 * 5; // 5 KiB
constexpr const std::size_t minimumSizeForWarning = 1024 * 5; // 5 KiB
const auto warnLargeText = text.size() > minimumSizeForWarning && globalSettings.WarnAboutLargePaste();
if (warnMultiLine || warnLargeText)
@@ -2984,20 +2857,8 @@ namespace winrt::TerminalApp::implementation
if (const auto strongThis = weakThis.get())
{
// We have to initialize the dialog here to be able to change the text of the text block within it
std::ignore = FindName(L"MultiLinePasteDialog");
// WinUI absolutely cannot deal with large amounts of text (at least O(n), possibly O(n^2),
// so we limit the string length here and add an ellipsis if necessary.
auto clipboardText = text;
if (clipboardText.size() > 1024)
{
const std::wstring_view view{ text };
// Make sure we don't cut in the middle of a surrogate pair
const auto len = til::utf16_iterate_prev(view, 512);
clipboardText = til::hstring_format(FMT_COMPILE(L"{}\n"), view.substr(0, len));
}
ClipboardText().Text(std::move(clipboardText));
FindName(L"MultiLinePasteDialog").try_as<WUX::Controls::ContentDialog>();
ClipboardText().Text(text);
// The vertical offset on the scrollbar does not reset automatically, so reset it manually
ClipboardContentScrollViewer().ScrollToVerticalOffset(0);
@@ -3013,7 +2874,7 @@ namespace winrt::TerminalApp::implementation
}
// Clear the clipboard text so it doesn't lie around in memory
ClipboardText().Text({});
ClipboardText().Text(L"");
if (warningResult != ContentDialogResult::Primary)
{
@@ -3177,7 +3038,7 @@ namespace winrt::TerminalApp::implementation
// - formats: dictate which formats need to be copied
// Return Value:
// - true iff we we able to copy text (if a selection was active)
bool TerminalPage::_CopyText(const bool dismissSelection, const bool singleLine, const bool withControlSequences, const CopyFormat formats)
bool TerminalPage::_CopyText(const bool dismissSelection, const bool singleLine, const bool withControlSequences, const Windows::Foundation::IReference<CopyFormat>& formats)
{
if (const auto& control{ _GetActiveControl() })
{
@@ -3193,12 +3054,8 @@ namespace winrt::TerminalApp::implementation
// - eventArgs: the arguments specifying how to set the progress indicator
safe_void_coroutine TerminalPage::_SetTaskbarProgressHandler(const IInspectable /*sender*/, const IInspectable /*eventArgs*/)
{
const auto weak = get_weak();
co_await wil::resume_foreground(Dispatcher());
if (const auto strong = weak.get())
{
SetTaskbarProgress.raise(*this, nullptr);
}
SetTaskbarProgress.raise(*this, nullptr);
}
// Method Description:
@@ -3235,17 +3092,33 @@ namespace winrt::TerminalApp::implementation
}
PackageCatalog catalog = connectResult.PackageCatalog();
// clang-format off
static constexpr std::array<WinGetSearchParams, 3> searches{ {
{ .Field = PackageMatchField::Command, .MatchOption = PackageFieldMatchOption::StartsWithCaseInsensitive },
{ .Field = PackageMatchField::Name, .MatchOption = PackageFieldMatchOption::ContainsCaseInsensitive },
{ .Field = PackageMatchField::Moniker, .MatchOption = PackageFieldMatchOption::ContainsCaseInsensitive } } };
// clang-format on
PackageMatchFilter filter = WindowsPackageManagerFactory::CreatePackageMatchFilter();
filter.Value(query);
filter.Field(PackageMatchField::Command);
filter.Option(PackageFieldMatchOption::Equals);
FindPackagesOptions options = WindowsPackageManagerFactory::CreateFindPackagesOptions();
options.Filters().Append(filter);
options.ResultLimit(20);
const auto result = co_await catalog.FindPackagesAsync(options);
const IVectorView<MatchResult> pkgList = result.Matches();
IVectorView<MatchResult> pkgList;
for (const auto& search : searches)
{
filter.Field(search.Field);
filter.Option(search.MatchOption);
const auto result = co_await catalog.FindPackagesAsync(options);
pkgList = result.Matches();
if (pkgList.Size() > 0)
{
break;
}
}
co_return pkgList;
}
@@ -3255,12 +3128,6 @@ namespace winrt::TerminalApp::implementation
{
co_return;
}
const auto weak = get_weak();
const auto dispatcher = Dispatcher();
// All of the code until resume_foreground is static and
// doesn't touch `this`, so we don't need weak/strong_ref.
co_await winrt::resume_background();
// no packages were found, nothing to suggest
@@ -3278,12 +3145,7 @@ namespace winrt::TerminalApp::implementation
suggestions.emplace_back(fmt::format(FMT_COMPILE(L"winget install --id {} -s winget"), pkg.CatalogPackage().Id()));
}
co_await wil::resume_foreground(dispatcher);
const auto strong = weak.get();
if (!strong)
{
co_return;
}
co_await wil::resume_foreground(Dispatcher());
auto term = _GetActiveControl();
if (!term)
@@ -3319,21 +3181,6 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPage::_copyToClipboard(const IInspectable, const WriteToClipboardEventArgs args) const
{
if (const auto clipboard = clipboard::open(_hostingHwnd.value_or(nullptr)))
{
const auto plain = args.Plain();
const auto html = args.Html();
const auto rtf = args.Rtf();
clipboard::write(
{ plain.data(), plain.size() },
{ reinterpret_cast<const char*>(html.data()), html.size() },
{ reinterpret_cast<const char*>(rtf.data()), rtf.size() });
}
}
// Method Description:
// - Paste text from the Windows Clipboard to the focused terminal
void TerminalPage::_PasteText()
@@ -3378,9 +3225,6 @@ namespace winrt::TerminalApp::implementation
// UI) thread. This is IMPORTANT, because the Windows.Storage API's
// (used for retrieving the path to the file) will crash on the UI
// thread, because the main thread is a STA.
//
// NOTE: All remaining code of this function doesn't touch `this`, so we don't need weak/strong_ref.
// NOTE NOTE: Don't touch `this` when you make changes here.
co_await winrt::resume_background();
auto openFile = [](const auto& filePath) {
@@ -3707,13 +3551,7 @@ namespace winrt::TerminalApp::implementation
// for nulls
if (const auto& connection{ _duplicateConnectionForRestart(paneContent) })
{
// Reset the terminal's VT state before attaching the new connection.
// The previous client may have left dirty modes (e.g., bracketed
// paste, mouse tracking, alternate buffer, kitty keyboard) that
// would corrupt input/output for the new shell process.
const auto& termControl = paneContent.GetTermControl();
termControl.HardResetWithoutErase();
termControl.Connection(connection);
paneContent.GetTermControl().Connection(connection);
connection.Start();
}
}
@@ -3733,7 +3571,7 @@ namespace winrt::TerminalApp::implementation
return;
}
const auto path = newAppearance.BackgroundImagePath().Resolved();
const auto path = newAppearance.ExpandedBackgroundImagePath();
if (path.empty())
{
_tabContent.Background(nullptr);
@@ -3798,7 +3636,7 @@ namespace winrt::TerminalApp::implementation
// updating terminal panes, so that we don't have to build a _new_
// TerminalSettings for every profile we update - we can just look them
// up the previous ones we built.
_terminalSettingsCache->Reset(_settings, *_bindings);
_terminalSettingsCache.Reset(_settings, *_bindings);
for (const auto& tab : _tabs)
{
@@ -3856,9 +3694,6 @@ namespace winrt::TerminalApp::implementation
_updateThemeColors();
_updateAllTabCloseButtons();
// The user may have changed the "show title in titlebar" setting.
TitleChanged.raise(*this, nullptr);
}
void TerminalPage::_updateAllTabCloseButtons()
@@ -3872,8 +3707,6 @@ namespace winrt::TerminalApp::implementation
theme.Tab().ShowCloseButton() :
Settings::Model::TabCloseButtonVisibility::Always;
_tabItemMiddleClickHookEnabled = visibility == Settings::Model::TabCloseButtonVisibility::Never;
for (const auto& tab : _tabs)
{
tab.CloseButtonVisibility(visibility);
@@ -4745,23 +4578,14 @@ namespace winrt::TerminalApp::implementation
// - sender: the ICoreState instance containing the connection state
// Return Value:
// - <none>
safe_void_coroutine TerminalPage::_ConnectionStateChangedHandler(const IInspectable& sender, const IInspectable& /*args*/)
safe_void_coroutine TerminalPage::_ConnectionStateChangedHandler(const IInspectable& sender, const IInspectable& /*args*/) const
{
if (const auto coreState{ sender.try_as<winrt::Microsoft::Terminal::Control::ICoreState>() })
{
const auto newConnectionState = coreState.ConnectionState();
const auto weak = get_weak();
co_await wil::resume_foreground(Dispatcher());
const auto strong = weak.get();
if (!strong)
{
co_return;
}
_adjustProcessPriorityThrottled->Run();
if (newConnectionState == ConnectionState::Failed && !_IsMessageDismissed(InfoBarMessage::CloseOnExitInfo))
{
co_await wil::resume_foreground(Dispatcher());
if (const auto infoBar = FindName(L"CloseOnExitInfoBar").try_as<MUX::Controls::InfoBar>())
{
infoBar.IsOpen(true);
@@ -4894,18 +4718,8 @@ namespace winrt::TerminalApp::implementation
}
}
// GH#19604: Get the theme's tabRow color to use as the acrylic tint.
const auto tabRowBg{ theme.TabRow() ? (_activated ? theme.TabRow().Background() :
theme.TabRow().UnfocusedBackground()) :
ThemeColor{ nullptr } };
if (_settings.GlobalSettings().UseAcrylicInTabRow() && (_activated || _settings.GlobalSettings().EnableUnfocusedAcrylic()))
if (_settings.GlobalSettings().UseAcrylicInTabRow())
{
if (tabRowBg)
{
bgColor = ThemeColor::ColorFromBrush(tabRowBg.Evaluate(res, terminalBrush, true));
}
const auto acrylicBrush = Media::AcrylicBrush();
acrylicBrush.BackgroundSource(Media::AcrylicBackgroundSource::HostBackdrop);
acrylicBrush.FallbackColor(bgColor);
@@ -4914,7 +4728,9 @@ namespace winrt::TerminalApp::implementation
TitlebarBrush(acrylicBrush);
}
else if (tabRowBg)
else if (auto tabRowBg{ theme.TabRow() ? (_activated ? theme.TabRow().Background() :
theme.TabRow().UnfocusedBackground()) :
ThemeColor{ nullptr } })
{
const auto themeBrush{ tabRowBg.Evaluate(res, terminalBrush, true) };
bgColor = ThemeColor::ColorFromBrush(themeBrush);
@@ -5034,94 +4850,6 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPage::_adjustProcessPriority() const
{
// Windowing is single-threaded, so this will not cause a race condition.
static bool supported{ true };
if (!supported || !_hostingHwnd.has_value())
{
return;
}
std::array<HANDLE, 32> processes;
auto it = processes.begin();
const auto end = processes.end();
auto&& appendFromControl = [&](auto&& control) {
if (it == end)
{
return;
}
if (control)
{
if (const auto conn{ control.Connection() })
{
if (const auto pty{ conn.try_as<winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection>() })
{
if (const uint64_t process{ pty.RootProcessHandle() }; process != 0)
{
*it++ = reinterpret_cast<HANDLE>(process);
}
}
}
}
};
auto&& appendFromTab = [&](auto&& tabImpl) {
if (const auto pane{ tabImpl->GetRootPane() })
{
pane->WalkTree([&](auto&& child) {
if (const auto& control{ child->GetTerminalControl() })
{
appendFromControl(control);
}
});
}
};
if (!_activated)
{
// When a window is out of focus, we want to attach all of the processes
// under it to the window so they all go into the background at the same time.
for (auto&& tab : _tabs)
{
if (auto tabImpl{ _GetTabImpl(tab) })
{
appendFromTab(tabImpl);
}
}
}
else
{
// When a window is in focus, propagate our foreground boost (if we have one)
// to current all panes in the current tab.
if (auto tabImpl{ _GetFocusedTabImpl() })
{
appendFromTab(tabImpl);
}
}
const auto count{ gsl::narrow_cast<DWORD>(it - processes.begin()) };
const auto hr = TerminalTrySetWindowAssociatedProcesses(_hostingHwnd.value(), count, count ? processes.data() : nullptr);
if (S_FALSE == hr)
{
// Don't bother trying again or logging. The wrapper tells us it's unsupported.
supported = false;
return;
}
TraceLoggingWrite(
g_hTerminalAppProvider,
"CalledNewQoSAPI",
TraceLoggingValue(reinterpret_cast<uintptr_t>(_hostingHwnd.value()), "hwnd"),
TraceLoggingValue(count),
TraceLoggingHResult(hr));
#ifdef _DEBUG
OutputDebugStringW(fmt::format(FMT_COMPILE(L"Submitted {} processes to TerminalTrySetWindowAssociatedProcesses; return=0x{:08x}\n"), count, hr).c_str());
#endif
}
void TerminalPage::WindowActivated(const bool activated)
{
// Stash if we're activated. Use that when we reload
@@ -5129,8 +4857,6 @@ namespace winrt::TerminalApp::implementation
_activated = activated;
_updateThemeColors();
_adjustProcessPriorityThrottled->Run();
if (const auto& tab{ _GetFocusedTabImpl() })
{
if (tab->TabStatus().IsInputBroadcastActive())
@@ -5150,6 +4876,8 @@ namespace winrt::TerminalApp::implementation
safe_void_coroutine TerminalPage::_ControlCompletionsChangedHandler(const IInspectable sender,
const CompletionsChangedEventArgs args)
{
// This will come in on a background (not-UI, not output) thread.
// This won't even get hit if the velocity flag is disabled - we gate
// registering for the event based off of
// Feature_ShellCompletions::IsEnabled back in _RegisterTerminalEvents
@@ -5323,7 +5051,7 @@ namespace winrt::TerminalApp::implementation
makeItem(RS_(L"DuplicateTabText"), L"\xF5ED", ActionAndArgs{ ShortcutAction::DuplicateTab, nullptr }, menu);
const auto focusedProfileName = focusedProfile.Name();
const auto focusedProfileIcon = focusedProfile.Icon().Resolved();
const auto focusedProfileIcon = focusedProfile.Icon();
const auto splitPaneDuplicateText = RS_(L"SplitPaneDuplicateText") + L" " + focusedProfileName; // SplitPaneDuplicateText
const auto splitPaneRightText = RS_(L"SplitPaneRightText");
@@ -5349,7 +5077,7 @@ namespace winrt::TerminalApp::implementation
{
const auto profile = activeProfiles.GetAt(profileIndex);
const auto profileName = profile.Name();
const auto profileIcon = profile.Icon().Resolved();
const auto profileIcon = profile.Icon();
NewTerminalArgs args{};
args.Profile(profileName);
@@ -5384,22 +5112,22 @@ namespace winrt::TerminalApp::implementation
if (auto neighbor = rootPane->NavigateDirection(activePane, FocusDirection::Down, mruPanes))
{
makeItem(RS_(L"SwapPaneDownText"), neighbor->GetProfile().Icon().Resolved(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Down } }, swapPaneMenu);
makeItem(RS_(L"SwapPaneDownText"), neighbor->GetProfile().Icon(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Down } }, swapPaneMenu);
}
if (auto neighbor = rootPane->NavigateDirection(activePane, FocusDirection::Right, mruPanes))
{
makeItem(RS_(L"SwapPaneRightText"), neighbor->GetProfile().Icon().Resolved(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Right } }, swapPaneMenu);
makeItem(RS_(L"SwapPaneRightText"), neighbor->GetProfile().Icon(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Right } }, swapPaneMenu);
}
if (auto neighbor = rootPane->NavigateDirection(activePane, FocusDirection::Up, mruPanes))
{
makeItem(RS_(L"SwapPaneUpText"), neighbor->GetProfile().Icon().Resolved(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Up } }, swapPaneMenu);
makeItem(RS_(L"SwapPaneUpText"), neighbor->GetProfile().Icon(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Up } }, swapPaneMenu);
}
if (auto neighbor = rootPane->NavigateDirection(activePane, FocusDirection::Left, mruPanes))
{
makeItem(RS_(L"SwapPaneLeftText"), neighbor->GetProfile().Icon().Resolved(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Left } }, swapPaneMenu);
makeItem(RS_(L"SwapPaneLeftText"), neighbor->GetProfile().Icon(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Left } }, swapPaneMenu);
}
makeMenuItem(RS_(L"SwapPaneText"), L"\xF1CB", swapPaneMenu, menu);

View File

@@ -3,8 +3,6 @@
#pragma once
#include <ThrottledFunc.h>
#include "TerminalPage.g.h"
#include "Tab.h"
#include "AppKeyBindings.h"
@@ -31,8 +29,6 @@ namespace Microsoft::Terminal::Core
namespace winrt::TerminalApp::implementation
{
struct TerminalSettingsCache;
inline constexpr uint32_t DefaultRowsToScroll{ 3 };
inline constexpr std::wstring_view TabletInputServiceKey{ L"TabletInputService" };
@@ -153,7 +149,7 @@ namespace winrt::TerminalApp::implementation
safe_void_coroutine ProcessStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
const winrt::hstring cwd = winrt::hstring{},
const winrt::hstring env = winrt::hstring{});
safe_void_coroutine CreateTabFromConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
void CreateTabFromConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
TerminalApp::WindowProperties WindowProperties() const noexcept { return _WindowProperties; };
@@ -173,7 +169,7 @@ namespace winrt::TerminalApp::implementation
til::property_changed_event PropertyChanged;
// -------------------------------- WinRT Events ---------------------------------
til::typed_event<IInspectable, IInspectable> TitleChanged;
til::typed_event<IInspectable, winrt::hstring> TitleChanged;
til::typed_event<IInspectable, IInspectable> CloseWindowRequested;
til::typed_event<IInspectable, winrt::Windows::UI::Xaml::UIElement> SetTitleBarContent;
til::typed_event<IInspectable, IInspectable> FocusModeChanged;
@@ -277,7 +273,7 @@ namespace winrt::TerminalApp::implementation
TerminalApp::ContentManager _manager{ nullptr };
std::shared_ptr<TerminalSettingsCache> _terminalSettingsCache{};
TerminalApp::TerminalSettingsCache _terminalSettingsCache{ nullptr };
struct StashedDragData
{
@@ -363,11 +359,8 @@ namespace winrt::TerminalApp::implementation
bool _MovePane(const Microsoft::Terminal::Settings::Model::MovePaneArgs args);
bool _MoveTab(winrt::com_ptr<Tab> tab, const Microsoft::Terminal::Settings::Model::MoveTabArgs args);
std::shared_ptr<ThrottledFunc<>> _adjustProcessPriorityThrottled;
void _adjustProcessPriority() const;
template<typename F>
bool _ApplyToActiveControls(F f) const
bool _ApplyToActiveControls(F f)
{
if (const auto tab{ _GetFocusedTabImpl() })
{
@@ -386,12 +379,12 @@ namespace winrt::TerminalApp::implementation
return false;
}
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl() const;
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl();
std::optional<uint32_t> _GetFocusedTabIndex() const noexcept;
std::optional<uint32_t> _GetTabIndex(const TerminalApp::Tab& tab) const noexcept;
TerminalApp::Tab _GetFocusedTab() const noexcept;
winrt::com_ptr<Tab> _GetFocusedTabImpl() const noexcept;
TerminalApp::Tab _GetTabByTabViewItem(const IInspectable& tabViewItem) const noexcept;
TerminalApp::Tab _GetTabByTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept;
void _HandleClosePaneRequested(std::shared_ptr<Pane> pane);
safe_void_coroutine _SetFocusedTab(const winrt::TerminalApp::Tab tab);
@@ -420,11 +413,10 @@ namespace winrt::TerminalApp::implementation
bool _IsUriSupported(const winrt::Windows::Foundation::Uri& parsedUri);
void _ShowCouldNotOpenDialog(winrt::hstring reason, winrt::hstring uri);
bool _CopyText(bool dismissSelection, bool singleLine, bool withControlSequences, Microsoft::Terminal::Control::CopyFormat formats);
bool _CopyText(const bool dismissSelection, const bool singleLine, const bool withControlSequences, const Windows::Foundation::IReference<Microsoft::Terminal::Control::CopyFormat>& formats);
safe_void_coroutine _SetTaskbarProgressHandler(const IInspectable sender, const IInspectable eventArgs);
void _copyToClipboard(IInspectable, Microsoft::Terminal::Control::WriteToClipboardEventArgs args) const;
void _PasteText();
safe_void_coroutine _ControlNoticeRaisedHandler(const IInspectable sender, const Microsoft::Terminal::Control::NoticeEventArgs eventArgs);
@@ -435,18 +427,13 @@ namespace winrt::TerminalApp::implementation
void _TabDragStarted(const IInspectable& sender, const IInspectable& eventArgs);
void _TabDragCompleted(const IInspectable& sender, const IInspectable& eventArgs);
// BODGY: WinUI's TabView has a broken close event handler:
// If the close button is disabled, middle-clicking the tab raises no close
// event. Because that's dumb, we implement our own middle-click handling.
// `_tabItemMiddleClickHookEnabled` is true whenever the close button is hidden,
// and that enables all of the rest of this machinery (and this workaround).
bool _tabItemMiddleClickHookEnabled = false;
bool _tabItemMiddleClickExited = false;
PointerEntered_revoker _tabItemMiddleClickPointerEntered;
PointerExited_revoker _tabItemMiddleClickPointerExited;
PointerCaptureLost_revoker _tabItemMiddleClickPointerCaptureLost;
bool _tabPointerMiddleButtonPressed{ false };
bool _tabPointerMiddleButtonExited{ false };
void _OnTabPointerPressed(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
safe_void_coroutine _OnTabPointerReleasedCloseTab(IInspectable sender);
void _OnTabPointerReleased(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
safe_void_coroutine _OnTabPointerReleasedCloseTab(winrt::Microsoft::UI::Xaml::Controls::TabViewItem sender);
void _OnTabPointerEntered(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
void _OnTabPointerExited(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
void _OnTabSelectionChanged(const IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& eventArgs);
void _OnTabItemsChanged(const IInspectable& sender, const Windows::Foundation::Collections::IVectorChangedEventArgs& eventArgs);
@@ -520,7 +507,7 @@ namespace winrt::TerminalApp::implementation
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
void _OpenElevatedWT(winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
safe_void_coroutine _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
safe_void_coroutine _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
void _CloseOnExitInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
void _KeyboardServiceWarningInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
@@ -536,7 +523,7 @@ namespace winrt::TerminalApp::implementation
void _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
Windows::Foundation::IAsyncAction _SearchMissingCommandHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::SearchMissingCommandEventArgs args);
static Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::MatchResult>> _FindPackageAsync(hstring query);
Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::MatchResult>> _FindPackageAsync(hstring query);
void _WindowSizeChanged(const IInspectable sender, const winrt::Microsoft::Terminal::Control::WindowSizeChangedEventArgs args);
void _windowPropertyChanged(const IInspectable& sender, const winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs& args);

View File

@@ -82,7 +82,7 @@ namespace TerminalApp
void WindowActivated(Boolean activated);
void SendContentToOther(RequestReceiveContentArgs args);
event Windows.Foundation.TypedEventHandler<Object, Object> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> CloseWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;

View File

@@ -6,7 +6,6 @@
#include <mmsystem.h>
#include "TerminalSettingsCache.h"
#include "../../types/inc/utils.hpp"
#include "BellEventArgs.g.cpp"
@@ -21,7 +20,7 @@ using namespace winrt::Microsoft::Terminal::TerminalConnection;
namespace winrt::TerminalApp::implementation
{
TerminalPaneContent::TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const std::shared_ptr<TerminalSettingsCache>& cache,
const TerminalApp::TerminalSettingsCache& cache,
const winrt::Microsoft::Terminal::Control::TermControl& control) :
_control{ control },
_cache{ cache },
@@ -83,7 +82,7 @@ namespace winrt::TerminalApp::implementation
winrt::hstring TerminalPaneContent::Icon() const
{
return _profile.Icon().Resolved();
return _profile.EvaluatedIcon();
}
Windows::Foundation::IReference<winrt::Windows::UI::Color> TerminalPaneContent::TabColor() const noexcept
@@ -279,7 +278,7 @@ namespace winrt::TerminalApp::implementation
auto sounds{ _profile.BellSound() };
if (sounds && sounds.Size() > 0)
{
winrt::hstring soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW<std::wstring>(sounds.GetAt(rand() % sounds.Size()).c_str()) };
winrt::Windows::Foundation::Uri uri{ soundPath };
_playBellSound(uri);
}
@@ -341,13 +340,9 @@ namespace winrt::TerminalApp::implementation
RestartTerminalRequested.raise(*this, nullptr);
}
void TerminalPaneContent::UpdateSettings(const CascadiaSettings& settings)
void TerminalPaneContent::UpdateSettings(const CascadiaSettings& /*settings*/)
{
// Reload our profile from the settings model to propagate bell mode, icon, and close on exit mode (anything that uses _profile).
const auto profile{ settings.FindProfile(_profile.Guid()) };
_profile = profile ? profile : settings.ProfileDefaults();
if (const auto& settings{ _cache->TryLookup(_profile) })
if (const auto& settings{ _cache.TryLookup(_profile) })
{
_control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings());
}

View File

@@ -8,8 +8,6 @@
namespace winrt::TerminalApp::implementation
{
struct TerminalSettingsCache;
struct BellEventArgs : public BellEventArgsT<BellEventArgs>
{
public:
@@ -22,7 +20,7 @@ namespace winrt::TerminalApp::implementation
struct TerminalPaneContent : TerminalPaneContentT<TerminalPaneContent>, BasicPaneEvents
{
TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const std::shared_ptr<TerminalSettingsCache>& cache,
const TerminalApp::TerminalSettingsCache& cache,
const winrt::Microsoft::Terminal::Control::TermControl& control);
winrt::Windows::UI::Xaml::FrameworkElement GetRoot();
@@ -61,7 +59,7 @@ namespace winrt::TerminalApp::implementation
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 };
std::shared_ptr<TerminalSettingsCache> _cache{};
TerminalApp::TerminalSettingsCache _cache{ nullptr };
bool _isDefTermSession{ false };
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
import "IPaneContent.idl";
import "TerminalSettingsCache.idl";
import "FilteredCommand.idl";
namespace TerminalApp

View File

@@ -3,6 +3,7 @@
#include "pch.h"
#include "TerminalSettingsCache.h"
#include "TerminalSettingsCache.g.cpp"
namespace winrt
{

View File

@@ -13,13 +13,14 @@ Abstract:
--*/
#pragma once
#include "winrt/Microsoft.Terminal.Settings.Model.h"
#include "winrt/TerminalApp.h"
#include "TerminalSettingsCache.g.h"
#include <inc/cppwinrt_utils.h>
namespace winrt::TerminalApp::implementation
{
struct TerminalSettingsCache
class TerminalSettingsCache : public TerminalSettingsCacheT<TerminalSettingsCache>
{
public:
TerminalSettingsCache(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const TerminalApp::AppKeyBindings& bindings);
Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult TryLookup(const Microsoft::Terminal::Settings::Model::Profile& profile);
void Reset(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const TerminalApp::AppKeyBindings& bindings);
@@ -30,3 +31,8 @@ namespace winrt::TerminalApp::implementation
std::unordered_map<winrt::guid, std::pair<Microsoft::Terminal::Settings::Model::Profile, Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult>> profileGuidSettingsMap;
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(TerminalSettingsCache);
}

View File

@@ -0,0 +1,13 @@
import "AppKeyBindings.idl";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
[default_interface] runtimeclass TerminalSettingsCache
{
TerminalSettingsCache(Microsoft.Terminal.Settings.Model.CascadiaSettings settings, AppKeyBindings bindings);
Microsoft.Terminal.Settings.Model.TerminalSettingsCreateResult TryLookup(Microsoft.Terminal.Settings.Model.Profile profile);
void Reset(Microsoft.Terminal.Settings.Model.CascadiaSettings settings, AppKeyBindings bindings);
}
}

View File

@@ -40,7 +40,8 @@ static const std::array settingsLoadWarningsLabels{
USES_RESOURCE(L"MissingDefaultProfileText"),
USES_RESOURCE(L"DuplicateProfileText"),
USES_RESOURCE(L"UnknownColorSchemeText"),
USES_RESOURCE(L"InvalidMediaResource"),
USES_RESOURCE(L"InvalidBackgroundImage"),
USES_RESOURCE(L"InvalidIcon"),
USES_RESOURCE(L"AtLeastOneKeybindingWarning"),
USES_RESOURCE(L"TooManyKeysForChord"),
USES_RESOURCE(L"MissingRequiredParameter"),
@@ -322,10 +323,6 @@ namespace winrt::TerminalApp::implementation
// - an IAsyncOperation with the dialog result
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalWindow::ShowDialog(winrt::WUX::Controls::ContentDialog dialog)
{
const auto weak = get_weak();
const auto dispatcher = _root->Dispatcher();
const auto root = _root->XamlRoot();
// As mentioned on s_activeDialog, dismissing the active dialog is necessary.
// We repeat it a few times in case the resume_foreground failed to work,
// but I found that one iteration will always be enough in practice.
@@ -339,7 +336,7 @@ namespace winrt::TerminalApp::implementation
s_activeDialog.Hide();
// Wait for the current dialog to be hidden.
co_await wil::resume_foreground(dispatcher, CoreDispatcherPriority::Low);
co_await wil::resume_foreground(_root->Dispatcher(), CoreDispatcherPriority::Low);
}
// If two sources call ShowDialog() simultaneously, it may happen that both enter the above loop,
@@ -356,7 +353,7 @@ namespace winrt::TerminalApp::implementation
// IMPORTANT: This is necessary as documented in the ContentDialog MSDN docs.
// Since we're hosting the dialog in a Xaml island, we need to connect it to the
// xaml tree somehow.
dialog.XamlRoot(root);
dialog.XamlRoot(_root->XamlRoot());
// IMPORTANT: Set the requested theme of the dialog, because the
// PopupRoot isn't directly in the Xaml tree of our root. So the dialog
@@ -370,17 +367,14 @@ namespace winrt::TerminalApp::implementation
// theme on each element up to the root. We're relying a bit on Xaml's implementation
// details here, but it does have the desired effect.
// It's not enough to set the theme on the dialog alone.
auto themingLambda{ [weak](const Windows::Foundation::IInspectable& sender, const RoutedEventArgs&) {
if (const auto strong = weak.get())
auto themingLambda{ [this](const Windows::Foundation::IInspectable& sender, const RoutedEventArgs&) {
auto theme{ _settings.GlobalSettings().CurrentTheme() };
auto requestedTheme{ theme.RequestedTheme() };
auto element{ sender.try_as<winrt::Windows::UI::Xaml::FrameworkElement>() };
while (element)
{
auto theme{ strong->_settings.GlobalSettings().CurrentTheme() };
auto requestedTheme{ theme.RequestedTheme() };
auto element{ sender.try_as<winrt::Windows::UI::Xaml::FrameworkElement>() };
while (element)
{
element.RequestedTheme(requestedTheme);
element = element.Parent().try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
}
element.RequestedTheme(requestedTheme);
element = element.Parent().try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
}
} };
@@ -895,11 +889,6 @@ namespace winrt::TerminalApp::implementation
{
// Manually bubble the OnDirectKeyEvent event up through the focus tree.
auto xamlRoot{ _root->XamlRoot() };
if (!xamlRoot)
{
return false;
}
auto focusedObject{ Windows::UI::Xaml::Input::FocusManager::GetFocusedElement(xamlRoot) };
do
{
@@ -1060,11 +1049,6 @@ namespace winrt::TerminalApp::implementation
// (or called TerminalWindow::Initialize)
if (_appArgs->ExitCode() == 0)
{
// The existing logic (before this commit) strictly relied on
// ValidateStartupCommands() only to be called for new windows.
// It modifies the actions it stores.
parsedArgs.ValidateStartupCommands();
// If the size of the arguments list is 1,
// then it contains only the executable name and no other arguments.
_hasCommandLineArguments = _appArgs->CommandlineRef().size() > 1;

View File

@@ -210,7 +210,7 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(Initialized, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, Initialized);
FORWARDED_TYPED_EVENT(SetTitleBarContent, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::UIElement, _root, SetTitleBarContent);
FORWARDED_TYPED_EVENT(TitleChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, TitleChanged);
FORWARDED_TYPED_EVENT(TitleChanged, winrt::Windows::Foundation::IInspectable, winrt::hstring, _root, TitleChanged);
FORWARDED_TYPED_EVENT(CloseWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, CloseWindowRequested);
FORWARDED_TYPED_EVENT(FocusModeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, FocusModeChanged);
FORWARDED_TYPED_EVENT(FullscreenChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, FullscreenChanged);

View File

@@ -112,7 +112,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> Initialized;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;
event Windows.Foundation.TypedEventHandler<Object, Object> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> CloseWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.Theme> RequestedThemeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;

View File

@@ -53,16 +53,6 @@ namespace winrt::TerminalApp::implementation
return static_cast<float>(minMaxCloseWidth) / 3.0f;
}
bool TitlebarControl::Focused()
{
return MinMaxCloseControl().Focused();
}
void TitlebarControl::Focused(bool focused)
{
MinMaxCloseControl().Focused(focused);
}
IInspectable TitlebarControl::Content()
{
return ContentRoot().Content();

View File

@@ -17,9 +17,6 @@ namespace winrt::TerminalApp::implementation
void ReleaseButtons();
float CaptionButtonWidth();
bool Focused();
void Focused(bool focused);
IInspectable Content();
void Content(IInspectable content);

View File

@@ -29,7 +29,6 @@ namespace TerminalApp
void ClickButton(CaptionButton button);
void ReleaseButtons();
Single CaptionButtonWidth { get; };
Boolean Focused { get; set; };
IInspectable Content;
Windows.UI.Xaml.Controls.Border DragBar { get; };

View File

@@ -16,7 +16,6 @@
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalMUX>true</TerminalMUX>
<TerminalThemeHelpers>true</TerminalThemeHelpers>
</PropertyGroup>
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />

View File

@@ -0,0 +1,87 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ConsoleInputReader.h"
#include "unicode.hpp"
ConsoleInputReader::ConsoleInputReader(HANDLE handle) :
_handle(handle)
{
_buffer.resize(BufferSize);
_convertedString.reserve(BufferSize);
}
void ConsoleInputReader::SetWindowSizeChangedCallback(std::function<void()> callback)
{
_windowSizeChangedCallback = std::move(callback);
}
std::optional<std::wstring_view> ConsoleInputReader::Read()
{
DWORD readCount{ 0 };
_convertedString.clear();
while (_convertedString.empty())
{
_buffer.resize(BufferSize);
auto succeeded =
ReadConsoleInputW(_handle, _buffer.data(), gsl::narrow_cast<DWORD>(_buffer.size()), &readCount);
if (!succeeded)
{
return std::nullopt;
}
_buffer.resize(readCount);
for (auto it = _buffer.begin(); it != _buffer.end(); ++it)
{
if (it->EventType == WINDOW_BUFFER_SIZE_EVENT && _windowSizeChangedCallback)
{
_windowSizeChangedCallback();
}
else if (it->EventType == KEY_EVENT)
{
const auto& keyEvent = it->Event.KeyEvent;
if (keyEvent.bKeyDown || (!keyEvent.bKeyDown && keyEvent.wVirtualKeyCode == VK_MENU))
{
// Got a high surrogate at the end of the buffer
if (IS_HIGH_SURROGATE(keyEvent.uChar.UnicodeChar))
{
_highSurrogate.emplace(keyEvent.uChar.UnicodeChar);
continue; // we've consumed it -- only dispatch it if we get a low
}
if (IS_LOW_SURROGATE(keyEvent.uChar.UnicodeChar))
{
// No matter what we do, we want to destructively consume the high surrogate
if (const auto oldHighSurrogate{ std::exchange(_highSurrogate, std::nullopt) })
{
_convertedString.push_back(*_highSurrogate);
}
else
{
// If we get a low without a high surrogate, we've done everything we can.
// This is an illegal state.
_convertedString.push_back(UNICODE_REPLACEMENT);
continue; // onto the next event
}
}
// (\0 with a scancode is probably a modifier key, not a VT input key)
if (keyEvent.uChar.UnicodeChar != L'\0' || keyEvent.wVirtualScanCode == 0)
{
if (_highSurrogate) // non-destructive: we don't want to set it to nullopt needlessly for every character
{
// If we get a high surrogate *here*, we didn't find a low surrogate.
// This state is also illegal.
_convertedString.push_back(UNICODE_REPLACEMENT);
_highSurrogate.reset();
}
_convertedString.push_back(keyEvent.uChar.UnicodeChar);
}
}
}
}
}
return _convertedString;
}

View File

@@ -0,0 +1,33 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
Module Name:
ConsoleInputReader.h
Abstract:
This file contains a class whose sole purpose is to
abstract away a bunch of details you usually need to
know to read VT from a console input handle.
--*/
class ConsoleInputReader
{
public:
explicit ConsoleInputReader(HANDLE handle);
void SetWindowSizeChangedCallback(std::function<void()> callback);
std::optional<std::wstring_view> Read();
private:
static constexpr size_t BufferSize{ 128 };
HANDLE _handle;
std::wstring _convertedString;
std::vector<INPUT_RECORD> _buffer;
std::optional<wchar_t> _highSurrogate;
std::function<void()> _windowSizeChangedCallback;
};

View File

@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>{067F0A06-FCB7-472C-96E9-B03B54E8E18D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>TerminalAzBridge</RootNamespace>
<ProjectName>TerminalAzBridge</ProjectName>
<TargetName>TerminalAzBridge</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OpenConsoleUniversalApp>false</OpenConsoleUniversalApp>
<ApplicationType>Windows Store</ApplicationType>
<TargetPlatformIdentifier>Windows</TargetPlatformIdentifier>
<VersionInfoFileDescription>Windows Terminal Azure Cloud Shell Connector</VersionInfoFileDescription>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<PropertyGroup>
<GenerateManifest>true</GenerateManifest>
<EmbedManifest>true</EmbedManifest>
</PropertyGroup>
<!-- Source Files -->
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="ConsoleInputReader.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="main.cpp" />
<ClCompile Include="ConsoleInputReader.cpp" />
</ItemGroup>
<!-- Dependencies -->
<ItemGroup>
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalConnection\TerminalConnection.vcxproj">
<Project>{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}</Project>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
</ItemGroup>
<!--
This ItemGroup and the Globals PropertyGroup below it are required in order
to enable F5 debugging for the unpackaged application
-->
<ItemGroup>
<PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\debugger_general.xml" />
<PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\debugger_local_windows.xml" />
</ItemGroup>
<PropertyGroup Label="Globals">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
<!-- These have to come after post.props because the Cpp common targets will inexplicably overwrite them. -->
<ItemDefinitionGroup>
<ClCompile>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<!--
BODGY
The wapproj `GetResolvedWinMD` target tries to get a winmd from every cppwinrt
executable we put in the package. But we DON'T produce a winmd. This makes the
FastUpToDate check fail every time, and leads to the whole wapproj build
running even if you're just f5'ing the package. EVEN AFTER A SUCCESSFUL BUILD.
Setting GenerateWindowsMetadata=false is enough to tell the build system that
we don't produce one, and get it off our backs.
-->
<ItemDefinitionGroup>
<Link>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<Import Project="$(OpenConsoleDir)\build\rules\GenerateSxsManifestsFromWinmds.targets" />
</Project>

View File

@@ -0,0 +1,108 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "winrt/Microsoft.Terminal.TerminalConnection.h"
#include "ConsoleInputReader.h"
using namespace winrt;
using namespace winrt::Windows::Foundation;
using namespace winrt::Microsoft::Terminal::TerminalConnection;
static til::size GetConsoleScreenSize(HANDLE outputHandle)
{
CONSOLE_SCREEN_BUFFER_INFOEX csbiex{};
csbiex.cbSize = sizeof(csbiex);
GetConsoleScreenBufferInfoEx(outputHandle, &csbiex);
return {
(csbiex.srWindow.Right - csbiex.srWindow.Left) + 1,
(csbiex.srWindow.Bottom - csbiex.srWindow.Top) + 1
};
}
static ConnectionState RunConnectionToCompletion(const ITerminalConnection& connection, HANDLE outputHandle, HANDLE inputHandle)
{
connection.TerminalOutput([outputHandle](const winrt::hstring& output) {
WriteConsoleW(outputHandle, output.data(), output.size(), nullptr, nullptr);
});
// Detach a thread to spin the console read indefinitely.
// This application exits when the connection is closed, so
// the connection's lifetime will outlast this thread.
std::thread([connection, outputHandle, inputHandle] {
ConsoleInputReader reader{ inputHandle };
reader.SetWindowSizeChangedCallback([&]() {
const auto size = GetConsoleScreenSize(outputHandle);
connection.Resize(size.height, size.width);
});
while (true)
{
auto input = reader.Read();
if (input)
{
connection.WriteInput(winrt_wstring_to_array_view(*input));
}
}
}).detach();
std::condition_variable stateChangeVar;
std::optional<ConnectionState> state;
std::mutex stateMutex;
connection.StateChanged([&](auto&& /*s*/, auto&& /*e*/) {
std::unique_lock<std::mutex> lg{ stateMutex };
state = connection.State();
stateChangeVar.notify_all();
});
connection.Start();
std::unique_lock<std::mutex> lg{ stateMutex };
stateChangeVar.wait(lg, [&]() {
if (!state.has_value())
{
return false;
}
return state.value() == ConnectionState::Closed || state.value() == ConnectionState::Failed;
});
return state.value();
}
int wmain(int /*argc*/, wchar_t** /*argv*/)
{
winrt::init_apartment(winrt::apartment_type::single_threaded);
DWORD inputMode{}, outputMode{};
auto conIn{ GetStdHandle(STD_INPUT_HANDLE) }, conOut{ GetStdHandle(STD_OUTPUT_HANDLE) };
auto codepage{ GetConsoleCP() }, outputCodepage{ GetConsoleOutputCP() };
RETURN_IF_WIN32_BOOL_FALSE(GetConsoleMode(conIn, &inputMode));
RETURN_IF_WIN32_BOOL_FALSE(GetConsoleMode(conOut, &outputMode));
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleMode(conIn, ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT));
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleMode(conOut, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_WRAP_AT_EOL_OUTPUT | DISABLE_NEWLINE_AUTO_RETURN));
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleCP(CP_UTF8));
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleOutputCP(CP_UTF8));
auto restoreConsoleModes = wil::scope_exit([&]() {
SetConsoleMode(conIn, inputMode);
SetConsoleMode(conOut, outputMode);
SetConsoleCP(codepage);
SetConsoleOutputCP(outputCodepage);
});
const auto size = GetConsoleScreenSize(conOut);
AzureConnection azureConn{};
winrt::Windows::Foundation::Collections::ValueSet vs{};
vs.Insert(L"initialRows", winrt::Windows::Foundation::PropertyValue::CreateUInt32(gsl::narrow_cast<uint32_t>(size.height)));
vs.Insert(L"initialCols", winrt::Windows::Foundation::PropertyValue::CreateUInt32(gsl::narrow_cast<uint32_t>(size.width)));
azureConn.Initialize(vs);
const auto state = RunConnectionToCompletion(azureConn, conOut, conIn);
return state == ConnectionState::Closed ? 0 : 1;
}

View File

@@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"

View File

@@ -0,0 +1,40 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- pch.h
Abstract:
- Contains external headers to include in the precompile phase of console build process.
- Avoid including internal project headers. Instead include them only in the classes that need them (helps with test project building).
--*/
#pragma once
// Ignore checked iterators warning from VC compiler.
#define _SCL_SECURE_NO_WARNINGS
// Block minwindef.h min/max macros to prevent <algorithm> conflict
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#define NOMCX
#define NOHELP
#define NOCOMM
#include <Unknwn.h>
#include <windows.h>
#include "../inc/LibraryIncludes.h"
#include <wil/cppwinrt.h>
#include <winrt/Windows.system.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <wil/resource.h>
#include <wil/win32_helpers.h>
#include <cppwinrt_utils.h>

View File

@@ -30,7 +30,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
// Function Description:
// - launches the client application attached to the new pseudoconsole
void ConptyConnection::_LaunchAttachedClient()
HRESULT ConptyConnection::_LaunchAttachedClient() noexcept
try
{
STARTUPINFOEX siEx{ 0 };
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
@@ -42,16 +43,15 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
auto attrList{ std::make_unique<std::byte[]>(size) };
#pragma warning(suppress : 26490) // We have to use reinterpret_cast because we allocated a byte array as a proxy for the adjustable size list.
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(attrList.get());
THROW_IF_WIN32_BOOL_FALSE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size));
RETURN_IF_WIN32_BOOL_FALSE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size));
THROW_IF_WIN32_BOOL_FALSE(UpdateProcThreadAttribute(
siEx.lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
_hPC.get(),
sizeof(HPCON),
nullptr,
nullptr));
RETURN_IF_WIN32_BOOL_FALSE(UpdateProcThreadAttribute(siEx.lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
_hPC.get(),
sizeof(HPCON),
nullptr,
nullptr));
auto cmdline{ wil::ExpandEnvironmentStringsW<std::wstring>(_commandline.c_str()) }; // mutable copy -- required for CreateProcessW
auto environment = _initialEnv;
@@ -72,11 +72,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
std::wstring additionalWslEnv;
// WSLENV.2: Figure out what variables are already in WSLENV.
std::unordered_set<std::wstring> wslEnvVars{
// We never want to put a custom Windows PATH variable into WSLENV,
// because that would override WSL's computation of the NIX PATH.
L"PATH",
};
std::unordered_set<std::wstring_view> wslEnvVars;
for (const auto& part : til::split_iterator{ std::wstring_view{ wslEnv }, L':' })
{
// Each part may contain a variable name and flags (e.g., /p, /l, etc.)
@@ -101,19 +97,25 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
}
// add additional env vars
if (_environment)
{
// Order the environment variable names so that resolution order is consistent
// NOTE(lhecker): I'm like 99% sure that this is unnecessary.
std::set<std::wstring, til::env_key_sorter> keys{};
for (const auto item : _environment)
{
keys.insert(std::wstring{ item.Key() });
}
// add additional env vars
for (const auto& key : keys)
{
try
{
const auto key = item.Key();
// This will throw if the value isn't a string. If that
// happens, then just skip this entry.
const auto value = winrt::unbox_value<hstring>(_environment.Lookup(key));
environment.set_user_environment_var(key, value);
environment.set_user_environment_var(key.c_str(), value.c_str());
// WSLENV.4: Add custom user environment variables to WSLENV.
if (wslEnvVars.emplace(key).second)
@@ -164,7 +166,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
auto [newCommandLine, newStartingDirectory] = Utils::MangleStartingDirectoryForWSL(cmdline, _startingDirectory);
const auto startingDirectory = newStartingDirectory.size() > 0 ? newStartingDirectory.c_str() : nullptr;
THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
nullptr,
newCommandLine.data(),
nullptr, // lpProcessAttributes
@@ -191,7 +193,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
TraceLoggingWideString(_clientName.c_str(), "Client", "The attached client process"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
return S_OK;
}
CATCH_RETURN();
// Who decided that?
#pragma warning(suppress : 26455) // Default constructor should not throw. Declare it 'noexcept' (f.6).
@@ -340,13 +345,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
auto ownedSignal = duplicateHandle(signal);
auto ownedReference = duplicateHandle(reference);
auto ownedServer = duplicateHandle(server);
wil::unique_hfile ownedClient;
LOG_IF_WIN32_BOOL_FALSE(DuplicateHandle(GetCurrentProcess(), client, GetCurrentProcess(), ownedClient.addressof(), PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_SET_INFORMATION | SYNCHRONIZE, FALSE, 0));
if (!ownedClient)
{
// If we couldn't reopen the handle with SET_INFORMATION, which may be required to do things like QoS management, fall back.
ownedClient = duplicateHandle(client);
}
auto ownedClient = duplicateHandle(client);
THROW_IF_FAILED(ConptyPackPseudoConsole(ownedServer.get(), ownedReference.get(), ownedSignal.get(), &_hPC));
ownedServer.release();
@@ -419,7 +418,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility));
}
_LaunchAttachedClient();
THROW_IF_FAILED(_LaunchAttachedClient());
}
// But if it was an inbound handoff... attempt to synchronize the size of it with what our connection
// window is expecting it to be on the first layout.
@@ -539,8 +538,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
DWORD exitCode{ 0 };
GetExitCodeProcess(_piClient.hProcess, &exitCode);
_piClient.reset();
// Signal the closing or failure of the process.
// exitCode might be STILL_ACTIVE if a client has called FreeConsole() and
// thus caused the tab to close, even though the CLI app is still running.
@@ -657,12 +654,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
}
uint64_t ConptyConnection::RootProcessHandle() noexcept
{
#pragma warning(disable : 26490) // Don't use reinterpret_cast (type.1).
return reinterpret_cast<uint64_t>(_piClient.hProcess);
}
void ConptyConnection::Close() noexcept
try
{

View File

@@ -30,7 +30,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
void ShowHide(const bool show);
void ReparentWindow(const uint64_t newParent);
uint64_t RootProcessHandle() noexcept;
winrt::hstring Commandline() const;
winrt::hstring StartingTitle() const;
@@ -59,7 +58,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
static HRESULT NewHandoff(HANDLE* in, HANDLE* out, HANDLE signal, HANDLE reference, HANDLE server, HANDLE client, const TERMINAL_STARTUP_INFO* startupInfo) noexcept;
static winrt::hstring _commandlineFromProcess(HANDLE process);
void _LaunchAttachedClient();
HRESULT _LaunchAttachedClient() noexcept;
void _indicateExitWithStatus(unsigned int status) noexcept;
static std::wstring _formatStatus(uint32_t status);
void _LastConPtyClientDisconnected() noexcept;

View File

@@ -21,8 +21,6 @@ namespace Microsoft.Terminal.TerminalConnection
void ReparentWindow(UInt64 newParent);
UInt64 RootProcessHandle();
static event NewConnectionHandler NewConnection;
static void StartInboundListener();

View File

@@ -104,9 +104,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// GH#8969: pre-seed working directory to prevent potential races
_terminal->SetWorkingDirectory(_settings->StartingDirectory());
_terminal->SetCopyToClipboardCallback([this](wil::zwstring_view wstr) {
WriteToClipboard.raise(*this, winrt::make<WriteToClipboardEventArgs>(winrt::hstring{ std::wstring_view{ wstr } }, std::string{}, std::string{}));
});
auto pfnCopyToClipboard = [this](auto&& PH1) { _terminalCopyToClipboard(std::forward<decltype(PH1)>(PH1)); };
_terminal->SetCopyToClipboardCallback(pfnCopyToClipboard);
auto pfnWarningBell = [this] { _terminalWarningBell(); };
_terminal->SetWarningBellCallback(pfnWarningBell);
@@ -149,27 +148,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderer->SetBackgroundColorChangedCallback([this]() { _rendererBackgroundColorChanged(); });
_renderer->SetFrameColorChangedCallback([this]() { _rendererTabColorChanged(); });
_renderer->SetRendererEnteredErrorStateCallback([this]() { _rendererEnteredErrorState(); });
_renderer->SetRendererEnteredErrorStateCallback([this]() { RendererEnteredErrorState.raise(nullptr, nullptr); });
}
UpdateSettings(settings, unfocusedAppearance);
}
void ControlCore::_rendererEnteredErrorState()
{
// The first time the renderer fails out (after all of its own retries), switch it to D2D and WARP
// and force it to try again. If it _still_ fails, we can let it halt.
if (_renderFailures++ == 0)
{
const auto lock = _terminal->LockForWriting();
_renderEngine->SetGraphicsAPI(parseGraphicsAPI(GraphicsAPI::Direct2D));
_renderEngine->SetSoftwareRendering(true);
_renderer->EnablePainting();
return;
}
RendererEnteredErrorState.raise(nullptr, nullptr);
}
void ControlCore::_setupDispatcherAndCallbacks()
{
// Get our dispatcher. If we're hosted in-proc with XAML, this will get
@@ -190,12 +174,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
//
// NOTE: Calling UpdatePatternLocations from a background
// thread is a workaround for us to hit GH#12607 less often.
shared->outputIdle = std::make_unique<til::throttled_func<>>(
til::throttled_func_options{
.delay = std::chrono::milliseconds{ 100 },
.debounce = true,
.trailing = true,
},
shared->outputIdle = std::make_unique<til::debounced_func_trailing<>>(
std::chrono::milliseconds{ 100 },
[this, weakThis = get_weak(), dispatcher = _dispatcher]() {
dispatcher.TryEnqueue(DispatcherQueuePriority::Normal, [weakThis]() {
if (const auto self = weakThis.get(); self && !self->_IsClosing())
@@ -215,12 +195,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// If you rapidly show/hide Windows Terminal, something about GotFocus()/LostFocus() gets broken.
// We'll then receive easily 10+ such calls from WinUI the next time the application is shown.
shared->focusChanged = std::make_unique<til::throttled_func<bool>>(
til::throttled_func_options{
.delay = std::chrono::milliseconds{ 25 },
.debounce = true,
.trailing = true,
},
shared->focusChanged = std::make_unique<til::debounced_func_trailing<bool>>(
std::chrono::milliseconds{ 25 },
[this](const bool focused) {
// Theoretically `debounced_func_trailing` should call `WaitForThreadpoolTimerCallbacks()`
// with cancel=true on destruction, which should ensure that our use of `this` here is safe.
@@ -228,12 +204,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
});
// Scrollbar updates are also expensive (XAML), so we'll throttle them as well.
shared->updateScrollBar = std::make_shared<ThrottledFunc<Control::ScrollPositionChangedArgs>>(
shared->updateScrollBar = std::make_shared<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>>(
_dispatcher,
til::throttled_func_options{
.delay = std::chrono::milliseconds{ 8 },
.trailing = true,
},
std::chrono::milliseconds{ 8 },
[weakThis = get_weak()](const auto& update) {
if (auto core{ weakThis.get() }; core && !core->_IsClosing())
{
@@ -349,12 +322,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlCore::HardResetWithoutErase()
{
const auto lock = _terminal->LockForWriting();
_terminal->HardResetWithoutErase();
}
bool ControlCore::Initialize(const float actualWidth,
const float actualHeight,
const float compositionScale)
@@ -621,7 +588,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
else if (vkey == VK_RETURN && !mods.IsCtrlPressed() && !mods.IsAltPressed())
{
// [Shift +] Enter --> copy text
CopySelectionToClipboard(mods.IsShiftPressed(), false, _settings->CopyFormatting());
CopySelectionToClipboard(mods.IsShiftPressed(), false, nullptr);
_terminal->ClearSelection();
_updateSelectionUI();
return true;
@@ -932,7 +899,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderEngine->SetSoftwareRendering(_settings->SoftwareRendering());
// Inform the renderer of our opacity
_renderEngine->EnableTransparentBackground(_isBackgroundTransparent());
_renderFailures = 0; // We may have changed the engine; reset the failure counter.
// Trigger a redraw to repaint the window background and tab colors.
_renderer->TriggerRedrawAll(true, true);
@@ -1286,6 +1252,89 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_updateSelectionUI();
}
static wil::unique_close_clipboard_call _openClipboard(HWND hwnd)
{
bool success = false;
// OpenClipboard may fail to acquire the internal lock --> retry.
for (DWORD sleep = 10;; sleep *= 2)
{
if (OpenClipboard(hwnd))
{
success = true;
break;
}
// 10 iterations
if (sleep > 10000)
{
break;
}
Sleep(sleep);
}
return wil::unique_close_clipboard_call{ success };
}
static void _copyToClipboard(const UINT format, const void* src, const size_t bytes)
{
wil::unique_hglobal handle{ THROW_LAST_ERROR_IF_NULL(GlobalAlloc(GMEM_MOVEABLE, bytes)) };
const auto locked = GlobalLock(handle.get());
memcpy(locked, src, bytes);
GlobalUnlock(handle.get());
THROW_LAST_ERROR_IF_NULL(SetClipboardData(format, handle.get()));
handle.release();
}
static void _copyToClipboardRegisteredFormat(const wchar_t* format, const void* src, size_t bytes)
{
const auto id = RegisterClipboardFormatW(format);
if (!id)
{
LOG_LAST_ERROR();
return;
}
_copyToClipboard(id, src, bytes);
}
static void copyToClipboard(wil::zwstring_view text, std::string_view html, std::string_view rtf)
{
const auto clipboard = _openClipboard(nullptr);
if (!clipboard)
{
LOG_LAST_ERROR();
return;
}
EmptyClipboard();
if (!text.empty())
{
// As per: https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats
// CF_UNICODETEXT: [...] A null character signals the end of the data.
// --> We add +1 to the length. This works because .c_str() is null-terminated.
_copyToClipboard(CF_UNICODETEXT, text.c_str(), (text.size() + 1) * sizeof(wchar_t));
}
if (!html.empty())
{
_copyToClipboardRegisteredFormat(L"HTML Format", html.data(), html.size());
}
if (!rtf.empty())
{
_copyToClipboardRegisteredFormat(L"Rich Text Format", rtf.data(), rtf.size());
}
}
// Called when the Terminal wants to set something to the clipboard, i.e.
// when an OSC 52 is emitted.
void ControlCore::_terminalCopyToClipboard(wil::zwstring_view wstr)
{
copyToClipboard(wstr, {}, {});
}
// Method Description:
// - Given a copy-able selection, get the selected text from the buffer and send it to the
// Windows Clipboard (CascadiaWin32:main.cpp).
@@ -1296,7 +1345,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// if we should defer which formats are copied to the global setting
bool ControlCore::CopySelectionToClipboard(bool singleLine,
bool withControlSequences,
const CopyFormat formats)
const Windows::Foundation::IReference<CopyFormat>& formats)
{
::Microsoft::Terminal::Core::Terminal::TextCopyData payload;
{
@@ -1308,20 +1357,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return false;
}
const auto copyHtml = WI_IsFlagSet(formats, CopyFormat::HTML);
const auto copyRtf = WI_IsFlagSet(formats, CopyFormat::RTF);
// use action's copyFormatting if it's present, else fall back to globally
// set copyFormatting.
const auto copyFormats = formats != nullptr ? formats.Value() : _settings->CopyFormatting();
const auto copyHtml = WI_IsFlagSet(copyFormats, CopyFormat::HTML);
const auto copyRtf = WI_IsFlagSet(copyFormats, CopyFormat::RTF);
// extract text from buffer
// RetrieveSelectedTextFromBuffer will lock while it's reading
payload = _terminal->RetrieveSelectedTextFromBuffer(singleLine, withControlSequences, copyHtml, copyRtf);
}
WriteToClipboard.raise(
*this,
winrt::make<WriteToClipboardEventArgs>(
winrt::hstring{ payload.plainText },
std::move(payload.html),
std::move(payload.rtf)));
copyToClipboard(payload.plainText, payload.html, payload.rtf);
return true;
}
@@ -1690,7 +1738,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - resetOnly: If true, only Reset() will be called, if anything. FindNext() will never be called.
// Return Value:
// - <none>
SearchResults ControlCore::Search(const SearchRequest& request)
SearchResults ControlCore::Search(SearchRequest request)
{
const auto lock = _terminal->LockForWriting();
@@ -1699,9 +1747,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
WI_SetFlagIf(flags, SearchFlag::RegularExpression, request.RegularExpression);
const auto searchInvalidated = _searcher.IsStale(*_terminal.get(), request.Text, flags);
if (searchInvalidated || request.ExecuteSearch)
if (searchInvalidated || !request.ResetOnly)
{
std::vector<til::point_span> oldResults;
til::point_span oldFocused;
if (const auto focused = _terminal->GetSearchHighlightFocused())
{
oldFocused = *focused;
}
if (searchInvalidated)
{
@@ -1710,18 +1764,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_terminal->SetSearchHighlights(_searcher.Results());
}
if (request.ExecuteSearch)
if (!request.ResetOnly)
{
_searcher.FindNext(!request.GoForward);
}
_terminal->SetSearchHighlightFocused(gsl::narrow<size_t>(std::max<ptrdiff_t>(0, _searcher.CurrentMatch())));
_renderer->TriggerSearchHighlight(oldResults);
}
if (request.ScrollIntoView)
{
_terminal->ScrollToSearchHighlight(request.ScrollOffset);
if (const auto focused = _terminal->GetSearchHighlightFocused(); focused && *focused != oldFocused)
{
_terminal->ScrollToSearchHighlight(request.ScrollOffset);
}
}
int32_t totalMatches = 0;
@@ -1928,7 +1982,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// The lock must be held, because it calls into IRenderData which is shared state.
const auto lock = _terminal->LockForWriting();
_renderFailures = 0;
_renderer->EnablePainting();
}
@@ -2016,7 +2069,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_terminal->MultiClickSelection(terminalPosition, mode);
selectionNeedsToBeCopied = true;
}
else if (_settings->RepositionCursorWithMouse() && !selectionNeedsToBeCopied) // Don't reposition cursor if this is part of a selection operation
else if (_settings->RepositionCursorWithMouse()) // This is also mode==Char && !shiftEnabled
{
_repositionCursorWithMouse(terminalPosition);
}
@@ -2704,9 +2757,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlCore::_terminalCompletionsChanged(std::wstring_view menuJson, unsigned int replaceLength)
safe_void_coroutine ControlCore::_terminalCompletionsChanged(std::wstring_view menuJson,
unsigned int replaceLength)
{
CompletionsChanged.raise(*this, winrt::make<CompletionsChangedEventArgs>(winrt::hstring{ menuJson }, replaceLength));
auto args = winrt::make_self<CompletionsChangedEventArgs>(winrt::hstring{ menuJson },
replaceLength);
co_await winrt::resume_background();
CompletionsChanged.raise(*this, *args);
}
// Select the region of text between [s.start, s.end), in buffer space

View File

@@ -124,7 +124,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SendInput(std::wstring_view wstr);
void PasteText(const winrt::hstring& hstr);
bool CopySelectionToClipboard(bool singleLine, bool withControlSequences, const CopyFormat formats);
bool CopySelectionToClipboard(bool singleLine, bool withControlSequences, const Windows::Foundation::IReference<CopyFormat>& formats);
void SelectAll();
void ClearSelection();
bool ToggleBlockSelection();
@@ -228,7 +228,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SetSelectionAnchor(const til::point position);
void SetEndSelectionPoint(const til::point position);
SearchResults Search(const SearchRequest& request);
SearchResults Search(SearchRequest request);
const std::vector<til::point_span>& SearchResultRows() const noexcept;
void ClearSearch();
@@ -260,7 +260,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TerminalConnection::ITerminalConnection Connection();
void Connection(const TerminalConnection::ITerminalConnection& connection);
void HardResetWithoutErase();
void AnchorContextMenu(til::point viewportRelativeCharacterPosition);
@@ -278,7 +277,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::typed_event<IInspectable, Control::FontSizeChangedArgs> FontSizeChanged;
til::typed_event<IInspectable, Control::TitleChangedEventArgs> TitleChanged;
til::typed_event<IInspectable, Control::WriteToClipboardEventArgs> WriteToClipboard;
til::typed_event<> WarningBell;
til::typed_event<> TabColorChanged;
til::typed_event<> BackgroundColorChanged;
@@ -309,9 +307,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
private:
struct SharedState
{
std::unique_ptr<til::throttled_func<>> outputIdle;
std::unique_ptr<til::throttled_func<bool>> focusChanged;
std::shared_ptr<ThrottledFunc<Control::ScrollPositionChangedArgs>> updateScrollBar;
std::unique_ptr<til::debounced_func_trailing<>> outputIdle;
std::unique_ptr<til::debounced_func_trailing<bool>> focusChanged;
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> updateScrollBar;
};
void _setupDispatcherAndCallbacks();
@@ -327,6 +325,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _sendInputToConnection(std::wstring_view wstr);
#pragma region TerminalCoreCallbacks
void _terminalCopyToClipboard(wil::zwstring_view wstr);
void _terminalWarningBell();
void _terminalTitleChanged(std::wstring_view wstr);
void _terminalScrollPositionChanged(const int viewTop,
@@ -340,7 +339,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _terminalSearchMissingCommand(std::wstring_view missingCommand, const til::CoordType& bufferRow);
void _terminalWindowSizeChanged(int32_t width, int32_t height);
void _terminalCompletionsChanged(std::wstring_view menuJson, unsigned int replaceLength);
safe_void_coroutine _terminalCompletionsChanged(std::wstring_view menuJson, unsigned int replaceLength);
#pragma endregion
#pragma region RendererCallbacks
@@ -348,7 +347,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
safe_void_coroutine _renderEngineSwapChainChanged(const HANDLE handle);
void _rendererBackgroundColorChanged();
void _rendererTabColorChanged();
void _rendererEnteredErrorState();
#pragma endregion
void _raiseReadOnlyWarning();
@@ -403,7 +401,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
float _panelWidth{ 0 };
float _panelHeight{ 0 };
float _compositionScale{ 0 };
uint8_t _renderFailures{ 0 };
// Audio stuff.
MidiAudio _midiAudio;

View File

@@ -55,8 +55,7 @@ namespace Microsoft.Terminal.Control
Boolean GoForward;
Boolean CaseSensitive;
Boolean RegularExpression;
Boolean ExecuteSearch;
Boolean ScrollIntoView;
Boolean ResetOnly;
Int32 ScrollOffset;
};
@@ -98,7 +97,6 @@ namespace Microsoft.Terminal.Control
void ApplyAppearance(Boolean focused);
Microsoft.Terminal.TerminalConnection.ITerminalConnection Connection;
void HardResetWithoutErase();
IControlSettings Settings { get; };
IControlAppearance FocusedAppearance { get; };
@@ -187,7 +185,6 @@ namespace Microsoft.Terminal.Control
// These events are called from some background thread
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, WriteToClipboardEventArgs> WriteToClipboard;
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> BackgroundColorChanged;

View File

@@ -55,20 +55,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
self->Attached.raise(*self, nullptr);
}
});
// GH#14464: Mark mode and quick-edit (shift+arrow) selections update
// the selection through ControlCore, bypassing SetEndSelectionPoint.
// Listen for selection changes so _selectionNeedsToBeCopied is set
// for ALL selection types, not just mouse drag.
_core->UpdateSelectionMarkers([weakThis = get_weak()](auto&&, auto&&) {
if (auto self{ weakThis.get() })
{
if (self->_core->HasSelection())
{
self->_selectionNeedsToBeCopied = true;
}
}
});
}
uint64_t ControlInteractivity::Id()
@@ -213,7 +199,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// if we should defer which formats are copied to the global setting
bool ControlInteractivity::CopySelectionToClipboard(bool singleLine,
bool withControlSequences,
const CopyFormat formats)
const Windows::Foundation::IReference<CopyFormat>& formats)
{
if (_core)
{
@@ -329,18 +315,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
else
{
// GH#19942, GH#14464: Don't re-copy a selection that was
// already copied via copyOnSelect on mouse-up. But DO copy
// if the selection was made via mark mode or modified with
// quick-edit keys (shift+arrow), since those paths never
// triggered an automatic copy.
const auto copied = (_selectionNeedsToBeCopied || !_core->CopyOnSelect()) &&
CopySelectionToClipboard(shiftEnabled, false, _core->Settings().CopyFormatting());
// Try to copy the text and clear the selection
const auto successfulCopy = CopySelectionToClipboard(shiftEnabled, false, nullptr);
_core->ClearSelection();
if (_core->CopyOnSelect() || !copied)
if (_core->CopyOnSelect() || !successfulCopy)
{
// CopyOnSelect: right-click always pastes.
// Otherwise: no selection paste.
// CopyOnSelect: right click always pastes!
// Otherwise: no selection --> paste
RequestPasteTextFromClipboard();
}
}
@@ -480,7 +461,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// IMPORTANT!
// DO NOT clear the selection here!
// Otherwise, the selection will be cleared immediately after you make it.
CopySelectionToClipboard(false, false, _core->Settings().CopyFormatting());
CopySelectionToClipboard(false, false, nullptr);
}
_singleClickTouchdownPos = std::nullopt;
@@ -504,7 +485,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - modifiers: The modifiers pressed during this event, in the form of a VirtualKeyModifiers
// - delta: the mouse wheel delta that triggered this event.
bool ControlInteractivity::MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const Core::Point delta,
const int32_t delta,
const Core::Point pixelPosition,
const Control::MouseButtonState buttonState)
{
@@ -525,9 +506,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// PointerPoint to work with. So, we're just going to do a
// mousewheel event manually
return _sendMouseEventHelper(terminalPosition,
delta.Y != 0 ? WM_MOUSEWHEEL : WM_MOUSEHWHEEL,
WM_MOUSEWHEEL,
modifiers,
::base::saturated_cast<short>(delta.Y != 0 ? delta.Y : delta.X),
::base::saturated_cast<short>(delta),
buttonState);
}
@@ -536,15 +517,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (ctrlPressed && shiftPressed && _core->Settings().ScrollToChangeOpacity())
{
_mouseTransparencyHandler(delta.Y);
_mouseTransparencyHandler(delta);
}
else if (ctrlPressed && !shiftPressed && _core->Settings().ScrollToZoom())
{
_mouseZoomHandler(delta.Y);
_mouseZoomHandler(delta);
}
else
{
_mouseScrollHandler(delta.Y, pixelPosition, WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown));
_mouseScrollHandler(delta, pixelPosition, WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown));
}
return false;
}
@@ -678,7 +659,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _core->IsVtMouseModeEnabled();
}
bool ControlInteractivity::_shouldSendAlternateScroll(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const Core::Point delta)
bool ControlInteractivity::_shouldSendAlternateScroll(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const int32_t delta)
{
// If the user is holding down Shift, suppress mouse events
// TODO GH#4875: disable/customize this functionality
@@ -686,14 +667,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
return false;
}
if (delta.Y != 0)
{
return _core->ShouldSendAlternateScroll(WM_MOUSEWHEEL, delta.Y);
}
else
{
return _core->ShouldSendAlternateScroll(WM_MOUSEHWHEEL, delta.X);
}
return _core->ShouldSendAlternateScroll(WM_MOUSEWHEEL, delta);
}
// Method Description:

View File

@@ -74,7 +74,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void TouchReleased();
bool MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const Core::Point delta,
const int32_t delta,
const Core::Point pixelPosition,
const Control::MouseButtonState state);
@@ -84,7 +84,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool CopySelectionToClipboard(bool singleLine,
bool withControlSequences,
const CopyFormat formats);
const Windows::Foundation::IReference<CopyFormat>& formats);
void RequestPasteTextFromClipboard();
void SetEndSelectionPoint(const Core::Point pixelPosition);
@@ -153,7 +153,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _hyperlinkHandler(const std::wstring_view uri);
bool _canSendVTMouseInput(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers);
bool _shouldSendAlternateScroll(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const Core::Point delta);
bool _shouldSendAlternateScroll(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const int32_t delta);
til::point _getTerminalPosition(const til::point pixelPosition, bool roundToNearestCell);

View File

@@ -32,7 +32,7 @@ namespace Microsoft.Terminal.Control
InteractivityAutomationPeer OnCreateAutomationPeer();
Boolean CopySelectionToClipboard(Boolean singleLine, Boolean withControlSequences, CopyFormat formats);
Boolean CopySelectionToClipboard(Boolean singleLine, Boolean withControlSequences, Windows.Foundation.IReference<CopyFormat> formats);
void RequestPasteTextFromClipboard();
void SetEndSelectionPoint(Microsoft.Terminal.Core.Point point);
@@ -60,7 +60,7 @@ namespace Microsoft.Terminal.Control
void TouchReleased();
Boolean MouseWheel(Microsoft.Terminal.Core.ControlKeyStates modifiers,
Microsoft.Terminal.Core.Point delta,
Int32 delta,
Microsoft.Terminal.Core.Point pixelPosition,
MouseButtonState state);

View File

@@ -6,7 +6,6 @@
#include "FontSizeChangedArgs.g.cpp"
#include "TitleChangedEventArgs.g.cpp"
#include "ContextMenuRequestedEventArgs.g.cpp"
#include "WriteToClipboardEventArgs.g.cpp"
#include "PasteFromClipboardEventArgs.g.cpp"
#include "OpenHyperlinkEventArgs.g.cpp"
#include "NoticeEventArgs.g.cpp"

View File

@@ -6,7 +6,6 @@
#include "FontSizeChangedArgs.g.h"
#include "TitleChangedEventArgs.g.h"
#include "ContextMenuRequestedEventArgs.g.h"
#include "WriteToClipboardEventArgs.g.h"
#include "PasteFromClipboardEventArgs.g.h"
#include "OpenHyperlinkEventArgs.g.h"
#include "NoticeEventArgs.g.h"
@@ -57,32 +56,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
WINRT_PROPERTY(winrt::Windows::Foundation::Point, Position);
};
struct WriteToClipboardEventArgs : WriteToClipboardEventArgsT<WriteToClipboardEventArgs>
{
WriteToClipboardEventArgs(winrt::hstring&& plain, std::string&& html, std::string&& rtf) :
_plain(std::move(plain)),
_html(std::move(html)),
_rtf(std::move(rtf))
{
}
winrt::hstring Plain() const noexcept { return _plain; }
winrt::com_array<uint8_t> Html() noexcept { return _cast(_html); }
winrt::com_array<uint8_t> Rtf() noexcept { return _cast(_rtf); }
private:
static winrt::com_array<uint8_t> _cast(const std::string& str)
{
const auto beg = reinterpret_cast<const uint8_t*>(str.data());
const auto len = str.size();
return { beg, beg + len };
}
winrt::hstring _plain;
std::string _html;
std::string _rtf;
};
struct PasteFromClipboardEventArgs : public PasteFromClipboardEventArgsT<PasteFromClipboardEventArgs>
{
public:

View File

@@ -6,7 +6,6 @@ namespace Microsoft.Terminal.Control
[flags]
enum CopyFormat
{
None = 0x0,
HTML = 0x1,
RTF = 0x2,
All = 0xffffffff
@@ -32,13 +31,6 @@ namespace Microsoft.Terminal.Control
AlphanumericHalfWidth,
};
enum WarnAboutMultiLinePaste
{
Automatic,
Always,
Never,
};
runtimeclass FontSizeChangedArgs
{
Int32 Width { get; };
@@ -55,13 +47,6 @@ namespace Microsoft.Terminal.Control
String Title;
}
runtimeclass WriteToClipboardEventArgs
{
String Plain { get; }; // UTF-16, as required by CF_UNICODETEXT
byte[] Html { get; }; // UTF-8, as required by "HTML Format"
byte[] Rtf { get; }; // UTF-8, as required by "Rich Text Format"
}
runtimeclass PasteFromClipboardEventArgs
{
void HandleClipboardData(String data);

Some files were not shown because too many files have changed in this diff Show More